Merge "Add a process state seq counter to UidRecord."
diff --git a/Android.mk b/Android.mk
index b98d3bc..f544620 100644
--- a/Android.mk
+++ b/Android.mk
@@ -213,7 +213,6 @@
core/java/android/hardware/usb/IUsbManager.aidl \
core/java/android/net/ICaptivePortal.aidl \
core/java/android/net/IConnectivityManager.aidl \
- core/java/android/net/IConnectivityMetricsLogger.aidl \
core/java/android/net/IIpConnectivityMetrics.aidl \
core/java/android/net/IEthernetManager.aidl \
core/java/android/net/IEthernetServiceListener.aidl \
@@ -409,6 +408,10 @@
location/java/android/location/INetInitiatedListener.aidl \
location/java/com/android/internal/location/ILocationProvider.aidl \
media/java/android/media/IAudioService.aidl \
+ ../av/drm/libmediadrm/aidl/android/media/ICas.aidl \
+ ../av/drm/libmediadrm/aidl/android/media/ICasListener.aidl \
+ ../av/drm/libmediadrm/aidl/android/media/IDescrambler.aidl \
+ ../av/drm/libmediadrm/aidl/android/media/IMediaCasService.aidl \
media/java/android/media/IAudioFocusDispatcher.aidl \
media/java/android/media/IAudioRoutesObserver.aidl \
media/java/android/media/IMediaHTTPConnection.aidl \
@@ -438,6 +441,7 @@
media/java/android/media/projection/IMediaProjectionManager.aidl \
media/java/android/media/projection/IMediaProjectionWatcherCallback.aidl \
media/java/android/media/session/IActiveSessionsListener.aidl \
+ media/java/android/media/session/ICallback.aidl \
media/java/android/media/session/IOnMediaKeyListener.aidl \
media/java/android/media/session/IOnVolumeKeyLongPressListener.aidl \
media/java/android/media/session/ISession.aidl \
@@ -534,6 +538,7 @@
LOCAL_AIDL_INCLUDES += \
frameworks/av/camera/aidl \
+ frameworks/av/drm/libmediadrm/aidl \
frameworks/native/aidl/gui \
system/netd/server/binder
@@ -928,6 +933,7 @@
-since $(SRC_API_DIR)/23.txt 23 \
-since $(SRC_API_DIR)/24.txt 24 \
-since $(SRC_API_DIR)/25.txt 25 \
+ -since ./frameworks/base/api/current.txt O \
-werror -hide 111 -hide 113 \
-overview $(LOCAL_PATH)/core/java/overview.html
@@ -1000,7 +1006,7 @@
-removedApi $(INTERNAL_PLATFORM_REMOVED_API_FILE) \
-nodocs
-LOCAL_DROIDDOC_CUSTOM_TEMPLATE_DIR:=build/tools/droiddoc/templates-sdk
+LOCAL_DROIDDOC_CUSTOM_TEMPLATE_DIR:=external/doclava/res/assets/templates-sdk
LOCAL_UNINSTALLABLE_MODULE := true
@@ -1035,7 +1041,7 @@
-removedApi $(INTERNAL_PLATFORM_SYSTEM_REMOVED_API_FILE) \
-nodocs
-LOCAL_DROIDDOC_CUSTOM_TEMPLATE_DIR:=build/tools/droiddoc/templates-sdk
+LOCAL_DROIDDOC_CUSTOM_TEMPLATE_DIR:=external/doclava/res/assets/templates-sdk
LOCAL_UNINSTALLABLE_MODULE := true
@@ -1071,7 +1077,7 @@
-removedApi $(INTERNAL_PLATFORM_TEST_REMOVED_API_FILE) \
-nodocs
-LOCAL_DROIDDOC_CUSTOM_TEMPLATE_DIR:=build/tools/droiddoc/templates-sdk
+LOCAL_DROIDDOC_CUSTOM_TEMPLATE_DIR:=external/doclava/res/assets/templates-sdk
LOCAL_UNINSTALLABLE_MODULE := true
@@ -1101,7 +1107,7 @@
-referenceonly \
-parsecomments
-LOCAL_DROIDDOC_CUSTOM_TEMPLATE_DIR:=build/tools/droiddoc/templates-sdk
+LOCAL_DROIDDOC_CUSTOM_TEMPLATE_DIR:=external/doclava/res/assets/templates-sdk
LOCAL_UNINSTALLABLE_MODULE := true
@@ -1137,7 +1143,7 @@
-sdkvalues $(OUT_DOCS) \
-hdf android.whichdoc offline
-LOCAL_DROIDDOC_CUSTOM_TEMPLATE_DIR:=build/tools/droiddoc/templates-sdk
+LOCAL_DROIDDOC_CUSTOM_TEMPLATE_DIR:=external/doclava/res/assets/templates-sdk
include $(BUILD_DROIDDOC)
@@ -1176,7 +1182,7 @@
-resourcesdir $(LOCAL_PATH)/docs/html/reference/images/ \
-resourcesoutdir reference/android/images/
-LOCAL_DROIDDOC_CUSTOM_TEMPLATE_DIR:=build/tools/droiddoc/templates-sdk
+LOCAL_DROIDDOC_CUSTOM_TEMPLATE_DIR:=external/doclava/res/assets/templates-sdk
include $(BUILD_DROIDDOC)
@@ -1219,7 +1225,7 @@
-hdf android.hasSamples true \
-samplesdir $(samples_dir)
-LOCAL_DROIDDOC_CUSTOM_TEMPLATE_DIR:=build/tools/droiddoc/templates-sdk
+LOCAL_DROIDDOC_CUSTOM_TEMPLATE_DIR:=external/doclava/res/assets/templates-sdk
include $(BUILD_DROIDDOC)
@@ -1255,7 +1261,7 @@
-hdf android.hasSamples true \
-samplesdir $(samples_dir)
-LOCAL_DROIDDOC_CUSTOM_TEMPLATE_DIR:=build/tools/droiddoc/templates-sdk
+LOCAL_DROIDDOC_CUSTOM_TEMPLATE_DIR:=external/doclava/res/assets/templates-sdk
# Don't build by default
LOCAL_UNINSTALLABLE_MODULE := true
@@ -1287,7 +1293,7 @@
-hdf android.hasSamples true \
-samplesdir $(samples_dir)
-LOCAL_DROIDDOC_CUSTOM_TEMPLATE_DIR:=build/tools/droiddoc/templates-sdk
+LOCAL_DROIDDOC_CUSTOM_TEMPLATE_DIR:=external/doclava/res/assets/templates-sdk
include $(BUILD_DROIDDOC)
@@ -1315,7 +1321,7 @@
-devsite \
-ignoreJdLinks
-LOCAL_DROIDDOC_CUSTOM_TEMPLATE_DIR:=build/tools/droiddoc/templates-sdk
+LOCAL_DROIDDOC_CUSTOM_TEMPLATE_DIR:=external/doclava/res/assets/templates-sdk
include $(BUILD_DROIDDOC)
@@ -1340,7 +1346,7 @@
-atLinksNavtree \
-navtreeonly
-LOCAL_DROIDDOC_CUSTOM_TEMPLATE_DIR:=build/tools/droiddoc/templates-sdk
+LOCAL_DROIDDOC_CUSTOM_TEMPLATE_DIR:=external/doclava/res/assets/templates-sdk
include $(BUILD_DROIDDOC)
@@ -1368,7 +1374,7 @@
-hdf android.hasSamples true \
-samplesdir $(samples_dir)
-LOCAL_DROIDDOC_CUSTOM_TEMPLATE_DIR:=build/tools/droiddoc/templates-sdk
+LOCAL_DROIDDOC_CUSTOM_TEMPLATE_DIR:=external/doclava/res/assets/templates-sdk
include $(BUILD_DROIDDOC)
@@ -1391,7 +1397,7 @@
-title "Android SDK - Including hidden APIs."
# -hidden
-LOCAL_DROIDDOC_CUSTOM_TEMPLATE_DIR:=build/tools/droiddoc/templates-sdk
+LOCAL_DROIDDOC_CUSTOM_TEMPLATE_DIR:=external/doclava/res/assets/templates-sdk
include $(BUILD_DROIDDOC)
diff --git a/apct-tests/perftests/core/jni/SystemPerfTest.cpp b/apct-tests/perftests/core/jni/SystemPerfTest.cpp
index eb55408..f102e3e 100644
--- a/apct-tests/perftests/core/jni/SystemPerfTest.cpp
+++ b/apct-tests/perftests/core/jni/SystemPerfTest.cpp
@@ -73,7 +73,7 @@
return JNI_ERR;
}
- if (registerNativeMethods(env, "java/lang/perftests/SystemPerfTest",
+ if (registerNativeMethods(env, "android/perftests/SystemPerfTest",
sMethods, NELEM(sMethods)) == -1) {
return JNI_ERR;
}
diff --git a/apct-tests/perftests/core/res/layout/test_autosize_textview_10.xml b/apct-tests/perftests/core/res/layout/test_autosize_textview_10.xml
index a8d3de0..4a4b3b4 100644
--- a/apct-tests/perftests/core/res/layout/test_autosize_textview_10.xml
+++ b/apct-tests/perftests/core/res/layout/test_autosize_textview_10.xml
@@ -35,7 +35,7 @@
android:layout_width="400dp"
android:layout_height="600dp"
android:text="@string/long_text"
- android:autoSizeText="uniform"
+ android:autoSizeTextType="uniform"
android:autoSizeMinTextSize="10px"
android:textSize="20px"
android:autoSizeStepGranularity="1px"/>
diff --git a/apct-tests/perftests/core/res/layout/test_autosize_textview_100.xml b/apct-tests/perftests/core/res/layout/test_autosize_textview_100.xml
index d991862..0b326e8 100644
--- a/apct-tests/perftests/core/res/layout/test_autosize_textview_100.xml
+++ b/apct-tests/perftests/core/res/layout/test_autosize_textview_100.xml
@@ -19,7 +19,7 @@
android:layout_width="400dp"
android:layout_height="600dp"
android:text="@string/long_text"
- android:autoSizeText="uniform"
+ android:autoSizeTextType="uniform"
android:autoSizeMinTextSize="10px"
android:textSize="110px"
android:autoSizeStepGranularity="1px"/>
diff --git a/apct-tests/perftests/core/res/layout/test_autosize_textview_1000.xml b/apct-tests/perftests/core/res/layout/test_autosize_textview_1000.xml
index 3b55b6c..2f4239d 100644
--- a/apct-tests/perftests/core/res/layout/test_autosize_textview_1000.xml
+++ b/apct-tests/perftests/core/res/layout/test_autosize_textview_1000.xml
@@ -19,7 +19,7 @@
android:layout_width="400dp"
android:layout_height="600dp"
android:text="@string/long_text"
- android:autoSizeText="uniform"
+ android:autoSizeTextType="uniform"
android:autoSizeMinTextSize="10px"
android:textSize="1010px"
android:autoSizeStepGranularity="1px"/>
diff --git a/apct-tests/perftests/core/res/layout/test_autosize_textview_10000.xml b/apct-tests/perftests/core/res/layout/test_autosize_textview_10000.xml
index 64a25c2..b6be10a 100644
--- a/apct-tests/perftests/core/res/layout/test_autosize_textview_10000.xml
+++ b/apct-tests/perftests/core/res/layout/test_autosize_textview_10000.xml
@@ -19,7 +19,7 @@
android:layout_width="400dp"
android:layout_height="600dp"
android:text="@string/long_text"
- android:autoSizeText="uniform"
+ android:autoSizeTextType="uniform"
android:autoSizeMinTextSize="10px"
android:textSize="10010px"
android:autoSizeStepGranularity="1px"/>
diff --git a/apct-tests/perftests/core/res/layout/test_autosize_textview_100000.xml b/apct-tests/perftests/core/res/layout/test_autosize_textview_100000.xml
index 1f60783..aed339c 100644
--- a/apct-tests/perftests/core/res/layout/test_autosize_textview_100000.xml
+++ b/apct-tests/perftests/core/res/layout/test_autosize_textview_100000.xml
@@ -19,7 +19,7 @@
android:layout_width="400dp"
android:layout_height="600dp"
android:text="@string/long_text"
- android:autoSizeText="uniform"
+ android:autoSizeTextType="uniform"
android:autoSizeMinTextSize="10px"
android:textSize="100010px"
android:autoSizeStepGranularity="1px"/>
diff --git a/apct-tests/perftests/core/res/layout/test_autosize_textview_300.xml b/apct-tests/perftests/core/res/layout/test_autosize_textview_300.xml
index 54c7e71..62522ba 100644
--- a/apct-tests/perftests/core/res/layout/test_autosize_textview_300.xml
+++ b/apct-tests/perftests/core/res/layout/test_autosize_textview_300.xml
@@ -19,7 +19,7 @@
android:layout_width="400dp"
android:layout_height="600dp"
android:text="@string/long_text"
- android:autoSizeText="uniform"
+ android:autoSizeTextType="uniform"
android:autoSizeMinTextSize="10px"
android:textSize="310px"
android:autoSizeStepGranularity="1px"/>
diff --git a/apct-tests/perftests/core/res/layout/test_autosize_textview_5.xml b/apct-tests/perftests/core/res/layout/test_autosize_textview_5.xml
index 525b2c8..f383fa4 100644
--- a/apct-tests/perftests/core/res/layout/test_autosize_textview_5.xml
+++ b/apct-tests/perftests/core/res/layout/test_autosize_textview_5.xml
@@ -35,7 +35,7 @@
android:layout_width="400dp"
android:layout_height="600dp"
android:text="@string/long_text"
- android:autoSizeText="uniform"
+ android:autoSizeTextType="uniform"
android:autoSizeMinTextSize="10px"
android:textSize="15px"
android:autoSizeStepGranularity="1px"/>
diff --git a/apct-tests/perftests/core/res/layout/test_autosize_textview_50.xml b/apct-tests/perftests/core/res/layout/test_autosize_textview_50.xml
index 470c4da..04dd6c2 100644
--- a/apct-tests/perftests/core/res/layout/test_autosize_textview_50.xml
+++ b/apct-tests/perftests/core/res/layout/test_autosize_textview_50.xml
@@ -19,7 +19,7 @@
android:layout_width="400dp"
android:layout_height="600dp"
android:text="@string/long_text"
- android:autoSizeText="uniform"
+ android:autoSizeTextType="uniform"
android:autoSizeMinTextSize="10px"
android:textSize="60px"
android:autoSizeStepGranularity="1px"/>
diff --git a/apct-tests/perftests/core/res/layout/test_autosize_textview_500.xml b/apct-tests/perftests/core/res/layout/test_autosize_textview_500.xml
index b8a6e0a..a8e2b38 100644
--- a/apct-tests/perftests/core/res/layout/test_autosize_textview_500.xml
+++ b/apct-tests/perftests/core/res/layout/test_autosize_textview_500.xml
@@ -19,7 +19,7 @@
android:layout_width="400dp"
android:layout_height="600dp"
android:text="@string/long_text"
- android:autoSizeText="uniform"
+ android:autoSizeTextType="uniform"
android:autoSizeMinTextSize="10px"
android:textSize="510px"
android:autoSizeStepGranularity="1px"/>
diff --git a/apct-tests/perftests/core/src/java/lang/perftests/SystemPerfTest.java b/apct-tests/perftests/core/src/android/perftests/SystemPerfTest.java
similarity index 98%
rename from apct-tests/perftests/core/src/java/lang/perftests/SystemPerfTest.java
rename to apct-tests/perftests/core/src/android/perftests/SystemPerfTest.java
index afc9d0c..95a7144 100644
--- a/apct-tests/perftests/core/src/java/lang/perftests/SystemPerfTest.java
+++ b/apct-tests/perftests/core/src/android/perftests/SystemPerfTest.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package java.lang.perftests;
+package android.perftests;
import android.perftests.utils.BenchmarkState;
import android.perftests.utils.PerfStatusReporter;
diff --git a/apct-tests/perftests/core/src/android/widget/TextViewAutoSizeLayoutPerfTest.java b/apct-tests/perftests/core/src/android/widget/TextViewAutoSizeLayoutPerfTest.java
index 6ee6f70..c310166 100644
--- a/apct-tests/perftests/core/src/android/widget/TextViewAutoSizeLayoutPerfTest.java
+++ b/apct-tests/perftests/core/src/android/widget/TextViewAutoSizeLayoutPerfTest.java
@@ -89,7 +89,7 @@
while (state.keepRunning()) {
TextView textView = new TextView(activity);
- // TextView#onMeasure() gets called, which triggers TextView#autoSizeText()
+ // TextView#onLayout() gets called, which triggers TextView#autoSizeText()
// which is the method we want to benchmark.
textView.requestLayout();
}
diff --git a/api/current.txt b/api/current.txt
index 202ea21..c7074cc 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -16,6 +16,7 @@
field public static final java.lang.String ACCOUNT_MANAGER = "android.permission.ACCOUNT_MANAGER";
field public static final java.lang.String ADD_VOICEMAIL = "com.android.voicemail.permission.ADD_VOICEMAIL";
field public static final java.lang.String ALLOCATE_AGGRESSIVE = "android.permission.ALLOCATE_AGGRESSIVE";
+ field public static final java.lang.String ANSWER_PHONE_CALLS = "android.permission.ANSWER_PHONE_CALLS";
field public static final java.lang.String BATTERY_STATS = "android.permission.BATTERY_STATS";
field public static final java.lang.String BIND_ACCESSIBILITY_SERVICE = "android.permission.BIND_ACCESSIBILITY_SERVICE";
field public static final java.lang.String BIND_APPWIDGET = "android.permission.BIND_APPWIDGET";
@@ -305,7 +306,7 @@
field public static final int autoSizeMinTextSize = 16844088; // 0x1010538
field public static final int autoSizePresetSizes = 16844087; // 0x1010537
field public static final int autoSizeStepGranularity = 16844086; // 0x1010536
- field public static final int autoSizeText = 16844085; // 0x1010535
+ field public static final int autoSizeTextType = 16844085; // 0x1010535
field public static final int autoStart = 16843445; // 0x10102b5
field public static final deprecated int autoText = 16843114; // 0x101016a
field public static final int autoUrlDetect = 16843404; // 0x101028c
@@ -410,6 +411,7 @@
field public static final int colorControlHighlight = 16843820; // 0x101042c
field public static final int colorControlNormal = 16843817; // 0x1010429
field public static final int colorEdgeEffect = 16843982; // 0x10104ce
+ field public static final int colorError = 16844100; // 0x1010544
field public static final int colorFocusedHighlight = 16843663; // 0x101038f
field public static final int colorForeground = 16842800; // 0x1010030
field public static final int colorForegroundInverse = 16843270; // 0x1010206
@@ -1316,7 +1318,6 @@
field public static final int textCheckMarkInverse = 16842823; // 0x1010047
field public static final int textColor = 16842904; // 0x1010098
field public static final int textColorAlertDialogListItem = 16843526; // 0x1010306
- field public static final int textColorError = 16844100; // 0x1010544
field public static final int textColorHighlight = 16842905; // 0x1010099
field public static final int textColorHighlightInverse = 16843599; // 0x101034f
field public static final int textColorHint = 16842906; // 0x101009a
@@ -4143,6 +4144,7 @@
field public static final int MODE_ERRORED = 2; // 0x2
field public static final int MODE_IGNORED = 1; // 0x1
field public static final java.lang.String OPSTR_ADD_VOICEMAIL = "android:add_voicemail";
+ field public static final java.lang.String OPSTR_ANSWER_PHONE_CALLS = "android:answer_phone_calls";
field public static final java.lang.String OPSTR_BODY_SENSORS = "android:body_sensors";
field public static final java.lang.String OPSTR_CALL_PHONE = "android:call_phone";
field public static final java.lang.String OPSTR_CAMERA = "android:camera";
@@ -4737,6 +4739,7 @@
method public abstract android.app.Fragment getPrimaryNavigationFragment();
method public void invalidateOptionsMenu();
method public abstract boolean isDestroyed();
+ method public abstract boolean isStateSaved();
method public abstract void popBackStack();
method public abstract void popBackStack(java.lang.String, int);
method public abstract void popBackStack(int, int);
@@ -6547,6 +6550,7 @@
public static class AssistStructure.ViewNode {
method public float getAlpha();
method public android.view.autofill.AutoFillId getAutoFillId();
+ method public java.lang.String[] getAutoFillOptions();
method public android.view.autofill.AutoFillType getAutoFillType();
method public android.view.autofill.AutoFillValue getAutoFillValue();
method public android.app.assist.AssistStructure.ViewNode getChildAt(int);
@@ -6716,6 +6720,7 @@
method public android.app.job.JobInfo.TriggerContentUri[] getTriggerContentUris();
method public boolean isPeriodic();
method public boolean isPersisted();
+ method public boolean isRequireBatteryNotLow();
method public boolean isRequireCharging();
method public boolean isRequireDeviceIdle();
method public void writeToParcel(android.os.Parcel, int);
@@ -6742,6 +6747,7 @@
method public android.app.job.JobInfo.Builder setPeriodic(long, long);
method public android.app.job.JobInfo.Builder setPersisted(boolean);
method public android.app.job.JobInfo.Builder setRequiredNetworkType(int);
+ method public android.app.job.JobInfo.Builder setRequiresBatteryNotLow(boolean);
method public android.app.job.JobInfo.Builder setRequiresCharging(boolean);
method public android.app.job.JobInfo.Builder setRequiresDeviceIdle(boolean);
method public android.app.job.JobInfo.Builder setTransientExtras(android.os.Bundle);
@@ -6882,6 +6888,7 @@
method public long getFreeBytes(java.lang.String);
method public long getTotalBytes(java.lang.String);
method public android.app.usage.ExternalStorageStats queryExternalStatsForUser(java.lang.String, android.os.UserHandle);
+ method public android.app.usage.StorageStats queryStatsForPackage(java.lang.String, java.lang.String, android.os.UserHandle);
method public android.app.usage.StorageStats queryStatsForUid(java.lang.String, int);
method public android.app.usage.StorageStats queryStatsForUser(java.lang.String, android.os.UserHandle);
}
@@ -8669,6 +8676,7 @@
field public static final java.lang.String HARDWARE_PROPERTIES_SERVICE = "hardware_properties";
field public static final java.lang.String INPUT_METHOD_SERVICE = "input_method";
field public static final java.lang.String INPUT_SERVICE = "input";
+ field public static final java.lang.String IPSEC_SERVICE = "ipsec";
field public static final java.lang.String JOB_SCHEDULER_SERVICE = "jobscheduler";
field public static final java.lang.String KEYGUARD_SERVICE = "keyguard";
field public static final java.lang.String LAUNCHER_APPS_SERVICE = "launcherapps";
@@ -9038,6 +9046,7 @@
field public static final java.lang.String ACTION_CALL = "android.intent.action.CALL";
field public static final java.lang.String ACTION_CALL_BUTTON = "android.intent.action.CALL_BUTTON";
field public static final java.lang.String ACTION_CAMERA_BUTTON = "android.intent.action.CAMERA_BUTTON";
+ field public static final java.lang.String ACTION_CARRIER_SETUP = "android.intent.action.CARRIER_SETUP";
field public static final java.lang.String ACTION_CHOOSER = "android.intent.action.CHOOSER";
field public static final java.lang.String ACTION_CLEAR_PACKAGE = "android.intent.action.CLEAR_PACKAGE";
field public static final java.lang.String ACTION_CLOSE_SYSTEM_DIALOGS = "android.intent.action.CLOSE_SYSTEM_DIALOGS";
@@ -10099,10 +10108,12 @@
ctor public LauncherApps.ShortcutQuery();
method public android.content.pm.LauncherApps.ShortcutQuery setActivity(android.content.ComponentName);
method public android.content.pm.LauncherApps.ShortcutQuery setChangedSince(long);
+ method public android.content.pm.LauncherApps.ShortcutQuery setIntent(android.content.Intent);
method public android.content.pm.LauncherApps.ShortcutQuery setPackage(java.lang.String);
method public android.content.pm.LauncherApps.ShortcutQuery setQueryFlags(int);
method public android.content.pm.LauncherApps.ShortcutQuery setShortcutIds(java.util.List<java.lang.String>);
field public static final int FLAG_GET_KEY_FIELDS_ONLY = 4; // 0x4
+ field public static final int FLAG_MATCH_CHOOSER = 16; // 0x10
field public static final int FLAG_MATCH_DYNAMIC = 1; // 0x1
field public static final int FLAG_MATCH_MANIFEST = 8; // 0x8
field public static final int FLAG_MATCH_PINNED = 2; // 0x2
@@ -10158,9 +10169,11 @@
method public void unregisterSessionCallback(android.content.pm.PackageInstaller.SessionCallback);
method public void updateSessionAppIcon(int, android.graphics.Bitmap);
method public void updateSessionAppLabel(int, java.lang.CharSequence);
+ field public static final java.lang.String ACTION_SESSION_COMMITTED = "android.content.pm.action.SESSION_COMMITTED";
field public static final java.lang.String ACTION_SESSION_DETAILS = "android.content.pm.action.SESSION_DETAILS";
field public static final java.lang.String EXTRA_OTHER_PACKAGE_NAME = "android.content.pm.extra.OTHER_PACKAGE_NAME";
field public static final java.lang.String EXTRA_PACKAGE_NAME = "android.content.pm.extra.PACKAGE_NAME";
+ field public static final java.lang.String EXTRA_SESSION = "android.content.pm.extra.SESSION";
field public static final java.lang.String EXTRA_SESSION_ID = "android.content.pm.extra.SESSION_ID";
field public static final java.lang.String EXTRA_STATUS = "android.content.pm.extra.STATUS";
field public static final java.lang.String EXTRA_STATUS_MESSAGE = "android.content.pm.extra.STATUS_MESSAGE";
@@ -10203,6 +10216,7 @@
method public android.graphics.Bitmap getAppIcon();
method public java.lang.CharSequence getAppLabel();
method public java.lang.String getAppPackageName();
+ method public int getInstallReason();
method public java.lang.String getInstallerPackageName();
method public float getProgress();
method public int getSessionId();
@@ -10592,6 +10606,7 @@
field public android.content.pm.ActivityInfo activityInfo;
field public android.content.IntentFilter filter;
field public int icon;
+ field public boolean instantAppAvailable;
field public boolean isDefault;
field public int labelRes;
field public int match;
@@ -10641,6 +10656,9 @@
method public int describeContents();
method public android.content.ComponentName getActivity();
method public java.util.Set<java.lang.String> getCategories();
+ method public android.content.ComponentName[] getChooserComponentNames();
+ method public android.os.PersistableBundle getChooserExtras();
+ method public android.content.IntentFilter[] getChooserIntentFilters();
method public java.lang.CharSequence getDisabledMessage();
method public android.os.PersistableBundle getExtras();
method public java.lang.String getId();
@@ -10653,6 +10671,7 @@
method public java.lang.CharSequence getShortLabel();
method public android.os.UserHandle getUserHandle();
method public boolean hasKeyFieldsOnly();
+ method public boolean isChooser();
method public boolean isDeclaredInManifest();
method public boolean isDynamic();
method public boolean isEnabled();
@@ -10665,9 +10684,11 @@
public static class ShortcutInfo.Builder {
ctor public ShortcutInfo.Builder(android.content.Context, java.lang.String);
+ method public android.content.pm.ShortcutInfo.Builder addChooserIntentFilter(android.content.IntentFilter, android.content.ComponentName);
method public android.content.pm.ShortcutInfo build();
method public android.content.pm.ShortcutInfo.Builder setActivity(android.content.ComponentName);
method public android.content.pm.ShortcutInfo.Builder setCategories(java.util.Set<java.lang.String>);
+ method public android.content.pm.ShortcutInfo.Builder setChooserExtras(android.os.PersistableBundle);
method public android.content.pm.ShortcutInfo.Builder setDisabledMessage(java.lang.CharSequence);
method public android.content.pm.ShortcutInfo.Builder setExtras(android.os.PersistableBundle);
method public android.content.pm.ShortcutInfo.Builder setIcon(android.graphics.drawable.Icon);
@@ -12572,6 +12593,7 @@
method public static android.graphics.ColorSpace.Adaptation valueOf(java.lang.String);
method public static final android.graphics.ColorSpace.Adaptation[] values();
enum_constant public static final android.graphics.ColorSpace.Adaptation BRADFORD;
+ enum_constant public static final android.graphics.ColorSpace.Adaptation CIECAT02;
enum_constant public static final android.graphics.ColorSpace.Adaptation VON_KRIES;
}
@@ -14008,6 +14030,8 @@
public class ArcShape extends android.graphics.drawable.shapes.RectShape {
ctor public ArcShape(float, float);
+ method public final float getStartAngle();
+ method public final float getSweepAngle();
}
public class OvalShape extends android.graphics.drawable.shapes.RectShape {
@@ -20643,6 +20667,26 @@
field public static final int TYPE_WIRED_HEADSET = 3; // 0x3
}
+ public final class AudioFocusRequest {
+ method public boolean acceptsDelayedFocusGain();
+ method public android.media.AudioAttributes getAudioAttributes();
+ method public int getFocusGain();
+ method public android.media.AudioManager.OnAudioFocusChangeListener getOnAudioFocusChangeListener();
+ method public android.os.Handler getOnAudioFocusChangeListenerHandler();
+ method public boolean willPauseWhenDucked();
+ }
+
+ public static final class AudioFocusRequest.Builder {
+ ctor public AudioFocusRequest.Builder(int);
+ ctor public AudioFocusRequest.Builder(android.media.AudioFocusRequest);
+ method public android.media.AudioFocusRequest build();
+ method public android.media.AudioFocusRequest.Builder setAcceptsDelayedFocusGain(boolean);
+ method public android.media.AudioFocusRequest.Builder setAudioAttributes(android.media.AudioAttributes);
+ method public android.media.AudioFocusRequest.Builder setFocusGain(int);
+ method public android.media.AudioFocusRequest.Builder setOnAudioFocusChangeListener(android.media.AudioManager.OnAudioFocusChangeListener, android.os.Handler);
+ method public android.media.AudioFocusRequest.Builder setWillPauseWhenDucked(boolean);
+ }
+
public final class AudioFormat implements android.os.Parcelable {
method public int describeContents();
method public int getChannelCount();
@@ -20719,6 +20763,7 @@
public class AudioManager {
method public int abandonAudioFocus(android.media.AudioManager.OnAudioFocusChangeListener);
+ method public int abandonAudioFocusRequest(android.media.AudioFocusRequest);
method public void adjustStreamVolume(int, int, int);
method public void adjustSuggestedStreamVolume(int, int, int);
method public void adjustVolume(int, int);
@@ -20755,6 +20800,7 @@
method public deprecated void registerRemoteControlClient(android.media.RemoteControlClient);
method public deprecated boolean registerRemoteController(android.media.RemoteController);
method public int requestAudioFocus(android.media.AudioManager.OnAudioFocusChangeListener, int, int);
+ method public int requestAudioFocus(android.media.AudioFocusRequest);
method public deprecated void setBluetoothA2dpOn(boolean);
method public void setBluetoothScoOn(boolean);
method public void setMicrophoneMute(boolean);
@@ -20797,6 +20843,8 @@
field public static final int AUDIOFOCUS_LOSS = -1; // 0xffffffff
field public static final int AUDIOFOCUS_LOSS_TRANSIENT = -2; // 0xfffffffe
field public static final int AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK = -3; // 0xfffffffd
+ field public static final int AUDIOFOCUS_NONE = 0; // 0x0
+ field public static final int AUDIOFOCUS_REQUEST_DELAYED = 2; // 0x2
field public static final int AUDIOFOCUS_REQUEST_FAILED = 0; // 0x0
field public static final int AUDIOFOCUS_REQUEST_GRANTED = 1; // 0x1
field public static final int AUDIO_SESSION_ID_GENERATE = 0; // 0x0
@@ -20993,13 +21041,14 @@
field public long nanoTime;
}
- public class AudioTrack implements android.media.AudioRouting {
+ public class AudioTrack implements android.media.AudioRouting android.media.VolumeAutomation {
ctor public deprecated AudioTrack(int, int, int, int, int, int) throws java.lang.IllegalArgumentException;
ctor public deprecated AudioTrack(int, int, int, int, int, int, int) throws java.lang.IllegalArgumentException;
ctor public AudioTrack(android.media.AudioAttributes, android.media.AudioFormat, int, int, int) throws java.lang.IllegalArgumentException;
method public void addOnRoutingChangedListener(android.media.AudioRouting.OnRoutingChangedListener, android.os.Handler);
method public deprecated void addOnRoutingChangedListener(android.media.AudioTrack.OnRoutingChangedListener, android.os.Handler);
method public int attachAuxEffect(int);
+ method public android.media.VolumeShaper createVolumeShaper(android.media.VolumeShaper.Configuration);
method public void flush();
method public int getAudioFormat();
method public int getAudioSessionId();
@@ -21467,8 +21516,42 @@
field public static final int STOP_VIDEO_RECORDING = 3; // 0x3
}
+ public final class MediaCas {
+ ctor public MediaCas(int) throws android.media.UnsupportedCasException;
+ method public void closeSession(byte[]);
+ method public static android.media.MediaCas.PluginDescriptor[] enumeratePlugins();
+ method public static boolean isSystemIdSupported(int);
+ method public byte[] openSession(int);
+ method public byte[] openSession(int, int);
+ method public void processEcm(byte[], byte[], int, int);
+ method public void processEcm(byte[], byte[]);
+ method public void processEmm(byte[], int, int);
+ method public void processEmm(byte[]);
+ method public void provision(java.lang.String);
+ method public void refreshEntitlements(int, byte[]);
+ method public void release();
+ method public void sendEvent(int, int, byte[]);
+ method public void setEventListener(android.media.MediaCas.EventListener, android.os.Handler);
+ method public void setPrivateData(byte[]);
+ method public void setSessionPrivateData(byte[], byte[]);
+ }
+
+ public static abstract interface MediaCas.EventListener {
+ method public abstract void onEvent(android.media.MediaCas, int, int, byte[]);
+ }
+
+ public static class MediaCas.PluginDescriptor {
+ method public java.lang.String getName();
+ method public int getSystemId();
+ }
+
+ public class MediaCasException extends java.lang.Exception {
+ ctor public MediaCasException(java.lang.String);
+ }
+
public final class MediaCodec {
method public void configure(android.media.MediaFormat, android.view.Surface, android.media.MediaCrypto, int);
+ method public void configure(android.media.MediaFormat, android.view.Surface, int, android.media.MediaDescrambler);
method public static android.media.MediaCodec createByCodecName(java.lang.String) throws java.io.IOException;
method public static android.media.MediaCodec createDecoderByType(java.lang.String) throws java.io.IOException;
method public static android.media.MediaCodec createEncoderByType(java.lang.String) throws java.io.IOException;
@@ -21508,6 +21591,7 @@
field public static final int BUFFER_FLAG_CODEC_CONFIG = 2; // 0x2
field public static final int BUFFER_FLAG_END_OF_STREAM = 4; // 0x4
field public static final int BUFFER_FLAG_KEY_FRAME = 1; // 0x1
+ field public static final int BUFFER_FLAG_PARTIAL_FRAME = 8; // 0x8
field public static final deprecated int BUFFER_FLAG_SYNC_FRAME = 1; // 0x1
field public static final int CONFIGURE_FLAG_ENCODE = 1; // 0x1
field public static final int CRYPTO_MODE_AES_CBC = 2; // 0x2
@@ -21664,6 +21748,7 @@
field public static final deprecated int COLOR_TI_FormatYUV420PackedSemiPlanar = 2130706688; // 0x7f000100
field public static final java.lang.String FEATURE_AdaptivePlayback = "adaptive-playback";
field public static final java.lang.String FEATURE_IntraRefresh = "intra-refresh";
+ field public static final java.lang.String FEATURE_PartialFrame = "partial-frame";
field public static final java.lang.String FEATURE_SecurePlayback = "secure-playback";
field public static final java.lang.String FEATURE_TunneledPlayback = "tunneled-playback";
field public int[] colorFormats;
@@ -21888,6 +21973,14 @@
method public abstract int readAt(long, byte[], int, int) throws java.io.IOException;
}
+ public final class MediaDescrambler {
+ ctor public MediaDescrambler(int) throws android.media.UnsupportedCasException;
+ method public final int descramble(java.nio.ByteBuffer, int, java.nio.ByteBuffer, int, android.media.MediaCodec.CryptoInfo);
+ method public final void release();
+ method public final boolean requiresSecureDecoderComponent(java.lang.String);
+ method public final void setMediaCasSession(byte[]);
+ }
+
public class MediaDescription implements android.os.Parcelable {
method public int describeContents();
method public java.lang.CharSequence getDescription();
@@ -22044,8 +22137,10 @@
method public final void setDataSource(android.content.res.AssetFileDescriptor) throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException;
method public final void setDataSource(java.io.FileDescriptor) throws java.io.IOException;
method public final void setDataSource(java.io.FileDescriptor, long, long) throws java.io.IOException;
+ method public final void setMediaCas(android.media.MediaCas);
method public void unselectTrack(int);
field public static final int SAMPLE_FLAG_ENCRYPTED = 2; // 0x2
+ field public static final int SAMPLE_FLAG_PARTIAL_FRAME = 4; // 0x4
field public static final int SAMPLE_FLAG_SYNC = 1; // 0x1
field public static final int SEEK_TO_CLOSEST_SYNC = 2; // 0x2
field public static final int SEEK_TO_NEXT_SYNC = 1; // 0x1
@@ -22111,6 +22206,7 @@
field public static final java.lang.String KEY_IS_FORCED_SUBTITLE = "is-forced-subtitle";
field public static final java.lang.String KEY_I_FRAME_INTERVAL = "i-frame-interval";
field public static final java.lang.String KEY_LANGUAGE = "language";
+ field public static final java.lang.String KEY_LATENCY = "latency";
field public static final java.lang.String KEY_LEVEL = "level";
field public static final java.lang.String KEY_MAX_HEIGHT = "max-height";
field public static final java.lang.String KEY_MAX_INPUT_SIZE = "max-input-size";
@@ -22142,6 +22238,7 @@
field public static final java.lang.String MIMETYPE_AUDIO_OPUS = "audio/opus";
field public static final java.lang.String MIMETYPE_AUDIO_QCELP = "audio/qcelp";
field public static final java.lang.String MIMETYPE_AUDIO_RAW = "audio/raw";
+ field public static final java.lang.String MIMETYPE_AUDIO_SCRAMBLED = "audio/scrambled";
field public static final java.lang.String MIMETYPE_AUDIO_VORBIS = "audio/vorbis";
field public static final java.lang.String MIMETYPE_TEXT_CEA_608 = "text/cea-608";
field public static final java.lang.String MIMETYPE_TEXT_VTT = "text/vtt";
@@ -22152,6 +22249,7 @@
field public static final java.lang.String MIMETYPE_VIDEO_MPEG2 = "video/mpeg2";
field public static final java.lang.String MIMETYPE_VIDEO_MPEG4 = "video/mp4v-es";
field public static final java.lang.String MIMETYPE_VIDEO_RAW = "video/raw";
+ field public static final java.lang.String MIMETYPE_VIDEO_SCRAMBLED = "video/scrambled";
field public static final java.lang.String MIMETYPE_VIDEO_VP8 = "video/x-vnd.on2.vp8";
field public static final java.lang.String MIMETYPE_VIDEO_VP9 = "video/x-vnd.on2.vp9";
}
@@ -22292,7 +22390,7 @@
field public static final int MUXER_OUTPUT_WEBM = 1; // 0x1
}
- public class MediaPlayer {
+ public class MediaPlayer implements android.media.VolumeAutomation {
ctor public MediaPlayer();
method public void addTimedTextSource(java.lang.String, java.lang.String) throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException;
method public void addTimedTextSource(android.content.Context, android.net.Uri, java.lang.String) throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException;
@@ -22304,6 +22402,7 @@
method public static android.media.MediaPlayer create(android.content.Context, android.net.Uri, android.view.SurfaceHolder, android.media.AudioAttributes, int);
method public static android.media.MediaPlayer create(android.content.Context, int);
method public static android.media.MediaPlayer create(android.content.Context, int, android.media.AudioAttributes, int);
+ method public android.media.VolumeShaper createVolumeShaper(android.media.VolumeShaper.Configuration);
method public void deselectTrack(int) throws java.lang.IllegalStateException;
method public int getAudioSessionId();
method public android.media.BufferingParams getBufferingParams();
@@ -23123,10 +23222,18 @@
field public static final int TONE_SUP_RINGTONE = 23; // 0x17
}
+ public final class UnsupportedCasException extends android.media.MediaCasException {
+ ctor public UnsupportedCasException(java.lang.String);
+ }
+
public final class UnsupportedSchemeException extends android.media.MediaDrmException {
ctor public UnsupportedSchemeException(java.lang.String);
}
+ public abstract interface VolumeAutomation {
+ method public abstract android.media.VolumeShaper createVolumeShaper(android.media.VolumeShaper.Configuration);
+ }
+
public abstract class VolumeProvider {
ctor public VolumeProvider(int, int, int);
method public final int getCurrentVolume();
@@ -23140,6 +23247,53 @@
field public static final int VOLUME_CONTROL_RELATIVE = 1; // 0x1
}
+ public final class VolumeShaper implements java.lang.AutoCloseable {
+ method public void apply(android.media.VolumeShaper.Operation);
+ method public void close();
+ method public float getVolume();
+ method public void replace(android.media.VolumeShaper.Configuration, android.media.VolumeShaper.Operation, boolean);
+ }
+
+ public static final class VolumeShaper.Configuration implements android.os.Parcelable {
+ method public int describeContents();
+ method public double getDurationMs();
+ method public int getInterpolatorType();
+ method public static int getMaximumCurvePoints();
+ method public float[] getTimes();
+ method public float[] getVolumes();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.media.VolumeShaper.Configuration> CREATOR;
+ field public static final android.media.VolumeShaper.Configuration CUBIC_RAMP;
+ field public static final int INTERPOLATOR_TYPE_CUBIC = 2; // 0x2
+ field public static final int INTERPOLATOR_TYPE_CUBIC_MONOTONIC = 3; // 0x3
+ field public static final int INTERPOLATOR_TYPE_LINEAR = 1; // 0x1
+ field public static final int INTERPOLATOR_TYPE_STEP = 0; // 0x0
+ field public static final android.media.VolumeShaper.Configuration LINEAR_RAMP;
+ field public static final android.media.VolumeShaper.Configuration SCURVE_RAMP;
+ field public static final android.media.VolumeShaper.Configuration SINE_RAMP;
+ }
+
+ public static final class VolumeShaper.Configuration.Builder {
+ ctor public VolumeShaper.Configuration.Builder();
+ ctor public VolumeShaper.Configuration.Builder(android.media.VolumeShaper.Configuration);
+ method public android.media.VolumeShaper.Configuration build();
+ method public android.media.VolumeShaper.Configuration.Builder invertVolumes();
+ method public android.media.VolumeShaper.Configuration.Builder reflectTimes();
+ method public android.media.VolumeShaper.Configuration.Builder scaleToEndVolume(float);
+ method public android.media.VolumeShaper.Configuration.Builder scaleToStartVolume(float);
+ method public android.media.VolumeShaper.Configuration.Builder setCurve(float[], float[]);
+ method public android.media.VolumeShaper.Configuration.Builder setDurationMs(double);
+ method public android.media.VolumeShaper.Configuration.Builder setInterpolatorType(int);
+ }
+
+ public static final class VolumeShaper.Operation implements android.os.Parcelable {
+ method public int describeContents();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.media.VolumeShaper.Operation> CREATOR;
+ field public static final android.media.VolumeShaper.Operation PLAY;
+ field public static final android.media.VolumeShaper.Operation REVERSE;
+ }
+
}
package android.media.audiofx {
@@ -23985,17 +24139,79 @@
method public static final android.net.Uri buildProgramsUriForChannel(long, long, long);
method public static final android.net.Uri buildProgramsUriForChannel(android.net.Uri, long, long);
method public static final android.net.Uri buildRecordedProgramUri(long);
+ method public static final android.net.Uri buildWatchNextProgramUri(long);
method public static final boolean isChannelUri(android.net.Uri);
method public static final boolean isChannelUriForPassthroughInput(android.net.Uri);
method public static final boolean isChannelUriForTunerInput(android.net.Uri);
method public static final boolean isProgramUri(android.net.Uri);
+ field public static final java.lang.String ACTION_MAKE_CHANNEL_BROWSABLE = "android.media.tv.action.MAKE_CHANNEL_BROWSABLE";
+ field public static final java.lang.String ACTION_PREVIEW_PROGRAM_ADDED_TO_WATCH_NEXT = "android.media.tv.action.PREVIEW_PROGRAM_ADDED_TO_WATCH_NEXT";
+ field public static final java.lang.String ACTION_PREVIEW_PROGRAM_BROWSABLE_DISABLED = "android.media.tv.action.PREVIEW_PROGRAM_BROWSABLE_DISABLED";
+ field public static final java.lang.String ACTION_WATCH_NEXT_PROGRAM_BROWSABLE_DISABLED = "android.media.tv.action.WATCH_NEXT_PROGRAM_BROWSABLE_DISABLED";
field public static final java.lang.String AUTHORITY = "android.media.tv";
+ field public static final java.lang.String EXTRA_CHANNEL_ID = "android.media.tv.extra.CHANNEL_ID";
+ field public static final java.lang.String EXTRA_PACKAGE_NAME = "android.media.tv.extra.PACKAGE_NAME";
+ field public static final java.lang.String EXTRA_PREVIEW_PROGRAM_ID = "android.media.tv.extra.PREVIEW_PROGRAM_ID";
+ field public static final java.lang.String EXTRA_WATCH_NEXT_PROGRAM_ID = "android.media.tv.extra.WATCH_NEXT_PROGRAM_ID";
+ }
+
+ public static abstract interface TvContract.BasePreviewProgramColumns implements android.media.tv.TvContract.BaseProgramColumns {
+ field public static final java.lang.String ASPECT_RATIO_16_9 = "ASPECT_RATIO_16_9";
+ field public static final java.lang.String ASPECT_RATIO_1_1 = "ASPECT_RATIO_1_1";
+ field public static final java.lang.String ASPECT_RATIO_2_3 = "ASPECT_RATIO_2_3";
+ field public static final java.lang.String ASPECT_RATIO_3_2 = "ASPECT_RATIO_3_2";
+ field public static final java.lang.String AVAILABILITY_AVAILABLE = "AVAILABILITY_AVAILABLE";
+ field public static final java.lang.String AVAILABILITY_FREE_WITH_SUBSCRIPTION = "AVAILABILITY_FREE_WITH_SUBSCRIPTION";
+ field public static final java.lang.String AVAILABILITY_PAID_CONTENT = "AVAILABILITY_PAID_CONTENT";
+ field public static final java.lang.String COLUMN_APP_LINK_INTENT_URI = "app_link_intent_uri";
+ field public static final java.lang.String COLUMN_AUTHOR = "author";
+ field public static final java.lang.String COLUMN_AVAILABILITY = "availability";
+ field public static final java.lang.String COLUMN_BROWSABLE = "browsable";
+ field public static final java.lang.String COLUMN_CONTENT_ID = "content_id";
+ field public static final java.lang.String COLUMN_DURATION_MILLIS = "duration_millis";
+ field public static final java.lang.String COLUMN_INTERACTION_COUNT = "interaction_count";
+ field public static final java.lang.String COLUMN_INTERACTION_TYPE = "interaction_type";
+ field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_ID = "internal_provider_id";
+ field public static final java.lang.String COLUMN_ITEM_COUNT = "item_count";
+ field public static final java.lang.String COLUMN_LAST_PLAYBACK_POSITION_MILLIS = "last_playback_position_millis";
+ field public static final java.lang.String COLUMN_LIVE = "live";
+ field public static final java.lang.String COLUMN_LOGO_URI = "logo_uri";
+ field public static final java.lang.String COLUMN_OFFER_PRICE = "offer_price";
+ field public static final java.lang.String COLUMN_POSTER_ART_ASPECT_RATIO = "poster_art_aspect_ratio";
+ field public static final java.lang.String COLUMN_PREVIEW_VIDEO_URI = "preview_video_uri";
+ field public static final java.lang.String COLUMN_RELEASE_DATE = "release_date";
+ field public static final java.lang.String COLUMN_REVIEW_RATING = "review_rating";
+ field public static final java.lang.String COLUMN_REVIEW_RATING_STYLE = "review_rating_style";
+ field public static final java.lang.String COLUMN_STARTING_PRICE = "starting_price";
+ field public static final java.lang.String COLUMN_THUMBNAIL_ASPECT_RATIO = "poster_thumbnail_aspect_ratio";
+ field public static final java.lang.String COLUMN_TYPE = "type";
+ field public static final java.lang.String INTERACTION_TYPE_FANS = "INTERACTION_TYPE_FANS";
+ field public static final java.lang.String INTERACTION_TYPE_FOLLOWERS = "INTERACTION_TYPE_FOLLOWERS";
+ field public static final java.lang.String INTERACTION_TYPE_LIKES = "INTERACTION_TYPE_LIKES";
+ field public static final java.lang.String INTERACTION_TYPE_LISTENS = "INTERACTION_TYPE_LISTENS";
+ field public static final java.lang.String INTERACTION_TYPE_THUMBS = "INTERACTION_TYPE_THUMBS";
+ field public static final java.lang.String INTERACTION_TYPE_VIEWERS = "INTERACTION_TYPE_VIEWERS";
+ field public static final java.lang.String INTERACTION_TYPE_VIEWS = "INTERACTION_TYPE_VIEWS";
+ field public static final java.lang.String REVIEW_RATING_STYLE_PERCENTAGE = "REVIEW_RATING_STYLE_PERCENTAGE";
+ field public static final java.lang.String REVIEW_RATING_STYLE_STARS = "REVIEW_RATING_STYLE_STARS";
+ field public static final java.lang.String REVIEW_RATING_STYLE_THUMBS_UP_DOWN = "REVIEW_RATING_STYLE_THUMBS_UP_DOWN";
+ field public static final java.lang.String TYPE_ALBUM = "TYPE_ALBUM";
+ field public static final java.lang.String TYPE_ARTIST = "TYPE_ARTIST";
+ field public static final java.lang.String TYPE_CHANNEL = "TYPE_CHANNEL";
+ field public static final java.lang.String TYPE_CLIP = "TYPE_CLIP";
+ field public static final java.lang.String TYPE_EVENT = "TYPE_EVENT";
+ field public static final java.lang.String TYPE_MOVIE = "TYPE_MOVIE";
+ field public static final java.lang.String TYPE_PLAYLIST = "TYPE_PLAYLIST";
+ field public static final java.lang.String TYPE_STATION = "TYPE_STATION";
+ field public static final java.lang.String TYPE_TRACK = "TYPE_TRACK";
+ field public static final java.lang.String TYPE_TV_EPISODE = "TYPE_TV_EPISODE";
+ field public static final java.lang.String TYPE_TV_SEASON = "TYPE_TV_SEASON";
+ field public static final java.lang.String TYPE_TV_SERIES = "TYPE_TV_SERIES";
}
public static abstract interface TvContract.BaseProgramColumns implements android.media.tv.TvContract.BaseTvColumns {
field public static final java.lang.String COLUMN_AUDIO_LANGUAGE = "audio_language";
field public static final java.lang.String COLUMN_CANONICAL_GENRE = "canonical_genre";
- field public static final java.lang.String COLUMN_CHANNEL_ID = "channel_id";
field public static final java.lang.String COLUMN_CONTENT_RATING = "content_rating";
field public static final java.lang.String COLUMN_EPISODE_DISPLAY_NUMBER = "episode_display_number";
field public static final java.lang.String COLUMN_EPISODE_TITLE = "episode_title";
@@ -24028,6 +24244,7 @@
field public static final java.lang.String COLUMN_APP_LINK_INTENT_URI = "app_link_intent_uri";
field public static final java.lang.String COLUMN_APP_LINK_POSTER_ART_URI = "app_link_poster_art_uri";
field public static final java.lang.String COLUMN_APP_LINK_TEXT = "app_link_text";
+ field public static final java.lang.String COLUMN_BROWSABLE = "browsable";
field public static final java.lang.String COLUMN_DESCRIPTION = "description";
field public static final java.lang.String COLUMN_DISPLAY_NAME = "display_name";
field public static final java.lang.String COLUMN_DISPLAY_NUMBER = "display_number";
@@ -24100,69 +24317,17 @@
field public static final java.lang.String CONTENT_DIRECTORY = "logo";
}
- public static final class TvContract.PreviewPrograms implements android.media.tv.TvContract.BaseProgramColumns {
- field public static final java.lang.String ASPECT_RATIO_16_9 = "ASPECT_RATIO_16_9";
- field public static final java.lang.String ASPECT_RATIO_1_1 = "ASPECT_RATIO_1_1";
- field public static final java.lang.String ASPECT_RATIO_2_3 = "ASPECT_RATIO_2_3";
- field public static final java.lang.String ASPECT_RATIO_3_2 = "ASPECT_RATIO_3_2";
- field public static final java.lang.String AVAILABILITY_AVAILABLE = "AVAILABILITY_AVAILABLE";
- field public static final java.lang.String AVAILABILITY_FREE_WITH_SUBSCRIPTION = "AVAILABILITY_FREE_WITH_SUBSCRIPTION";
- field public static final java.lang.String AVAILABILITY_PAID_CONTENT = "AVAILABILITY_PAID_CONTENT";
- field public static final java.lang.String COLUMN_APP_LINK_INTENT_URI = "app_link_intent_uri";
- field public static final java.lang.String COLUMN_AUTHOR = "author";
- field public static final java.lang.String COLUMN_AVAILABILITY = "availability";
- field public static final java.lang.String COLUMN_BROWSABLE = "browsable";
- field public static final java.lang.String COLUMN_DURATION_MILLIS = "duration_millis";
- field public static final java.lang.String COLUMN_INTERACTION_COUNT = "interaction_count";
- field public static final java.lang.String COLUMN_INTERACTION_TYPE = "interaction_type";
- field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_ID = "internal_provider_id";
- field public static final java.lang.String COLUMN_ITEM_COUNT = "item_count";
- field public static final java.lang.String COLUMN_LAST_PLAYBACK_POSITION_MILLIS = "last_playback_position_millis";
- field public static final java.lang.String COLUMN_LIVE = "live";
- field public static final java.lang.String COLUMN_LOGO_URI = "logo_uri";
- field public static final java.lang.String COLUMN_OFFER_PRICE = "offer_price";
- field public static final java.lang.String COLUMN_POSTER_ART_ASPECT_RATIO = "poster_art_aspect_ratio";
- field public static final java.lang.String COLUMN_PREVIEW_VIDEO_URI = "preview_video_uri";
- field public static final java.lang.String COLUMN_RELEASE_DATE = "release_date";
- field public static final java.lang.String COLUMN_REVIEW_RATING = "review_rating";
- field public static final java.lang.String COLUMN_REVIEW_RATING_STYLE = "review_rating_style";
- field public static final java.lang.String COLUMN_STARTING_PRICE = "starting_price";
- field public static final java.lang.String COLUMN_THUMBNAIL_ASPECT_RATIO = "poster_thumbnail_aspect_ratio";
- field public static final java.lang.String COLUMN_TYPE = "type";
- field public static final java.lang.String COLUMN_WATCH_NEXT_TYPE = "watch_next_type";
+ public static final class TvContract.PreviewPrograms implements android.media.tv.TvContract.BasePreviewProgramColumns {
+ field public static final java.lang.String COLUMN_CHANNEL_ID = "channel_id";
field public static final java.lang.String COLUMN_WEIGHT = "weight";
field public static final java.lang.String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/preview_program";
field public static final java.lang.String CONTENT_TYPE = "vnd.android.cursor.dir/preview_program";
field public static final android.net.Uri CONTENT_URI;
- field public static final java.lang.String INTERACTION_TYPE_FANS = "INTERACTION_TYPE_FANS";
- field public static final java.lang.String INTERACTION_TYPE_FOLLOWERS = "INTERACTION_TYPE_FOLLOWERS";
- field public static final java.lang.String INTERACTION_TYPE_LIKES = "INTERACTION_TYPE_LIKES";
- field public static final java.lang.String INTERACTION_TYPE_LISTENS = "INTERACTION_TYPE_LISTENS";
- field public static final java.lang.String INTERACTION_TYPE_THUMBS = "INTERACTION_TYPE_THUMBS";
- field public static final java.lang.String INTERACTION_TYPE_VIEWERS = "INTERACTION_TYPE_VIEWERS";
- field public static final java.lang.String INTERACTION_TYPE_VIEWS = "INTERACTION_TYPE_VIEWS";
- field public static final java.lang.String REVIEW_RATING_STYLE_PERCENTAGE = "REVIEW_RATING_STYLE_PERCENTAGE";
- field public static final java.lang.String REVIEW_RATING_STYLE_STARS = "REVIEW_RATING_STYLE_STARS";
- field public static final java.lang.String REVIEW_RATING_STYLE_THUMBS_UP_DOWN = "REVIEW_RATING_STYLE_THUMBS_UP_DOWN";
- field public static final java.lang.String TYPE_ALBUM = "TYPE_ALBUM";
- field public static final java.lang.String TYPE_ARTIST = "TYPE_ARTIST";
- field public static final java.lang.String TYPE_CHANNEL = "TYPE_CHANNEL";
- field public static final java.lang.String TYPE_CLIP = "TYPE_CLIP";
- field public static final java.lang.String TYPE_EVENT = "TYPE_EVENT";
- field public static final java.lang.String TYPE_MOVIE = "TYPE_MOVIE";
- field public static final java.lang.String TYPE_PLAYLIST = "TYPE_PLAYLIST";
- field public static final java.lang.String TYPE_STATION = "TYPE_STATION";
- field public static final java.lang.String TYPE_TRACK = "TYPE_TRACK";
- field public static final java.lang.String TYPE_TV_EPISODE = "TYPE_TV_EPISODE";
- field public static final java.lang.String TYPE_TV_SEASON = "TYPE_TV_SEASON";
- field public static final java.lang.String TYPE_TV_SERIES = "TYPE_TV_SERIES";
- field public static final java.lang.String WATCH_NEXT_TYPE_CONTINUE = "WATCH_NEXT_TYPE_CONTINUE";
- field public static final java.lang.String WATCH_NEXT_TYPE_NEW = "WATCH_NEXT_TYPE_NEW";
- field public static final java.lang.String WATCH_NEXT_TYPE_NEXT = "WATCH_NEXT_TYPE_NEXT";
}
public static final class TvContract.Programs implements android.media.tv.TvContract.BaseProgramColumns {
field public static final java.lang.String COLUMN_BROADCAST_GENRE = "broadcast_genre";
+ field public static final java.lang.String COLUMN_CHANNEL_ID = "channel_id";
field public static final java.lang.String COLUMN_END_TIME_UTC_MILLIS = "end_time_utc_millis";
field public static final deprecated java.lang.String COLUMN_EPISODE_NUMBER = "episode_number";
field public static final java.lang.String COLUMN_RECORDING_PROHIBITED = "recording_prohibited";
@@ -24198,6 +24363,7 @@
public static final class TvContract.RecordedPrograms implements android.media.tv.TvContract.BaseProgramColumns {
field public static final java.lang.String COLUMN_BROADCAST_GENRE = "broadcast_genre";
+ field public static final java.lang.String COLUMN_CHANNEL_ID = "channel_id";
field public static final java.lang.String COLUMN_END_TIME_UTC_MILLIS = "end_time_utc_millis";
field public static final java.lang.String COLUMN_INPUT_ID = "input_id";
field public static final java.lang.String COLUMN_RECORDING_DATA_BYTES = "recording_data_bytes";
@@ -24210,6 +24376,19 @@
field public static final android.net.Uri CONTENT_URI;
}
+ public static final class TvContract.WatchNextPrograms implements android.media.tv.TvContract.BasePreviewProgramColumns {
+ ctor public TvContract.WatchNextPrograms();
+ field public static final java.lang.String COLUMN_LAST_ENGAGEMENT_TIME_UTC_MILLIS = "last_engagement_time_utc_millis";
+ field public static final java.lang.String COLUMN_WATCH_NEXT_TYPE = "watch_next_type";
+ field public static final java.lang.String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/watch_next_program";
+ field public static final java.lang.String CONTENT_TYPE = "vnd.android.cursor.dir/watch_next_program";
+ field public static final android.net.Uri CONTENT_URI;
+ field public static final java.lang.String WATCH_NEXT_TYPE_CONTINUE = "WATCH_NEXT_TYPE_CONTINUE";
+ field public static final java.lang.String WATCH_NEXT_TYPE_NEW = "WATCH_NEXT_TYPE_NEW";
+ field public static final java.lang.String WATCH_NEXT_TYPE_NEXT = "WATCH_NEXT_TYPE_NEXT";
+ field public static final java.lang.String WATCH_NEXT_TYPE_WATCHLIST = "WATCH_NEXT_TYPE_WATCHLIST";
+ }
+
public final class TvInputInfo implements android.os.Parcelable {
method public boolean canRecord();
method public android.content.Intent createSettingsIntent();
@@ -24259,15 +24438,10 @@
method public void unregisterCallback(android.media.tv.TvInputManager.TvInputCallback);
method public void updateTvInputInfo(android.media.tv.TvInputInfo);
field public static final java.lang.String ACTION_BLOCKED_RATINGS_CHANGED = "android.media.tv.action.BLOCKED_RATINGS_CHANGED";
- field public static final java.lang.String ACTION_MAKE_CHANNEL_BROWSABLE = "android.media.tv.action.MAKE_CHANNEL_BROWSABLE";
field public static final java.lang.String ACTION_PARENTAL_CONTROLS_ENABLED_CHANGED = "android.media.tv.action.PARENTAL_CONTROLS_ENABLED_CHANGED";
- field public static final java.lang.String ACTION_PROGRAM_BROWSABLE_DISABLED = "android.media.tv.action.PROGRAM_BROWSABLE_DISABLED";
field public static final java.lang.String ACTION_QUERY_CONTENT_RATING_SYSTEMS = "android.media.tv.action.QUERY_CONTENT_RATING_SYSTEMS";
field public static final java.lang.String ACTION_SETUP_INPUTS = "android.media.tv.action.SETUP_INPUTS";
field public static final java.lang.String ACTION_VIEW_RECORDING_SCHEDULES = "android.media.tv.action.VIEW_RECORDING_SCHEDULES";
- field public static final java.lang.String EXTRA_CHANNEL_ID = "android.media.tv.extra.CHANNEL_ID";
- field public static final java.lang.String EXTRA_PACKAGE_NAME = "android.media.tv.extra.PACKAGE_NAME";
- field public static final java.lang.String EXTRA_PROGRAM_ID = "android.media.tv.extra.PROGRAM_ID";
field public static final int INPUT_STATE_CONNECTED = 0; // 0x0
field public static final int INPUT_STATE_CONNECTED_STANDBY = 1; // 0x1
field public static final int INPUT_STATE_DISCONNECTED = 2; // 0x2
@@ -24839,6 +25013,68 @@
field public static final android.os.Parcelable.Creator<android.net.IpPrefix> CREATOR;
}
+ public final class IpSecAlgorithm implements android.os.Parcelable {
+ ctor public IpSecAlgorithm(java.lang.String, byte[]);
+ ctor public IpSecAlgorithm(java.lang.String, byte[], int);
+ method public int describeContents();
+ method public byte[] getKey();
+ method public java.lang.String getName();
+ method public int getTruncationLengthBits();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final java.lang.String ALGO_AUTH_HMAC_MD5 = "hmac(md5)";
+ field public static final java.lang.String ALGO_AUTH_HMAC_SHA1 = "hmac(sha1)";
+ field public static final java.lang.String ALGO_AUTH_HMAC_SHA256 = "hmac(sha256)";
+ field public static final java.lang.String ALGO_AUTH_HMAC_SHA384 = "hmac(sha384)";
+ field public static final java.lang.String ALGO_AUTH_HMAC_SHA512 = "hmac(sha512)";
+ field public static final java.lang.String ALGO_CRYPT_AES_CBC = "cbc(aes)";
+ field public static final android.os.Parcelable.Creator<android.net.IpSecAlgorithm> CREATOR;
+ }
+
+ public final class IpSecManager {
+ method public void applyTransportModeTransform(java.net.Socket, android.net.IpSecTransform) throws java.io.IOException;
+ method public void applyTransportModeTransform(java.net.DatagramSocket, android.net.IpSecTransform) throws java.io.IOException;
+ method public android.net.IpSecManager.UdpEncapsulationSocket openUdpEncapsulationSocket(int) throws java.io.IOException, android.net.IpSecManager.ResourceUnavailableException;
+ method public android.net.IpSecManager.UdpEncapsulationSocket openUdpEncapsulationSocket() throws java.io.IOException, android.net.IpSecManager.ResourceUnavailableException;
+ method public void removeTransportModeTransform(java.net.Socket, android.net.IpSecTransform);
+ method public void removeTransportModeTransform(java.net.DatagramSocket, android.net.IpSecTransform);
+ method public android.net.IpSecManager.SecurityParameterIndex reserveSecurityParameterIndex(java.net.InetAddress, int) throws android.net.IpSecManager.ResourceUnavailableException, android.net.IpSecManager.SpiUnavailableException;
+ field public static final int INVALID_SECURITY_PARAMETER_INDEX = 0; // 0x0
+ }
+
+ public static final class IpSecManager.ResourceUnavailableException extends android.util.AndroidException {
+ }
+
+ public static final class IpSecManager.SecurityParameterIndex implements java.lang.AutoCloseable {
+ method public void close();
+ method public int getSpi();
+ }
+
+ public static final class IpSecManager.SpiUnavailableException extends android.util.AndroidException {
+ method public int getSpi();
+ }
+
+ public static final class IpSecManager.UdpEncapsulationSocket implements java.lang.AutoCloseable {
+ method public void close();
+ method public int getPort();
+ method public java.io.FileDescriptor getSocket();
+ }
+
+ public final class IpSecTransform implements java.lang.AutoCloseable {
+ method public void close();
+ field public static final int DIRECTION_IN = 0; // 0x0
+ field public static final int DIRECTION_OUT = 1; // 0x1
+ }
+
+ public static class IpSecTransform.Builder {
+ ctor public IpSecTransform.Builder(android.content.Context);
+ method public android.net.IpSecTransform buildTransportModeTransform(java.net.InetAddress) throws java.io.IOException, android.net.IpSecManager.ResourceUnavailableException, android.net.IpSecManager.SpiUnavailableException;
+ method public android.net.IpSecTransform.Builder setAuthentication(int, android.net.IpSecAlgorithm);
+ method public android.net.IpSecTransform.Builder setEncryption(int, android.net.IpSecAlgorithm);
+ method public android.net.IpSecTransform.Builder setIpv4Encapsulation(android.net.IpSecManager.UdpEncapsulationSocket, int);
+ method public android.net.IpSecTransform.Builder setSpi(int, int);
+ method public android.net.IpSecTransform.Builder setSpi(int, android.net.IpSecManager.SecurityParameterIndex);
+ }
+
public class LinkAddress implements android.os.Parcelable {
method public int describeContents();
method public java.net.InetAddress getAddress();
@@ -26019,8 +26255,6 @@
public class DiscoverySession {
method public java.lang.String createNetworkSpecifier(android.net.wifi.aware.PeerHandle, byte[]);
method public void destroy();
- method public static int getMaxSendRetryCount();
- method public void sendMessage(android.net.wifi.aware.PeerHandle, int, byte[], int);
method public void sendMessage(android.net.wifi.aware.PeerHandle, int, byte[]);
}
@@ -29891,7 +30125,7 @@
field public static final int BATTERY_PLUGGED_AC = 1; // 0x1
field public static final int BATTERY_PLUGGED_USB = 2; // 0x2
field public static final int BATTERY_PLUGGED_WIRELESS = 4; // 0x4
- field public static final int BATTERY_PROPERTY_BATTERY_STATUS = 6; // 0x6
+ field public static final int BATTERY_PROPERTY_STATUS = 6; // 0x6
field public static final int BATTERY_PROPERTY_CAPACITY = 4; // 0x4
field public static final int BATTERY_PROPERTY_CHARGE_COUNTER = 1; // 0x1
field public static final int BATTERY_PROPERTY_CURRENT_AVERAGE = 3; // 0x3
@@ -36265,10 +36499,10 @@
public static final class FillResponse.Builder {
ctor public FillResponse.Builder();
method public android.service.autofill.FillResponse.Builder addDataset(android.service.autofill.Dataset);
- method public android.service.autofill.FillResponse.Builder addSavableFields(android.view.autofill.AutoFillId...);
method public android.service.autofill.FillResponse build();
method public android.service.autofill.FillResponse.Builder setAuthentication(android.content.IntentSender, android.widget.RemoteViews);
method public android.service.autofill.FillResponse.Builder setExtras(android.os.Bundle);
+ method public android.service.autofill.FillResponse.Builder setSaveInfo(android.service.autofill.SaveInfo);
}
public final class SaveCallback {
@@ -36276,6 +36510,23 @@
method public void onSuccess();
}
+ public final class SaveInfo implements android.os.Parcelable {
+ method public int describeContents();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.service.autofill.SaveInfo> CREATOR;
+ field public static final int SAVE_DATA_TYPE_ADDRESS = 2; // 0x2
+ field public static final int SAVE_DATA_TYPE_CREDIT_CARD = 3; // 0x3
+ field public static final int SAVE_DATA_TYPE_GENERIC = 0; // 0x0
+ field public static final int SAVE_DATA_TYPE_PASSWORD = 1; // 0x1
+ }
+
+ public static final class SaveInfo.Builder {
+ ctor public SaveInfo.Builder(int);
+ method public android.service.autofill.SaveInfo.Builder addSavableIds(android.view.autofill.AutoFillId...);
+ method public android.service.autofill.SaveInfo build();
+ method public android.service.autofill.SaveInfo.Builder setDescription(java.lang.CharSequence);
+ }
+
}
package android.service.carrier {
@@ -37993,9 +38244,6 @@
field public static final int RTT_MODE_VCO = 3; // 0x3
}
- public static abstract class Call.RttCall.RttAudioMode implements java.lang.annotation.Annotation {
- }
-
public final class CallAudioState implements android.os.Parcelable {
ctor public CallAudioState(boolean, int, int);
method public static java.lang.String audioRouteToString(int);
@@ -38536,6 +38784,8 @@
}
public class TelecomManager {
+ method public void acceptRingingCall();
+ method public void acceptRingingCall(int);
method public void addNewIncomingCall(android.telecom.PhoneAccountHandle, android.os.Bundle);
method public void cancelMissedCallsNotification();
method public android.content.Intent createManageBlockedNumbersIntent();
@@ -40152,7 +40402,7 @@
package android.test.suitebuilder {
- public class TestMethod {
+ public deprecated class TestMethod {
ctor public TestMethod(java.lang.reflect.Method, java.lang.Class<? extends junit.framework.TestCase>);
ctor public TestMethod(java.lang.String, java.lang.Class<? extends junit.framework.TestCase>);
ctor public TestMethod(junit.framework.TestCase);
@@ -40163,7 +40413,7 @@
method public java.lang.String getName();
}
- public class TestSuiteBuilder {
+ public deprecated class TestSuiteBuilder {
ctor public TestSuiteBuilder(java.lang.Class);
ctor public TestSuiteBuilder(java.lang.String, java.lang.ClassLoader);
method public android.test.suitebuilder.TestSuiteBuilder addRequirements(java.util.List<com.android.internal.util.Predicate<android.test.suitebuilder.TestMethod>>);
@@ -40176,7 +40426,7 @@
method public android.test.suitebuilder.TestSuiteBuilder named(java.lang.String);
}
- public static class TestSuiteBuilder.FailedToCreateTests extends junit.framework.TestCase {
+ public static deprecated class TestSuiteBuilder.FailedToCreateTests extends junit.framework.TestCase {
ctor public TestSuiteBuilder.FailedToCreateTests(java.lang.Exception);
method public void testSuiteConstructionFailed();
}
@@ -42391,30 +42641,51 @@
method public abstract void setValue(T, float);
}
- public final class Half {
+ public final class Half extends java.lang.Number implements java.lang.Comparable {
+ ctor public Half(short);
+ ctor public Half(float);
+ ctor public Half(double);
+ ctor public Half(java.lang.String) throws java.lang.NumberFormatException;
method public static short abs(short);
method public static short ceil(short);
+ method public static int compare(short, short);
+ method public int compareTo(android.util.Half);
method public static short copySign(short, short);
+ method public double doubleValue();
method public static boolean equals(short, short);
+ method public float floatValue();
method public static short floor(short);
method public static int getExponent(short);
method public static int getSign(short);
method public static int getSignificand(short);
method public static boolean greater(short, short);
method public static boolean greaterEquals(short, short);
+ method public static int halfToIntBits(short);
+ method public static int halfToRawIntBits(short);
+ method public static short halfToShortBits(short);
+ method public short halfValue();
+ method public static int hashCode(short);
+ method public static short intBitsToHalf(int);
+ method public int intValue();
method public static boolean isInfinite(short);
+ method public boolean isNaN();
method public static boolean isNaN(short);
method public static boolean isNormalized(short);
method public static boolean less(short, short);
method public static boolean lessEquals(short, short);
+ method public long longValue();
method public static short max(short, short);
method public static short min(short, short);
+ method public static short parseHalf(java.lang.String) throws java.lang.NumberFormatException;
method public static short round(short);
method public static float toFloat(short);
+ method public static short toHalf(float);
method public static java.lang.String toHexString(short);
method public static java.lang.String toString(short);
method public static short trunc(short);
- method public static short valueOf(float);
+ method public static android.util.Half valueOf(short);
+ method public static android.util.Half valueOf(float);
+ method public static android.util.Half valueOf(java.lang.String);
field public static final short EPSILON = 5120; // 0x1400
field public static final short LOWEST_VALUE = -1025; // 0xfffffbff
field public static final int MAX_EXPONENT = 15; // 0xf
@@ -43139,11 +43410,13 @@
field public static final int DRAW_DURATION = 4; // 0x4
field public static final int FIRST_DRAW_FRAME = 9; // 0x9
field public static final int INPUT_HANDLING_DURATION = 1; // 0x1
+ field public static final int INTENDED_VSYNC_TIMESTAMP = 10; // 0xa
field public static final int LAYOUT_MEASURE_DURATION = 3; // 0x3
field public static final int SWAP_BUFFERS_DURATION = 7; // 0x7
field public static final int SYNC_DURATION = 5; // 0x5
field public static final int TOTAL_DURATION = 8; // 0x8
field public static final int UNKNOWN_DELAY_DURATION = 0; // 0x0
+ field public static final int VSYNC_TIMESTAMP = 11; // 0xb
}
public abstract class FrameStats {
@@ -44516,8 +44789,8 @@
method public void drawableHotspotChanged(float, float);
method protected void drawableStateChanged();
method public android.view.View findFocus();
- method public final android.view.View findViewById(int);
- method public final android.view.View findViewWithTag(java.lang.Object);
+ method public final <T extends android.view.View> T findViewById(int);
+ method public final <T extends android.view.View> T findViewWithTag(java.lang.Object);
method public void findViewsWithText(java.util.ArrayList<android.view.View>, java.lang.CharSequence, int);
method protected deprecated boolean fitSystemWindows(android.graphics.Rect);
method public android.view.View focusSearch(int);
@@ -45642,6 +45915,7 @@
method public abstract void setAccessibilityFocused(boolean);
method public abstract void setActivated(boolean);
method public abstract void setAlpha(float);
+ method public abstract void setAutoFillOptions(java.lang.String[]);
method public abstract void setAutoFillType(android.view.autofill.AutoFillType);
method public abstract void setAutoFillValue(android.view.autofill.AutoFillValue);
method public abstract void setCheckable(boolean);
@@ -50824,6 +51098,8 @@
method public int resolveAdjustedSize(int, int);
method public void resume();
method public void seekTo(int);
+ method public void setAudioAttributes(android.media.AudioAttributes);
+ method public void setAudioFocusRequest(int);
method public void setMediaController(android.widget.MediaController);
method public void setOnCompletionListener(android.media.MediaPlayer.OnCompletionListener);
method public void setOnErrorListener(android.media.MediaPlayer.OnErrorListener);
@@ -50928,7 +51204,7 @@
package com.android.internal.util {
- public abstract interface Predicate<T> {
+ public abstract deprecated interface Predicate<T> {
method public abstract boolean apply(T);
}
diff --git a/api/removed.txt b/api/removed.txt
index e467811..c5dbf8d 100644
--- a/api/removed.txt
+++ b/api/removed.txt
@@ -20,25 +20,14 @@
package android.content {
public abstract class Context {
- method public deprecated android.content.Context createCredentialEncryptedStorageContext();
- method public deprecated android.content.Context createDeviceEncryptedStorageContext();
method public abstract android.content.SharedPreferences getSharedPreferences(java.io.File, int);
method public abstract java.io.File getSharedPreferencesPath(java.lang.String);
- method public deprecated boolean isCredentialEncryptedStorage();
- method public deprecated boolean isDeviceEncryptedStorage();
- method public deprecated boolean migrateDatabaseFrom(android.content.Context, java.lang.String);
- method public deprecated boolean migrateSharedPreferencesFrom(android.content.Context, java.lang.String);
}
}
package android.content.pm {
- public class ApplicationInfo extends android.content.pm.PackageItemInfo implements android.os.Parcelable {
- field public deprecated java.lang.String credentialEncryptedDataDir;
- field public deprecated java.lang.String deviceEncryptedDataDir;
- }
-
public class ComponentInfo extends android.content.pm.PackageItemInfo {
field public deprecated boolean encryptionAware;
}
@@ -47,12 +36,6 @@
field public static final int REQUESTED_PERMISSION_REQUIRED = 1; // 0x1
}
- public abstract class PackageManager {
- field public static final deprecated int MATCH_ENCRYPTION_AWARE = 524288; // 0x80000
- field public static final deprecated int MATCH_ENCRYPTION_AWARE_AND_UNAWARE = 786432; // 0xc0000
- field public static final deprecated int MATCH_ENCRYPTION_UNAWARE = 262144; // 0x40000
- }
-
}
package android.database {
@@ -169,10 +152,6 @@
method public android.graphics.drawable.Drawable getBadgedDrawableForUser(android.graphics.drawable.Drawable, android.os.UserHandle, android.graphics.Rect, int);
method public android.graphics.drawable.Drawable getBadgedIconForUser(android.graphics.drawable.Drawable, android.os.UserHandle);
method public java.lang.CharSequence getBadgedLabelForUser(java.lang.CharSequence, android.os.UserHandle);
- method public deprecated boolean isUserRunningAndLocked();
- method public deprecated boolean isUserRunningAndLocked(android.os.UserHandle);
- method public deprecated boolean isUserRunningAndUnlocked();
- method public deprecated boolean isUserRunningAndUnlocked(android.os.UserHandle);
}
}
@@ -190,15 +169,6 @@
}
-package android.preference {
-
- public class PreferenceManager {
- method public deprecated void setStorageCredentialEncrypted();
- method public deprecated void setStorageDeviceEncrypted();
- }
-
-}
-
package android.provider {
public class Browser {
diff --git a/api/system-current.txt b/api/system-current.txt
index 2f67204..a467351 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -25,6 +25,7 @@
field public static final java.lang.String ADD_VOICEMAIL = "com.android.voicemail.permission.ADD_VOICEMAIL";
field public static final java.lang.String ALLOCATE_AGGRESSIVE = "android.permission.ALLOCATE_AGGRESSIVE";
field public static final java.lang.String ALLOW_ANY_CODEC_FOR_PLAYBACK = "android.permission.ALLOW_ANY_CODEC_FOR_PLAYBACK";
+ field public static final java.lang.String ANSWER_PHONE_CALLS = "android.permission.ANSWER_PHONE_CALLS";
field public static final java.lang.String BACKUP = "android.permission.BACKUP";
field public static final java.lang.String BATTERY_STATS = "android.permission.BATTERY_STATS";
field public static final java.lang.String BIND_ACCESSIBILITY_SERVICE = "android.permission.BIND_ACCESSIBILITY_SERVICE";
@@ -418,7 +419,7 @@
field public static final int autoSizeMinTextSize = 16844088; // 0x1010538
field public static final int autoSizePresetSizes = 16844087; // 0x1010537
field public static final int autoSizeStepGranularity = 16844086; // 0x1010536
- field public static final int autoSizeText = 16844085; // 0x1010535
+ field public static final int autoSizeTextType = 16844085; // 0x1010535
field public static final int autoStart = 16843445; // 0x10102b5
field public static final deprecated int autoText = 16843114; // 0x101016a
field public static final int autoUrlDetect = 16843404; // 0x101028c
@@ -523,6 +524,7 @@
field public static final int colorControlHighlight = 16843820; // 0x101042c
field public static final int colorControlNormal = 16843817; // 0x1010429
field public static final int colorEdgeEffect = 16843982; // 0x10104ce
+ field public static final int colorError = 16844100; // 0x1010544
field public static final int colorFocusedHighlight = 16843663; // 0x101038f
field public static final int colorForeground = 16842800; // 0x1010030
field public static final int colorForegroundInverse = 16843270; // 0x1010206
@@ -1433,7 +1435,6 @@
field public static final int textCheckMarkInverse = 16842823; // 0x1010047
field public static final int textColor = 16842904; // 0x1010098
field public static final int textColorAlertDialogListItem = 16843526; // 0x1010306
- field public static final int textColorError = 16844100; // 0x1010544
field public static final int textColorHighlight = 16842905; // 0x1010099
field public static final int textColorHighlightInverse = 16843599; // 0x101034f
field public static final int textColorHint = 16842906; // 0x101009a
@@ -4286,6 +4287,7 @@
field public static final int MODE_IGNORED = 1; // 0x1
field public static final java.lang.String OPSTR_ACTIVATE_VPN = "android:activate_vpn";
field public static final java.lang.String OPSTR_ADD_VOICEMAIL = "android:add_voicemail";
+ field public static final java.lang.String OPSTR_ANSWER_PHONE_CALLS = "android:answer_phone_calls";
field public static final java.lang.String OPSTR_BODY_SENSORS = "android:body_sensors";
field public static final java.lang.String OPSTR_CALL_PHONE = "android:call_phone";
field public static final java.lang.String OPSTR_CAMERA = "android:camera";
@@ -4898,6 +4900,7 @@
method public abstract android.app.Fragment getPrimaryNavigationFragment();
method public void invalidateOptionsMenu();
method public abstract boolean isDestroyed();
+ method public abstract boolean isStateSaved();
method public abstract void popBackStack();
method public abstract void popBackStack(java.lang.String, int);
method public abstract void popBackStack(int, int);
@@ -6787,6 +6790,7 @@
public static class AssistStructure.ViewNode {
method public float getAlpha();
method public android.view.autofill.AutoFillId getAutoFillId();
+ method public java.lang.String[] getAutoFillOptions();
method public android.view.autofill.AutoFillType getAutoFillType();
method public android.view.autofill.AutoFillValue getAutoFillValue();
method public android.app.assist.AssistStructure.ViewNode getChildAt(int);
@@ -7108,6 +7112,7 @@
method public android.app.job.JobInfo.TriggerContentUri[] getTriggerContentUris();
method public boolean isPeriodic();
method public boolean isPersisted();
+ method public boolean isRequireBatteryNotLow();
method public boolean isRequireCharging();
method public boolean isRequireDeviceIdle();
method public void writeToParcel(android.os.Parcel, int);
@@ -7134,6 +7139,7 @@
method public android.app.job.JobInfo.Builder setPeriodic(long, long);
method public android.app.job.JobInfo.Builder setPersisted(boolean);
method public android.app.job.JobInfo.Builder setRequiredNetworkType(int);
+ method public android.app.job.JobInfo.Builder setRequiresBatteryNotLow(boolean);
method public android.app.job.JobInfo.Builder setRequiresCharging(boolean);
method public android.app.job.JobInfo.Builder setRequiresDeviceIdle(boolean);
method public android.app.job.JobInfo.Builder setTransientExtras(android.os.Bundle);
@@ -7304,6 +7310,7 @@
method public long getFreeBytes(java.lang.String);
method public long getTotalBytes(java.lang.String);
method public android.app.usage.ExternalStorageStats queryExternalStatsForUser(java.lang.String, android.os.UserHandle);
+ method public android.app.usage.StorageStats queryStatsForPackage(java.lang.String, java.lang.String, android.os.UserHandle);
method public android.app.usage.StorageStats queryStatsForUid(java.lang.String, int);
method public android.app.usage.StorageStats queryStatsForUser(java.lang.String, android.os.UserHandle);
}
@@ -9132,6 +9139,7 @@
field public static final java.lang.String HDMI_CONTROL_SERVICE = "hdmi_control";
field public static final java.lang.String INPUT_METHOD_SERVICE = "input_method";
field public static final java.lang.String INPUT_SERVICE = "input";
+ field public static final java.lang.String IPSEC_SERVICE = "ipsec";
field public static final java.lang.String JOB_SCHEDULER_SERVICE = "jobscheduler";
field public static final java.lang.String KEYGUARD_SERVICE = "keyguard";
field public static final java.lang.String LAUNCHER_APPS_SERVICE = "launcherapps";
@@ -9512,6 +9520,7 @@
field public static final java.lang.String ACTION_CALL = "android.intent.action.CALL";
field public static final java.lang.String ACTION_CALL_BUTTON = "android.intent.action.CALL_BUTTON";
field public static final java.lang.String ACTION_CAMERA_BUTTON = "android.intent.action.CAMERA_BUTTON";
+ field public static final java.lang.String ACTION_CARRIER_SETUP = "android.intent.action.CARRIER_SETUP";
field public static final java.lang.String ACTION_CHOOSER = "android.intent.action.CHOOSER";
field public static final java.lang.String ACTION_CLEAR_PACKAGE = "android.intent.action.CLEAR_PACKAGE";
field public static final java.lang.String ACTION_CLOSE_SYSTEM_DIALOGS = "android.intent.action.CLOSE_SYSTEM_DIALOGS";
@@ -10636,10 +10645,12 @@
ctor public LauncherApps.ShortcutQuery();
method public android.content.pm.LauncherApps.ShortcutQuery setActivity(android.content.ComponentName);
method public android.content.pm.LauncherApps.ShortcutQuery setChangedSince(long);
+ method public android.content.pm.LauncherApps.ShortcutQuery setIntent(android.content.Intent);
method public android.content.pm.LauncherApps.ShortcutQuery setPackage(java.lang.String);
method public android.content.pm.LauncherApps.ShortcutQuery setQueryFlags(int);
method public android.content.pm.LauncherApps.ShortcutQuery setShortcutIds(java.util.List<java.lang.String>);
field public static final int FLAG_GET_KEY_FIELDS_ONLY = 4; // 0x4
+ field public static final int FLAG_MATCH_CHOOSER = 16; // 0x10
field public static final int FLAG_MATCH_DYNAMIC = 1; // 0x1
field public static final int FLAG_MATCH_MANIFEST = 8; // 0x8
field public static final int FLAG_MATCH_PINNED = 2; // 0x2
@@ -10695,9 +10706,11 @@
method public void unregisterSessionCallback(android.content.pm.PackageInstaller.SessionCallback);
method public void updateSessionAppIcon(int, android.graphics.Bitmap);
method public void updateSessionAppLabel(int, java.lang.CharSequence);
+ field public static final java.lang.String ACTION_SESSION_COMMITTED = "android.content.pm.action.SESSION_COMMITTED";
field public static final java.lang.String ACTION_SESSION_DETAILS = "android.content.pm.action.SESSION_DETAILS";
field public static final java.lang.String EXTRA_OTHER_PACKAGE_NAME = "android.content.pm.extra.OTHER_PACKAGE_NAME";
field public static final java.lang.String EXTRA_PACKAGE_NAME = "android.content.pm.extra.PACKAGE_NAME";
+ field public static final java.lang.String EXTRA_SESSION = "android.content.pm.extra.SESSION";
field public static final java.lang.String EXTRA_SESSION_ID = "android.content.pm.extra.SESSION_ID";
field public static final java.lang.String EXTRA_STATUS = "android.content.pm.extra.STATUS";
field public static final java.lang.String EXTRA_STATUS_MESSAGE = "android.content.pm.extra.STATUS_MESSAGE";
@@ -10740,6 +10753,7 @@
method public android.graphics.Bitmap getAppIcon();
method public java.lang.CharSequence getAppLabel();
method public java.lang.String getAppPackageName();
+ method public int getInstallReason();
method public java.lang.String getInstallerPackageName();
method public float getProgress();
method public int getSessionId();
@@ -11214,6 +11228,7 @@
field public android.content.pm.ActivityInfo activityInfo;
field public android.content.IntentFilter filter;
field public int icon;
+ field public boolean instantAppAvailable;
field public boolean isDefault;
field public int labelRes;
field public int match;
@@ -11263,6 +11278,9 @@
method public int describeContents();
method public android.content.ComponentName getActivity();
method public java.util.Set<java.lang.String> getCategories();
+ method public android.content.ComponentName[] getChooserComponentNames();
+ method public android.os.PersistableBundle getChooserExtras();
+ method public android.content.IntentFilter[] getChooserIntentFilters();
method public java.lang.CharSequence getDisabledMessage();
method public android.os.PersistableBundle getExtras();
method public java.lang.String getId();
@@ -11275,6 +11293,7 @@
method public java.lang.CharSequence getShortLabel();
method public android.os.UserHandle getUserHandle();
method public boolean hasKeyFieldsOnly();
+ method public boolean isChooser();
method public boolean isDeclaredInManifest();
method public boolean isDynamic();
method public boolean isEnabled();
@@ -11287,9 +11306,11 @@
public static class ShortcutInfo.Builder {
ctor public ShortcutInfo.Builder(android.content.Context, java.lang.String);
+ method public android.content.pm.ShortcutInfo.Builder addChooserIntentFilter(android.content.IntentFilter, android.content.ComponentName);
method public android.content.pm.ShortcutInfo build();
method public android.content.pm.ShortcutInfo.Builder setActivity(android.content.ComponentName);
method public android.content.pm.ShortcutInfo.Builder setCategories(java.util.Set<java.lang.String>);
+ method public android.content.pm.ShortcutInfo.Builder setChooserExtras(android.os.PersistableBundle);
method public android.content.pm.ShortcutInfo.Builder setDisabledMessage(java.lang.CharSequence);
method public android.content.pm.ShortcutInfo.Builder setExtras(android.os.PersistableBundle);
method public android.content.pm.ShortcutInfo.Builder setIcon(android.graphics.drawable.Icon);
@@ -13208,6 +13229,7 @@
method public static android.graphics.ColorSpace.Adaptation valueOf(java.lang.String);
method public static final android.graphics.ColorSpace.Adaptation[] values();
enum_constant public static final android.graphics.ColorSpace.Adaptation BRADFORD;
+ enum_constant public static final android.graphics.ColorSpace.Adaptation CIECAT02;
enum_constant public static final android.graphics.ColorSpace.Adaptation VON_KRIES;
}
@@ -14644,6 +14666,8 @@
public class ArcShape extends android.graphics.drawable.shapes.RectShape {
ctor public ArcShape(float, float);
+ method public final float getStartAngle();
+ method public final float getSweepAngle();
}
public class OvalShape extends android.graphics.drawable.shapes.RectShape {
@@ -22301,6 +22325,26 @@
field public static final android.os.Parcelable.Creator<android.media.AudioFocusInfo> CREATOR;
}
+ public final class AudioFocusRequest {
+ method public boolean acceptsDelayedFocusGain();
+ method public android.media.AudioAttributes getAudioAttributes();
+ method public int getFocusGain();
+ method public android.media.AudioManager.OnAudioFocusChangeListener getOnAudioFocusChangeListener();
+ method public android.os.Handler getOnAudioFocusChangeListenerHandler();
+ method public boolean willPauseWhenDucked();
+ }
+
+ public static final class AudioFocusRequest.Builder {
+ ctor public AudioFocusRequest.Builder(int);
+ ctor public AudioFocusRequest.Builder(android.media.AudioFocusRequest);
+ method public android.media.AudioFocusRequest build();
+ method public android.media.AudioFocusRequest.Builder setAcceptsDelayedFocusGain(boolean);
+ method public android.media.AudioFocusRequest.Builder setAudioAttributes(android.media.AudioAttributes);
+ method public android.media.AudioFocusRequest.Builder setFocusGain(int);
+ method public android.media.AudioFocusRequest.Builder setOnAudioFocusChangeListener(android.media.AudioManager.OnAudioFocusChangeListener, android.os.Handler);
+ method public android.media.AudioFocusRequest.Builder setWillPauseWhenDucked(boolean);
+ }
+
public final class AudioFormat implements android.os.Parcelable {
method public int describeContents();
method public int getChannelCount();
@@ -22378,6 +22422,7 @@
public class AudioManager {
method public int abandonAudioFocus(android.media.AudioManager.OnAudioFocusChangeListener);
method public int abandonAudioFocus(android.media.AudioManager.OnAudioFocusChangeListener, android.media.AudioAttributes);
+ method public int abandonAudioFocusRequest(android.media.AudioFocusRequest);
method public void adjustStreamVolume(int, int, int);
method public void adjustSuggestedStreamVolume(int, int, int);
method public void adjustVolume(int, int);
@@ -22416,6 +22461,7 @@
method public deprecated void registerRemoteControlClient(android.media.RemoteControlClient);
method public deprecated boolean registerRemoteController(android.media.RemoteController);
method public int requestAudioFocus(android.media.AudioManager.OnAudioFocusChangeListener, int, int);
+ method public int requestAudioFocus(android.media.AudioFocusRequest);
method public int requestAudioFocus(android.media.AudioManager.OnAudioFocusChangeListener, android.media.AudioAttributes, int, int) throws java.lang.IllegalArgumentException;
method public int requestAudioFocus(android.media.AudioManager.OnAudioFocusChangeListener, android.media.AudioAttributes, int, int, android.media.audiopolicy.AudioPolicy) throws java.lang.IllegalArgumentException;
method public deprecated void setBluetoothA2dpOn(boolean);
@@ -22464,6 +22510,8 @@
field public static final int AUDIOFOCUS_LOSS = -1; // 0xffffffff
field public static final int AUDIOFOCUS_LOSS_TRANSIENT = -2; // 0xfffffffe
field public static final int AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK = -3; // 0xfffffffd
+ field public static final int AUDIOFOCUS_NONE = 0; // 0x0
+ field public static final int AUDIOFOCUS_REQUEST_DELAYED = 2; // 0x2
field public static final int AUDIOFOCUS_REQUEST_FAILED = 0; // 0x0
field public static final int AUDIOFOCUS_REQUEST_GRANTED = 1; // 0x1
field public static final int AUDIO_SESSION_ID_GENERATE = 0; // 0x0
@@ -22681,13 +22729,14 @@
field public long nanoTime;
}
- public class AudioTrack implements android.media.AudioRouting {
+ public class AudioTrack implements android.media.AudioRouting android.media.VolumeAutomation {
ctor public deprecated AudioTrack(int, int, int, int, int, int) throws java.lang.IllegalArgumentException;
ctor public deprecated AudioTrack(int, int, int, int, int, int, int) throws java.lang.IllegalArgumentException;
ctor public AudioTrack(android.media.AudioAttributes, android.media.AudioFormat, int, int, int) throws java.lang.IllegalArgumentException;
method public void addOnRoutingChangedListener(android.media.AudioRouting.OnRoutingChangedListener, android.os.Handler);
method public deprecated void addOnRoutingChangedListener(android.media.AudioTrack.OnRoutingChangedListener, android.os.Handler);
method public int attachAuxEffect(int);
+ method public android.media.VolumeShaper createVolumeShaper(android.media.VolumeShaper.Configuration);
method public void flush();
method public int getAudioFormat();
method public int getAudioSessionId();
@@ -23155,8 +23204,42 @@
field public static final int STOP_VIDEO_RECORDING = 3; // 0x3
}
+ public final class MediaCas {
+ ctor public MediaCas(int) throws android.media.UnsupportedCasException;
+ method public void closeSession(byte[]);
+ method public static android.media.MediaCas.PluginDescriptor[] enumeratePlugins();
+ method public static boolean isSystemIdSupported(int);
+ method public byte[] openSession(int);
+ method public byte[] openSession(int, int);
+ method public void processEcm(byte[], byte[], int, int);
+ method public void processEcm(byte[], byte[]);
+ method public void processEmm(byte[], int, int);
+ method public void processEmm(byte[]);
+ method public void provision(java.lang.String);
+ method public void refreshEntitlements(int, byte[]);
+ method public void release();
+ method public void sendEvent(int, int, byte[]);
+ method public void setEventListener(android.media.MediaCas.EventListener, android.os.Handler);
+ method public void setPrivateData(byte[]);
+ method public void setSessionPrivateData(byte[], byte[]);
+ }
+
+ public static abstract interface MediaCas.EventListener {
+ method public abstract void onEvent(android.media.MediaCas, int, int, byte[]);
+ }
+
+ public static class MediaCas.PluginDescriptor {
+ method public java.lang.String getName();
+ method public int getSystemId();
+ }
+
+ public class MediaCasException extends java.lang.Exception {
+ ctor public MediaCasException(java.lang.String);
+ }
+
public final class MediaCodec {
method public void configure(android.media.MediaFormat, android.view.Surface, android.media.MediaCrypto, int);
+ method public void configure(android.media.MediaFormat, android.view.Surface, int, android.media.MediaDescrambler);
method public static android.media.MediaCodec createByCodecName(java.lang.String) throws java.io.IOException;
method public static android.media.MediaCodec createDecoderByType(java.lang.String) throws java.io.IOException;
method public static android.media.MediaCodec createEncoderByType(java.lang.String) throws java.io.IOException;
@@ -23196,6 +23279,7 @@
field public static final int BUFFER_FLAG_CODEC_CONFIG = 2; // 0x2
field public static final int BUFFER_FLAG_END_OF_STREAM = 4; // 0x4
field public static final int BUFFER_FLAG_KEY_FRAME = 1; // 0x1
+ field public static final int BUFFER_FLAG_PARTIAL_FRAME = 8; // 0x8
field public static final deprecated int BUFFER_FLAG_SYNC_FRAME = 1; // 0x1
field public static final int CONFIGURE_FLAG_ENCODE = 1; // 0x1
field public static final int CRYPTO_MODE_AES_CBC = 2; // 0x2
@@ -23352,6 +23436,7 @@
field public static final deprecated int COLOR_TI_FormatYUV420PackedSemiPlanar = 2130706688; // 0x7f000100
field public static final java.lang.String FEATURE_AdaptivePlayback = "adaptive-playback";
field public static final java.lang.String FEATURE_IntraRefresh = "intra-refresh";
+ field public static final java.lang.String FEATURE_PartialFrame = "partial-frame";
field public static final java.lang.String FEATURE_SecurePlayback = "secure-playback";
field public static final java.lang.String FEATURE_TunneledPlayback = "tunneled-playback";
field public int[] colorFormats;
@@ -23576,6 +23661,14 @@
method public abstract int readAt(long, byte[], int, int) throws java.io.IOException;
}
+ public final class MediaDescrambler {
+ ctor public MediaDescrambler(int) throws android.media.UnsupportedCasException;
+ method public final int descramble(java.nio.ByteBuffer, int, java.nio.ByteBuffer, int, android.media.MediaCodec.CryptoInfo);
+ method public final void release();
+ method public final boolean requiresSecureDecoderComponent(java.lang.String);
+ method public final void setMediaCasSession(byte[]);
+ }
+
public class MediaDescription implements android.os.Parcelable {
method public int describeContents();
method public java.lang.CharSequence getDescription();
@@ -23732,8 +23825,10 @@
method public final void setDataSource(android.content.res.AssetFileDescriptor) throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException;
method public final void setDataSource(java.io.FileDescriptor) throws java.io.IOException;
method public final void setDataSource(java.io.FileDescriptor, long, long) throws java.io.IOException;
+ method public final void setMediaCas(android.media.MediaCas);
method public void unselectTrack(int);
field public static final int SAMPLE_FLAG_ENCRYPTED = 2; // 0x2
+ field public static final int SAMPLE_FLAG_PARTIAL_FRAME = 4; // 0x4
field public static final int SAMPLE_FLAG_SYNC = 1; // 0x1
field public static final int SEEK_TO_CLOSEST_SYNC = 2; // 0x2
field public static final int SEEK_TO_NEXT_SYNC = 1; // 0x1
@@ -23799,6 +23894,7 @@
field public static final java.lang.String KEY_IS_FORCED_SUBTITLE = "is-forced-subtitle";
field public static final java.lang.String KEY_I_FRAME_INTERVAL = "i-frame-interval";
field public static final java.lang.String KEY_LANGUAGE = "language";
+ field public static final java.lang.String KEY_LATENCY = "latency";
field public static final java.lang.String KEY_LEVEL = "level";
field public static final java.lang.String KEY_MAX_HEIGHT = "max-height";
field public static final java.lang.String KEY_MAX_INPUT_SIZE = "max-input-size";
@@ -23830,6 +23926,7 @@
field public static final java.lang.String MIMETYPE_AUDIO_OPUS = "audio/opus";
field public static final java.lang.String MIMETYPE_AUDIO_QCELP = "audio/qcelp";
field public static final java.lang.String MIMETYPE_AUDIO_RAW = "audio/raw";
+ field public static final java.lang.String MIMETYPE_AUDIO_SCRAMBLED = "audio/scrambled";
field public static final java.lang.String MIMETYPE_AUDIO_VORBIS = "audio/vorbis";
field public static final java.lang.String MIMETYPE_TEXT_CEA_608 = "text/cea-608";
field public static final java.lang.String MIMETYPE_TEXT_VTT = "text/vtt";
@@ -23840,6 +23937,7 @@
field public static final java.lang.String MIMETYPE_VIDEO_MPEG2 = "video/mpeg2";
field public static final java.lang.String MIMETYPE_VIDEO_MPEG4 = "video/mp4v-es";
field public static final java.lang.String MIMETYPE_VIDEO_RAW = "video/raw";
+ field public static final java.lang.String MIMETYPE_VIDEO_SCRAMBLED = "video/scrambled";
field public static final java.lang.String MIMETYPE_VIDEO_VP8 = "video/x-vnd.on2.vp8";
field public static final java.lang.String MIMETYPE_VIDEO_VP9 = "video/x-vnd.on2.vp9";
}
@@ -23980,7 +24078,7 @@
field public static final int MUXER_OUTPUT_WEBM = 1; // 0x1
}
- public class MediaPlayer {
+ public class MediaPlayer implements android.media.VolumeAutomation {
ctor public MediaPlayer();
method public void addTimedTextSource(java.lang.String, java.lang.String) throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException;
method public void addTimedTextSource(android.content.Context, android.net.Uri, java.lang.String) throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException;
@@ -23992,6 +24090,7 @@
method public static android.media.MediaPlayer create(android.content.Context, android.net.Uri, android.view.SurfaceHolder, android.media.AudioAttributes, int);
method public static android.media.MediaPlayer create(android.content.Context, int);
method public static android.media.MediaPlayer create(android.content.Context, int, android.media.AudioAttributes, int);
+ method public android.media.VolumeShaper createVolumeShaper(android.media.VolumeShaper.Configuration);
method public void deselectTrack(int) throws java.lang.IllegalStateException;
method public int getAudioSessionId();
method public android.media.BufferingParams getBufferingParams();
@@ -24822,10 +24921,18 @@
field public static final int TONE_SUP_RINGTONE = 23; // 0x17
}
+ public final class UnsupportedCasException extends android.media.MediaCasException {
+ ctor public UnsupportedCasException(java.lang.String);
+ }
+
public final class UnsupportedSchemeException extends android.media.MediaDrmException {
ctor public UnsupportedSchemeException(java.lang.String);
}
+ public abstract interface VolumeAutomation {
+ method public abstract android.media.VolumeShaper createVolumeShaper(android.media.VolumeShaper.Configuration);
+ }
+
public abstract class VolumeProvider {
ctor public VolumeProvider(int, int, int);
method public final int getCurrentVolume();
@@ -24839,6 +24946,53 @@
field public static final int VOLUME_CONTROL_RELATIVE = 1; // 0x1
}
+ public final class VolumeShaper implements java.lang.AutoCloseable {
+ method public void apply(android.media.VolumeShaper.Operation);
+ method public void close();
+ method public float getVolume();
+ method public void replace(android.media.VolumeShaper.Configuration, android.media.VolumeShaper.Operation, boolean);
+ }
+
+ public static final class VolumeShaper.Configuration implements android.os.Parcelable {
+ method public int describeContents();
+ method public double getDurationMs();
+ method public int getInterpolatorType();
+ method public static int getMaximumCurvePoints();
+ method public float[] getTimes();
+ method public float[] getVolumes();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.media.VolumeShaper.Configuration> CREATOR;
+ field public static final android.media.VolumeShaper.Configuration CUBIC_RAMP;
+ field public static final int INTERPOLATOR_TYPE_CUBIC = 2; // 0x2
+ field public static final int INTERPOLATOR_TYPE_CUBIC_MONOTONIC = 3; // 0x3
+ field public static final int INTERPOLATOR_TYPE_LINEAR = 1; // 0x1
+ field public static final int INTERPOLATOR_TYPE_STEP = 0; // 0x0
+ field public static final android.media.VolumeShaper.Configuration LINEAR_RAMP;
+ field public static final android.media.VolumeShaper.Configuration SCURVE_RAMP;
+ field public static final android.media.VolumeShaper.Configuration SINE_RAMP;
+ }
+
+ public static final class VolumeShaper.Configuration.Builder {
+ ctor public VolumeShaper.Configuration.Builder();
+ ctor public VolumeShaper.Configuration.Builder(android.media.VolumeShaper.Configuration);
+ method public android.media.VolumeShaper.Configuration build();
+ method public android.media.VolumeShaper.Configuration.Builder invertVolumes();
+ method public android.media.VolumeShaper.Configuration.Builder reflectTimes();
+ method public android.media.VolumeShaper.Configuration.Builder scaleToEndVolume(float);
+ method public android.media.VolumeShaper.Configuration.Builder scaleToStartVolume(float);
+ method public android.media.VolumeShaper.Configuration.Builder setCurve(float[], float[]);
+ method public android.media.VolumeShaper.Configuration.Builder setDurationMs(double);
+ method public android.media.VolumeShaper.Configuration.Builder setInterpolatorType(int);
+ }
+
+ public static final class VolumeShaper.Operation implements android.os.Parcelable {
+ method public int describeContents();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.media.VolumeShaper.Operation> CREATOR;
+ field public static final android.media.VolumeShaper.Operation PLAY;
+ field public static final android.media.VolumeShaper.Operation REVERSE;
+ }
+
}
package android.media.audiofx {
@@ -25815,17 +25969,86 @@
method public static final android.net.Uri buildProgramsUriForChannel(long, long, long);
method public static final android.net.Uri buildProgramsUriForChannel(android.net.Uri, long, long);
method public static final android.net.Uri buildRecordedProgramUri(long);
+ method public static final android.net.Uri buildWatchNextProgramUri(long);
method public static final boolean isChannelUri(android.net.Uri);
method public static final boolean isChannelUriForPassthroughInput(android.net.Uri);
method public static final boolean isChannelUriForTunerInput(android.net.Uri);
method public static final boolean isProgramUri(android.net.Uri);
+ field public static final java.lang.String ACTION_MAKE_CHANNEL_BROWSABLE = "android.media.tv.action.MAKE_CHANNEL_BROWSABLE";
+ field public static final java.lang.String ACTION_PREVIEW_PROGRAM_ADDED_TO_WATCH_NEXT = "android.media.tv.action.PREVIEW_PROGRAM_ADDED_TO_WATCH_NEXT";
+ field public static final java.lang.String ACTION_PREVIEW_PROGRAM_BROWSABLE_DISABLED = "android.media.tv.action.PREVIEW_PROGRAM_BROWSABLE_DISABLED";
+ field public static final java.lang.String ACTION_WATCH_NEXT_PROGRAM_BROWSABLE_DISABLED = "android.media.tv.action.WATCH_NEXT_PROGRAM_BROWSABLE_DISABLED";
field public static final java.lang.String AUTHORITY = "android.media.tv";
+ field public static final java.lang.String EXTRA_CHANNEL_ID = "android.media.tv.extra.CHANNEL_ID";
+ field public static final java.lang.String EXTRA_COLUMN_NAME = "android.media.tv.extra.COLUMN_NAME";
+ field public static final java.lang.String EXTRA_DATA_TYPE = "android.media.tv.extra.DATA_TYPE";
+ field public static final java.lang.String EXTRA_DEFAULT_VALUE = "android.media.tv.extra.DEFAULT_VALUE";
+ field public static final java.lang.String EXTRA_EXISTING_COLUMN_NAMES = "android.media.tv.extra.EXISTING_COLUMN_NAMES";
+ field public static final java.lang.String EXTRA_PACKAGE_NAME = "android.media.tv.extra.PACKAGE_NAME";
+ field public static final java.lang.String EXTRA_PREVIEW_PROGRAM_ID = "android.media.tv.extra.PREVIEW_PROGRAM_ID";
+ field public static final java.lang.String EXTRA_WATCH_NEXT_PROGRAM_ID = "android.media.tv.extra.WATCH_NEXT_PROGRAM_ID";
+ field public static final java.lang.String METHOD_ADD_COLUMN = "add_column";
+ field public static final java.lang.String METHOD_GET_COLUMNS = "get_columns";
+ }
+
+ public static abstract interface TvContract.BasePreviewProgramColumns implements android.media.tv.TvContract.BaseProgramColumns {
+ field public static final java.lang.String ASPECT_RATIO_16_9 = "ASPECT_RATIO_16_9";
+ field public static final java.lang.String ASPECT_RATIO_1_1 = "ASPECT_RATIO_1_1";
+ field public static final java.lang.String ASPECT_RATIO_2_3 = "ASPECT_RATIO_2_3";
+ field public static final java.lang.String ASPECT_RATIO_3_2 = "ASPECT_RATIO_3_2";
+ field public static final java.lang.String AVAILABILITY_AVAILABLE = "AVAILABILITY_AVAILABLE";
+ field public static final java.lang.String AVAILABILITY_FREE_WITH_SUBSCRIPTION = "AVAILABILITY_FREE_WITH_SUBSCRIPTION";
+ field public static final java.lang.String AVAILABILITY_PAID_CONTENT = "AVAILABILITY_PAID_CONTENT";
+ field public static final java.lang.String COLUMN_APP_LINK_INTENT_URI = "app_link_intent_uri";
+ field public static final java.lang.String COLUMN_AUTHOR = "author";
+ field public static final java.lang.String COLUMN_AVAILABILITY = "availability";
+ field public static final java.lang.String COLUMN_BROWSABLE = "browsable";
+ field public static final java.lang.String COLUMN_CONTENT_ID = "content_id";
+ field public static final java.lang.String COLUMN_DURATION_MILLIS = "duration_millis";
+ field public static final java.lang.String COLUMN_INTERACTION_COUNT = "interaction_count";
+ field public static final java.lang.String COLUMN_INTERACTION_TYPE = "interaction_type";
+ field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_ID = "internal_provider_id";
+ field public static final java.lang.String COLUMN_ITEM_COUNT = "item_count";
+ field public static final java.lang.String COLUMN_LAST_PLAYBACK_POSITION_MILLIS = "last_playback_position_millis";
+ field public static final java.lang.String COLUMN_LIVE = "live";
+ field public static final java.lang.String COLUMN_LOGO_URI = "logo_uri";
+ field public static final java.lang.String COLUMN_OFFER_PRICE = "offer_price";
+ field public static final java.lang.String COLUMN_POSTER_ART_ASPECT_RATIO = "poster_art_aspect_ratio";
+ field public static final java.lang.String COLUMN_PREVIEW_VIDEO_URI = "preview_video_uri";
+ field public static final java.lang.String COLUMN_RELEASE_DATE = "release_date";
+ field public static final java.lang.String COLUMN_REVIEW_RATING = "review_rating";
+ field public static final java.lang.String COLUMN_REVIEW_RATING_STYLE = "review_rating_style";
+ field public static final java.lang.String COLUMN_STARTING_PRICE = "starting_price";
+ field public static final java.lang.String COLUMN_THUMBNAIL_ASPECT_RATIO = "poster_thumbnail_aspect_ratio";
+ field public static final java.lang.String COLUMN_TRANSIENT = "transient";
+ field public static final java.lang.String COLUMN_TYPE = "type";
+ field public static final java.lang.String INTERACTION_TYPE_FANS = "INTERACTION_TYPE_FANS";
+ field public static final java.lang.String INTERACTION_TYPE_FOLLOWERS = "INTERACTION_TYPE_FOLLOWERS";
+ field public static final java.lang.String INTERACTION_TYPE_LIKES = "INTERACTION_TYPE_LIKES";
+ field public static final java.lang.String INTERACTION_TYPE_LISTENS = "INTERACTION_TYPE_LISTENS";
+ field public static final java.lang.String INTERACTION_TYPE_THUMBS = "INTERACTION_TYPE_THUMBS";
+ field public static final java.lang.String INTERACTION_TYPE_VIEWERS = "INTERACTION_TYPE_VIEWERS";
+ field public static final java.lang.String INTERACTION_TYPE_VIEWS = "INTERACTION_TYPE_VIEWS";
+ field public static final java.lang.String REVIEW_RATING_STYLE_PERCENTAGE = "REVIEW_RATING_STYLE_PERCENTAGE";
+ field public static final java.lang.String REVIEW_RATING_STYLE_STARS = "REVIEW_RATING_STYLE_STARS";
+ field public static final java.lang.String REVIEW_RATING_STYLE_THUMBS_UP_DOWN = "REVIEW_RATING_STYLE_THUMBS_UP_DOWN";
+ field public static final java.lang.String TYPE_ALBUM = "TYPE_ALBUM";
+ field public static final java.lang.String TYPE_ARTIST = "TYPE_ARTIST";
+ field public static final java.lang.String TYPE_CHANNEL = "TYPE_CHANNEL";
+ field public static final java.lang.String TYPE_CLIP = "TYPE_CLIP";
+ field public static final java.lang.String TYPE_EVENT = "TYPE_EVENT";
+ field public static final java.lang.String TYPE_MOVIE = "TYPE_MOVIE";
+ field public static final java.lang.String TYPE_PLAYLIST = "TYPE_PLAYLIST";
+ field public static final java.lang.String TYPE_STATION = "TYPE_STATION";
+ field public static final java.lang.String TYPE_TRACK = "TYPE_TRACK";
+ field public static final java.lang.String TYPE_TV_EPISODE = "TYPE_TV_EPISODE";
+ field public static final java.lang.String TYPE_TV_SEASON = "TYPE_TV_SEASON";
+ field public static final java.lang.String TYPE_TV_SERIES = "TYPE_TV_SERIES";
}
public static abstract interface TvContract.BaseProgramColumns implements android.media.tv.TvContract.BaseTvColumns {
field public static final java.lang.String COLUMN_AUDIO_LANGUAGE = "audio_language";
field public static final java.lang.String COLUMN_CANONICAL_GENRE = "canonical_genre";
- field public static final java.lang.String COLUMN_CHANNEL_ID = "channel_id";
field public static final java.lang.String COLUMN_CONTENT_RATING = "content_rating";
field public static final java.lang.String COLUMN_EPISODE_DISPLAY_NUMBER = "episode_display_number";
field public static final java.lang.String COLUMN_EPISODE_TITLE = "episode_title";
@@ -25934,70 +26157,17 @@
field public static final java.lang.String CONTENT_DIRECTORY = "logo";
}
- public static final class TvContract.PreviewPrograms implements android.media.tv.TvContract.BaseProgramColumns {
- field public static final java.lang.String ASPECT_RATIO_16_9 = "ASPECT_RATIO_16_9";
- field public static final java.lang.String ASPECT_RATIO_1_1 = "ASPECT_RATIO_1_1";
- field public static final java.lang.String ASPECT_RATIO_2_3 = "ASPECT_RATIO_2_3";
- field public static final java.lang.String ASPECT_RATIO_3_2 = "ASPECT_RATIO_3_2";
- field public static final java.lang.String AVAILABILITY_AVAILABLE = "AVAILABILITY_AVAILABLE";
- field public static final java.lang.String AVAILABILITY_FREE_WITH_SUBSCRIPTION = "AVAILABILITY_FREE_WITH_SUBSCRIPTION";
- field public static final java.lang.String AVAILABILITY_PAID_CONTENT = "AVAILABILITY_PAID_CONTENT";
- field public static final java.lang.String COLUMN_APP_LINK_INTENT_URI = "app_link_intent_uri";
- field public static final java.lang.String COLUMN_AUTHOR = "author";
- field public static final java.lang.String COLUMN_AVAILABILITY = "availability";
- field public static final java.lang.String COLUMN_BROWSABLE = "browsable";
- field public static final java.lang.String COLUMN_DURATION_MILLIS = "duration_millis";
- field public static final java.lang.String COLUMN_INTERACTION_COUNT = "interaction_count";
- field public static final java.lang.String COLUMN_INTERACTION_TYPE = "interaction_type";
- field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_ID = "internal_provider_id";
- field public static final java.lang.String COLUMN_ITEM_COUNT = "item_count";
- field public static final java.lang.String COLUMN_LAST_PLAYBACK_POSITION_MILLIS = "last_playback_position_millis";
- field public static final java.lang.String COLUMN_LIVE = "live";
- field public static final java.lang.String COLUMN_LOGO_URI = "logo_uri";
- field public static final java.lang.String COLUMN_OFFER_PRICE = "offer_price";
- field public static final java.lang.String COLUMN_POSTER_ART_ASPECT_RATIO = "poster_art_aspect_ratio";
- field public static final java.lang.String COLUMN_PREVIEW_VIDEO_URI = "preview_video_uri";
- field public static final java.lang.String COLUMN_RELEASE_DATE = "release_date";
- field public static final java.lang.String COLUMN_REVIEW_RATING = "review_rating";
- field public static final java.lang.String COLUMN_REVIEW_RATING_STYLE = "review_rating_style";
- field public static final java.lang.String COLUMN_STARTING_PRICE = "starting_price";
- field public static final java.lang.String COLUMN_THUMBNAIL_ASPECT_RATIO = "poster_thumbnail_aspect_ratio";
- field public static final java.lang.String COLUMN_TRANSIENT = "transient";
- field public static final java.lang.String COLUMN_TYPE = "type";
- field public static final java.lang.String COLUMN_WATCH_NEXT_TYPE = "watch_next_type";
+ public static final class TvContract.PreviewPrograms implements android.media.tv.TvContract.BasePreviewProgramColumns {
+ field public static final java.lang.String COLUMN_CHANNEL_ID = "channel_id";
field public static final java.lang.String COLUMN_WEIGHT = "weight";
field public static final java.lang.String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/preview_program";
field public static final java.lang.String CONTENT_TYPE = "vnd.android.cursor.dir/preview_program";
field public static final android.net.Uri CONTENT_URI;
- field public static final java.lang.String INTERACTION_TYPE_FANS = "INTERACTION_TYPE_FANS";
- field public static final java.lang.String INTERACTION_TYPE_FOLLOWERS = "INTERACTION_TYPE_FOLLOWERS";
- field public static final java.lang.String INTERACTION_TYPE_LIKES = "INTERACTION_TYPE_LIKES";
- field public static final java.lang.String INTERACTION_TYPE_LISTENS = "INTERACTION_TYPE_LISTENS";
- field public static final java.lang.String INTERACTION_TYPE_THUMBS = "INTERACTION_TYPE_THUMBS";
- field public static final java.lang.String INTERACTION_TYPE_VIEWERS = "INTERACTION_TYPE_VIEWERS";
- field public static final java.lang.String INTERACTION_TYPE_VIEWS = "INTERACTION_TYPE_VIEWS";
- field public static final java.lang.String REVIEW_RATING_STYLE_PERCENTAGE = "REVIEW_RATING_STYLE_PERCENTAGE";
- field public static final java.lang.String REVIEW_RATING_STYLE_STARS = "REVIEW_RATING_STYLE_STARS";
- field public static final java.lang.String REVIEW_RATING_STYLE_THUMBS_UP_DOWN = "REVIEW_RATING_STYLE_THUMBS_UP_DOWN";
- field public static final java.lang.String TYPE_ALBUM = "TYPE_ALBUM";
- field public static final java.lang.String TYPE_ARTIST = "TYPE_ARTIST";
- field public static final java.lang.String TYPE_CHANNEL = "TYPE_CHANNEL";
- field public static final java.lang.String TYPE_CLIP = "TYPE_CLIP";
- field public static final java.lang.String TYPE_EVENT = "TYPE_EVENT";
- field public static final java.lang.String TYPE_MOVIE = "TYPE_MOVIE";
- field public static final java.lang.String TYPE_PLAYLIST = "TYPE_PLAYLIST";
- field public static final java.lang.String TYPE_STATION = "TYPE_STATION";
- field public static final java.lang.String TYPE_TRACK = "TYPE_TRACK";
- field public static final java.lang.String TYPE_TV_EPISODE = "TYPE_TV_EPISODE";
- field public static final java.lang.String TYPE_TV_SEASON = "TYPE_TV_SEASON";
- field public static final java.lang.String TYPE_TV_SERIES = "TYPE_TV_SERIES";
- field public static final java.lang.String WATCH_NEXT_TYPE_CONTINUE = "WATCH_NEXT_TYPE_CONTINUE";
- field public static final java.lang.String WATCH_NEXT_TYPE_NEW = "WATCH_NEXT_TYPE_NEW";
- field public static final java.lang.String WATCH_NEXT_TYPE_NEXT = "WATCH_NEXT_TYPE_NEXT";
}
public static final class TvContract.Programs implements android.media.tv.TvContract.BaseProgramColumns {
field public static final java.lang.String COLUMN_BROADCAST_GENRE = "broadcast_genre";
+ field public static final java.lang.String COLUMN_CHANNEL_ID = "channel_id";
field public static final java.lang.String COLUMN_END_TIME_UTC_MILLIS = "end_time_utc_millis";
field public static final deprecated java.lang.String COLUMN_EPISODE_NUMBER = "episode_number";
field public static final java.lang.String COLUMN_RECORDING_PROHIBITED = "recording_prohibited";
@@ -26033,6 +26203,7 @@
public static final class TvContract.RecordedPrograms implements android.media.tv.TvContract.BaseProgramColumns {
field public static final java.lang.String COLUMN_BROADCAST_GENRE = "broadcast_genre";
+ field public static final java.lang.String COLUMN_CHANNEL_ID = "channel_id";
field public static final java.lang.String COLUMN_END_TIME_UTC_MILLIS = "end_time_utc_millis";
field public static final java.lang.String COLUMN_INPUT_ID = "input_id";
field public static final java.lang.String COLUMN_RECORDING_DATA_BYTES = "recording_data_bytes";
@@ -26045,6 +26216,19 @@
field public static final android.net.Uri CONTENT_URI;
}
+ public static final class TvContract.WatchNextPrograms implements android.media.tv.TvContract.BasePreviewProgramColumns {
+ ctor public TvContract.WatchNextPrograms();
+ field public static final java.lang.String COLUMN_LAST_ENGAGEMENT_TIME_UTC_MILLIS = "last_engagement_time_utc_millis";
+ field public static final java.lang.String COLUMN_WATCH_NEXT_TYPE = "watch_next_type";
+ field public static final java.lang.String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/watch_next_program";
+ field public static final java.lang.String CONTENT_TYPE = "vnd.android.cursor.dir/watch_next_program";
+ field public static final android.net.Uri CONTENT_URI;
+ field public static final java.lang.String WATCH_NEXT_TYPE_CONTINUE = "WATCH_NEXT_TYPE_CONTINUE";
+ field public static final java.lang.String WATCH_NEXT_TYPE_NEW = "WATCH_NEXT_TYPE_NEW";
+ field public static final java.lang.String WATCH_NEXT_TYPE_NEXT = "WATCH_NEXT_TYPE_NEXT";
+ field public static final java.lang.String WATCH_NEXT_TYPE_WATCHLIST = "WATCH_NEXT_TYPE_WATCHLIST";
+ }
+
public static final class TvContract.WatchedPrograms implements android.media.tv.TvContract.BaseTvColumns {
field public static final java.lang.String COLUMN_CHANNEL_ID = "channel_id";
field public static final java.lang.String COLUMN_DESCRIPTION = "description";
@@ -26174,15 +26358,10 @@
method public void unregisterCallback(android.media.tv.TvInputManager.TvInputCallback);
method public void updateTvInputInfo(android.media.tv.TvInputInfo);
field public static final java.lang.String ACTION_BLOCKED_RATINGS_CHANGED = "android.media.tv.action.BLOCKED_RATINGS_CHANGED";
- field public static final java.lang.String ACTION_MAKE_CHANNEL_BROWSABLE = "android.media.tv.action.MAKE_CHANNEL_BROWSABLE";
field public static final java.lang.String ACTION_PARENTAL_CONTROLS_ENABLED_CHANGED = "android.media.tv.action.PARENTAL_CONTROLS_ENABLED_CHANGED";
- field public static final java.lang.String ACTION_PROGRAM_BROWSABLE_DISABLED = "android.media.tv.action.PROGRAM_BROWSABLE_DISABLED";
field public static final java.lang.String ACTION_QUERY_CONTENT_RATING_SYSTEMS = "android.media.tv.action.QUERY_CONTENT_RATING_SYSTEMS";
field public static final java.lang.String ACTION_SETUP_INPUTS = "android.media.tv.action.SETUP_INPUTS";
field public static final java.lang.String ACTION_VIEW_RECORDING_SCHEDULES = "android.media.tv.action.VIEW_RECORDING_SCHEDULES";
- field public static final java.lang.String EXTRA_CHANNEL_ID = "android.media.tv.extra.CHANNEL_ID";
- field public static final java.lang.String EXTRA_PACKAGE_NAME = "android.media.tv.extra.PACKAGE_NAME";
- field public static final java.lang.String EXTRA_PROGRAM_ID = "android.media.tv.extra.PROGRAM_ID";
field public static final int INPUT_STATE_CONNECTED = 0; // 0x0
field public static final int INPUT_STATE_CONNECTED_STANDBY = 1; // 0x1
field public static final int INPUT_STATE_DISCONNECTED = 2; // 0x2
@@ -26828,44 +27007,6 @@
method public void onTetheringStarted();
}
- public final class ConnectivityMetricsEvent implements android.os.Parcelable {
- ctor public ConnectivityMetricsEvent(long, int, int, android.os.Parcelable);
- method public int describeContents();
- method public void writeToParcel(android.os.Parcel, int);
- field public static final android.os.Parcelable.Creator<android.net.ConnectivityMetricsEvent> CREATOR;
- field public final int componentTag;
- field public final android.os.Parcelable data;
- field public final int eventTag;
- field public final long timestamp;
- }
-
- public static final class ConnectivityMetricsEvent.Reference implements android.os.Parcelable {
- ctor public ConnectivityMetricsEvent.Reference(long);
- method public int describeContents();
- method public long getValue();
- method public void readFromParcel(android.os.Parcel);
- method public void setValue(long);
- method public void writeToParcel(android.os.Parcel, int);
- field public static final android.os.Parcelable.Creator<android.net.ConnectivityMetricsEvent.Reference> CREATOR;
- }
-
- public class ConnectivityMetricsLogger {
- ctor public ConnectivityMetricsLogger();
- method public android.net.ConnectivityMetricsEvent[] getEvents(android.net.ConnectivityMetricsEvent.Reference);
- method public void logEvent(long, int, int, android.os.Parcelable);
- method public boolean register(android.app.PendingIntent);
- method public boolean unregister(android.app.PendingIntent);
- field public static final int COMPONENT_TAG_BLUETOOTH = 1; // 0x1
- field public static final int COMPONENT_TAG_CONNECTIVITY = 0; // 0x0
- field public static final int COMPONENT_TAG_TELECOM = 3; // 0x3
- field public static final int COMPONENT_TAG_TELEPHONY = 4; // 0x4
- field public static final int COMPONENT_TAG_WIFI = 2; // 0x2
- field public static final java.lang.String CONNECTIVITY_METRICS_LOGGER_SERVICE = "connectivity_metrics_logger";
- field public static final java.lang.String DATA_KEY_EVENTS_COUNT = "count";
- field public static final int NUMBER_OF_COMPONENTS = 5; // 0x5
- field public static final int TAG_SKIPPED_EVENTS = -1; // 0xffffffff
- }
-
public class Credentials {
ctor public Credentials(int, int, int);
method public int getGid();
@@ -26896,6 +27037,73 @@
field public static final android.os.Parcelable.Creator<android.net.IpPrefix> CREATOR;
}
+ public final class IpSecAlgorithm implements android.os.Parcelable {
+ ctor public IpSecAlgorithm(java.lang.String, byte[]);
+ ctor public IpSecAlgorithm(java.lang.String, byte[], int);
+ method public int describeContents();
+ method public byte[] getKey();
+ method public java.lang.String getName();
+ method public int getTruncationLengthBits();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final java.lang.String ALGO_AUTH_HMAC_MD5 = "hmac(md5)";
+ field public static final java.lang.String ALGO_AUTH_HMAC_SHA1 = "hmac(sha1)";
+ field public static final java.lang.String ALGO_AUTH_HMAC_SHA256 = "hmac(sha256)";
+ field public static final java.lang.String ALGO_AUTH_HMAC_SHA384 = "hmac(sha384)";
+ field public static final java.lang.String ALGO_AUTH_HMAC_SHA512 = "hmac(sha512)";
+ field public static final java.lang.String ALGO_CRYPT_AES_CBC = "cbc(aes)";
+ field public static final android.os.Parcelable.Creator<android.net.IpSecAlgorithm> CREATOR;
+ }
+
+ public final class IpSecManager {
+ method public void applyTransportModeTransform(java.net.Socket, android.net.IpSecTransform) throws java.io.IOException;
+ method public void applyTransportModeTransform(java.net.DatagramSocket, android.net.IpSecTransform) throws java.io.IOException;
+ method public void applyTunnelModeTransform(android.net.Network, android.net.IpSecTransform);
+ method public android.net.IpSecManager.UdpEncapsulationSocket openUdpEncapsulationSocket(int) throws java.io.IOException, android.net.IpSecManager.ResourceUnavailableException;
+ method public android.net.IpSecManager.UdpEncapsulationSocket openUdpEncapsulationSocket() throws java.io.IOException, android.net.IpSecManager.ResourceUnavailableException;
+ method public void removeTransportModeTransform(java.net.Socket, android.net.IpSecTransform);
+ method public void removeTransportModeTransform(java.net.DatagramSocket, android.net.IpSecTransform);
+ method public void removeTunnelModeTransform(android.net.Network, android.net.IpSecTransform);
+ method public android.net.IpSecManager.SecurityParameterIndex reserveSecurityParameterIndex(java.net.InetAddress, int) throws android.net.IpSecManager.ResourceUnavailableException, android.net.IpSecManager.SpiUnavailableException;
+ field public static final int INVALID_SECURITY_PARAMETER_INDEX = 0; // 0x0
+ }
+
+ public static final class IpSecManager.ResourceUnavailableException extends android.util.AndroidException {
+ }
+
+ public static final class IpSecManager.SecurityParameterIndex implements java.lang.AutoCloseable {
+ method public void close();
+ method public int getSpi();
+ }
+
+ public static final class IpSecManager.SpiUnavailableException extends android.util.AndroidException {
+ method public int getSpi();
+ }
+
+ public static final class IpSecManager.UdpEncapsulationSocket implements java.lang.AutoCloseable {
+ method public void close();
+ method public int getPort();
+ method public java.io.FileDescriptor getSocket();
+ }
+
+ public final class IpSecTransform implements java.lang.AutoCloseable {
+ method public void close();
+ field public static final int DIRECTION_IN = 0; // 0x0
+ field public static final int DIRECTION_OUT = 1; // 0x1
+ }
+
+ public static class IpSecTransform.Builder {
+ ctor public IpSecTransform.Builder(android.content.Context);
+ method public android.net.IpSecTransform buildTransportModeTransform(java.net.InetAddress) throws java.io.IOException, android.net.IpSecManager.ResourceUnavailableException, android.net.IpSecManager.SpiUnavailableException;
+ method public android.net.IpSecTransform buildTunnelModeTransform(java.net.InetAddress, java.net.InetAddress);
+ method public android.net.IpSecTransform.Builder setAuthentication(int, android.net.IpSecAlgorithm);
+ method public android.net.IpSecTransform.Builder setEncryption(int, android.net.IpSecAlgorithm);
+ method public android.net.IpSecTransform.Builder setIpv4Encapsulation(android.net.IpSecManager.UdpEncapsulationSocket, int);
+ method public android.net.IpSecTransform.Builder setNattKeepalive(int);
+ method public android.net.IpSecTransform.Builder setSpi(int, int);
+ method public android.net.IpSecTransform.Builder setSpi(int, android.net.IpSecManager.SecurityParameterIndex);
+ method public android.net.IpSecTransform.Builder setUnderlyingNetwork(android.net.Network);
+ }
+
public class LinkAddress implements android.os.Parcelable {
method public int describeContents();
method public java.net.InetAddress getAddress();
@@ -27106,7 +27314,8 @@
}
public abstract class NetworkRecommendationProvider {
- ctor public NetworkRecommendationProvider(android.os.Handler);
+ ctor public deprecated NetworkRecommendationProvider(android.os.Handler);
+ ctor public NetworkRecommendationProvider(android.content.Context, java.util.concurrent.Executor);
method public final android.os.IBinder getBinder();
method public abstract void onRequestRecommendation(android.net.RecommendationRequest, android.net.NetworkRecommendationProvider.ResultCallback);
method public abstract void onRequestScores(android.net.NetworkKey[]);
@@ -27577,175 +27786,6 @@
}
-package android.net.metrics {
-
- public final class ApfProgramEvent implements android.os.Parcelable {
- method public int describeContents();
- method public void writeToParcel(android.os.Parcel, int);
- field public static final android.os.Parcelable.Creator<android.net.metrics.ApfProgramEvent> CREATOR;
- field public static final int FLAG_HAS_IPV4_ADDRESS = 1; // 0x1
- field public static final int FLAG_MULTICAST_FILTER_ON = 0; // 0x0
- field public final int currentRas;
- field public final int filteredRas;
- field public final int flags;
- field public final long lifetime;
- field public final int programLength;
- }
-
- public final class ApfStats implements android.os.Parcelable {
- method public int describeContents();
- method public void writeToParcel(android.os.Parcel, int);
- field public static final android.os.Parcelable.Creator<android.net.metrics.ApfStats> CREATOR;
- field public final int droppedRas;
- field public final long durationMs;
- field public final int matchingRas;
- field public final int maxProgramSize;
- field public final int parseErrors;
- field public final int programUpdates;
- field public final int receivedRas;
- field public final int zeroLifetimeRas;
- }
-
- public final class DefaultNetworkEvent implements android.os.Parcelable {
- method public int describeContents();
- method public static void logEvent(int, int[], int, boolean, boolean);
- method public void writeToParcel(android.os.Parcel, int);
- field public static final android.os.Parcelable.Creator<android.net.metrics.DefaultNetworkEvent> CREATOR;
- field public final int netId;
- field public final boolean prevIPv4;
- field public final boolean prevIPv6;
- field public final int prevNetId;
- field public final int[] transportTypes;
- }
-
- public final class DhcpClientEvent implements android.os.Parcelable {
- method public int describeContents();
- method public static void logStateEvent(java.lang.String, java.lang.String);
- method public void writeToParcel(android.os.Parcel, int);
- field public static final android.os.Parcelable.Creator<android.net.metrics.DhcpClientEvent> CREATOR;
- field public final int durationMs;
- field public final java.lang.String ifName;
- field public final java.lang.String msg;
- }
-
- public final class DhcpErrorEvent implements android.os.Parcelable {
- method public int describeContents();
- method public static int errorCodeWithOption(int, int);
- method public static void logParseError(java.lang.String, int);
- method public static void logReceiveError(java.lang.String);
- method public void writeToParcel(android.os.Parcel, int);
- field public static final int BOOTP_TOO_SHORT;
- field public static final int BUFFER_UNDERFLOW;
- field public static final android.os.Parcelable.Creator<android.net.metrics.DhcpErrorEvent> CREATOR;
- field public static final int DHCP_BAD_MAGIC_COOKIE;
- field public static final int DHCP_ERROR = 4; // 0x4
- field public static final int DHCP_INVALID_OPTION_LENGTH;
- field public static final int DHCP_NO_MSG_TYPE;
- field public static final int DHCP_UNKNOWN_MSG_TYPE;
- field public static final int L2_ERROR = 1; // 0x1
- field public static final int L2_TOO_SHORT;
- field public static final int L2_WRONG_ETH_TYPE;
- field public static final int L3_ERROR = 2; // 0x2
- field public static final int L3_INVALID_IP;
- field public static final int L3_NOT_IPV4;
- field public static final int L3_TOO_SHORT;
- field public static final int L4_ERROR = 3; // 0x3
- field public static final int L4_NOT_UDP;
- field public static final int L4_WRONG_PORT;
- field public static final int MISC_ERROR = 5; // 0x5
- field public static final int RECEIVE_ERROR;
- field public final int errorCode;
- field public final java.lang.String ifName;
- }
-
- public final class DnsEvent implements android.os.Parcelable {
- method public int describeContents();
- method public static void logEvent(int, byte[], byte[], int[]);
- method public void writeToParcel(android.os.Parcel, int);
- field public static final android.os.Parcelable.Creator<android.net.metrics.DnsEvent> CREATOR;
- field public final byte[] eventTypes;
- field public final int[] latenciesMs;
- field public final int netId;
- field public final byte[] returnCodes;
- }
-
- public final class IpManagerEvent implements android.os.Parcelable {
- method public int describeContents();
- method public static void logEvent(int, java.lang.String, long);
- method public void writeToParcel(android.os.Parcel, int);
- field public static final int COMPLETE_LIFECYCLE = 3; // 0x3
- field public static final android.os.Parcelable.Creator<android.net.metrics.IpManagerEvent> CREATOR;
- field public static final int PROVISIONING_FAIL = 2; // 0x2
- field public static final int PROVISIONING_OK = 1; // 0x1
- field public final long durationMs;
- field public final int eventType;
- field public final java.lang.String ifName;
- }
-
- public final class IpReachabilityEvent implements android.os.Parcelable {
- method public int describeContents();
- method public static void logNudFailed(java.lang.String);
- method public static void logProbeEvent(java.lang.String, int);
- method public static void logProvisioningLost(java.lang.String);
- method public void writeToParcel(android.os.Parcel, int);
- field public static final android.os.Parcelable.Creator<android.net.metrics.IpReachabilityEvent> CREATOR;
- field public static final int NUD_FAILED = 512; // 0x200
- field public static final int PROBE = 256; // 0x100
- field public static final int PROVISIONING_LOST = 768; // 0x300
- field public final int eventType;
- field public final java.lang.String ifName;
- }
-
- public final class NetworkEvent implements android.os.Parcelable {
- method public int describeContents();
- method public static void logCaptivePortalFound(int, long);
- method public static void logEvent(int, int);
- method public static void logValidated(int, long);
- method public void writeToParcel(android.os.Parcel, int);
- field public static final android.os.Parcelable.Creator<android.net.metrics.NetworkEvent> CREATOR;
- field public static final int NETWORK_CAPTIVE_PORTAL_FOUND = 4; // 0x4
- field public static final int NETWORK_CONNECTED = 1; // 0x1
- field public static final int NETWORK_DISCONNECTED = 7; // 0x7
- field public static final int NETWORK_LINGER = 5; // 0x5
- field public static final int NETWORK_UNLINGER = 6; // 0x6
- field public static final int NETWORK_VALIDATED = 2; // 0x2
- field public static final int NETWORK_VALIDATION_FAILED = 3; // 0x3
- field public final long durationMs;
- field public final int eventType;
- field public final int netId;
- }
-
- public final class RaEvent implements android.os.Parcelable {
- method public int describeContents();
- method public void writeToParcel(android.os.Parcel, int);
- field public static final android.os.Parcelable.Creator<android.net.metrics.RaEvent> CREATOR;
- field public final long dnsslLifetime;
- field public final long prefixPreferredLifetime;
- field public final long prefixValidLifetime;
- field public final long rdnssLifetime;
- field public final long routeInfoLifetime;
- field public final long routerLifetime;
- }
-
- public final class ValidationProbeEvent implements android.os.Parcelable {
- method public int describeContents();
- method public static void logEvent(int, long, int, int);
- method public void writeToParcel(android.os.Parcel, int);
- field public static final android.os.Parcelable.Creator<android.net.metrics.ValidationProbeEvent> CREATOR;
- field public static final int DNS_FAILURE = 0; // 0x0
- field public static final int DNS_SUCCESS = 1; // 0x1
- field public static final int PROBE_DNS = 0; // 0x0
- field public static final int PROBE_HTTP = 1; // 0x1
- field public static final int PROBE_HTTPS = 2; // 0x2
- field public static final int PROBE_PAC = 3; // 0x3
- field public final long durationMs;
- field public final int netId;
- field public final int probeType;
- field public final int returnCode;
- }
-
-}
-
package android.net.nsd {
public final class NsdManager {
@@ -28804,8 +28844,6 @@
public class DiscoverySession {
method public java.lang.String createNetworkSpecifier(android.net.wifi.aware.PeerHandle, byte[]);
method public void destroy();
- method public static int getMaxSendRetryCount();
- method public void sendMessage(android.net.wifi.aware.PeerHandle, int, byte[], int);
method public void sendMessage(android.net.wifi.aware.PeerHandle, int, byte[]);
}
@@ -32689,7 +32727,7 @@
field public static final int BATTERY_PLUGGED_AC = 1; // 0x1
field public static final int BATTERY_PLUGGED_USB = 2; // 0x2
field public static final int BATTERY_PLUGGED_WIRELESS = 4; // 0x4
- field public static final int BATTERY_PROPERTY_BATTERY_STATUS = 6; // 0x6
+ field public static final int BATTERY_PROPERTY_STATUS = 6; // 0x6
field public static final int BATTERY_PROPERTY_CAPACITY = 4; // 0x4
field public static final int BATTERY_PROPERTY_CHARGE_COUNTER = 1; // 0x1
field public static final int BATTERY_PROPERTY_CURRENT_AVERAGE = 3; // 0x3
@@ -39385,10 +39423,10 @@
public static final class FillResponse.Builder {
ctor public FillResponse.Builder();
method public android.service.autofill.FillResponse.Builder addDataset(android.service.autofill.Dataset);
- method public android.service.autofill.FillResponse.Builder addSavableFields(android.view.autofill.AutoFillId...);
method public android.service.autofill.FillResponse build();
method public android.service.autofill.FillResponse.Builder setAuthentication(android.content.IntentSender, android.widget.RemoteViews);
method public android.service.autofill.FillResponse.Builder setExtras(android.os.Bundle);
+ method public android.service.autofill.FillResponse.Builder setSaveInfo(android.service.autofill.SaveInfo);
}
public final class SaveCallback {
@@ -39396,6 +39434,23 @@
method public void onSuccess();
}
+ public final class SaveInfo implements android.os.Parcelable {
+ method public int describeContents();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.service.autofill.SaveInfo> CREATOR;
+ field public static final int SAVE_DATA_TYPE_ADDRESS = 2; // 0x2
+ field public static final int SAVE_DATA_TYPE_CREDIT_CARD = 3; // 0x3
+ field public static final int SAVE_DATA_TYPE_GENERIC = 0; // 0x0
+ field public static final int SAVE_DATA_TYPE_PASSWORD = 1; // 0x1
+ }
+
+ public static final class SaveInfo.Builder {
+ ctor public SaveInfo.Builder(int);
+ method public android.service.autofill.SaveInfo.Builder addSavableIds(android.view.autofill.AutoFillId...);
+ method public android.service.autofill.SaveInfo build();
+ method public android.service.autofill.SaveInfo.Builder setDescription(java.lang.CharSequence);
+ }
+
}
package android.service.carrier {
@@ -41244,9 +41299,6 @@
field public static final int RTT_MODE_VCO = 3; // 0x3
}
- public static abstract class Call.RttCall.RttAudioMode implements java.lang.annotation.Annotation {
- }
-
public final class CallAudioState implements android.os.Parcelable {
ctor public CallAudioState(boolean, int, int);
method public static java.lang.String audioRouteToString(int);
@@ -42552,7 +42604,9 @@
method public void sendDataMessage(java.lang.String, java.lang.String, short, byte[], android.app.PendingIntent, android.app.PendingIntent);
method public void sendMultimediaMessage(android.content.Context, android.net.Uri, java.lang.String, android.os.Bundle, android.app.PendingIntent);
method public void sendMultipartTextMessage(java.lang.String, java.lang.String, java.util.ArrayList<java.lang.String>, java.util.ArrayList<android.app.PendingIntent>, java.util.ArrayList<android.app.PendingIntent>);
+ method public void sendMultipartTextMessageWithoutPersisting(java.lang.String, java.lang.String, java.util.List<java.lang.String>, java.util.List<android.app.PendingIntent>, java.util.List<android.app.PendingIntent>);
method public void sendTextMessage(java.lang.String, java.lang.String, java.lang.String, android.app.PendingIntent, android.app.PendingIntent);
+ method public void sendTextMessageWithoutPersisting(java.lang.String, java.lang.String, java.lang.String, android.app.PendingIntent, android.app.PendingIntent);
field public static final java.lang.String EXTRA_MMS_DATA = "android.telephony.extra.MMS_DATA";
field public static final java.lang.String EXTRA_MMS_HTTP_STATUS = "android.telephony.extra.MMS_HTTP_STATUS";
field public static final java.lang.String MMS_CONFIG_ALIAS_ENABLED = "aliasEnabled";
@@ -43696,7 +43750,7 @@
package android.test.suitebuilder {
- public class TestMethod {
+ public deprecated class TestMethod {
ctor public TestMethod(java.lang.reflect.Method, java.lang.Class<? extends junit.framework.TestCase>);
ctor public TestMethod(java.lang.String, java.lang.Class<? extends junit.framework.TestCase>);
ctor public TestMethod(junit.framework.TestCase);
@@ -43707,7 +43761,7 @@
method public java.lang.String getName();
}
- public class TestSuiteBuilder {
+ public deprecated class TestSuiteBuilder {
ctor public TestSuiteBuilder(java.lang.Class);
ctor public TestSuiteBuilder(java.lang.String, java.lang.ClassLoader);
method public android.test.suitebuilder.TestSuiteBuilder addRequirements(java.util.List<com.android.internal.util.Predicate<android.test.suitebuilder.TestMethod>>);
@@ -43720,7 +43774,7 @@
method public android.test.suitebuilder.TestSuiteBuilder named(java.lang.String);
}
- public static class TestSuiteBuilder.FailedToCreateTests extends junit.framework.TestCase {
+ public static deprecated class TestSuiteBuilder.FailedToCreateTests extends junit.framework.TestCase {
ctor public TestSuiteBuilder.FailedToCreateTests(java.lang.Exception);
method public void testSuiteConstructionFailed();
}
@@ -45936,30 +45990,51 @@
method public abstract void setValue(T, float);
}
- public final class Half {
+ public final class Half extends java.lang.Number implements java.lang.Comparable {
+ ctor public Half(short);
+ ctor public Half(float);
+ ctor public Half(double);
+ ctor public Half(java.lang.String) throws java.lang.NumberFormatException;
method public static short abs(short);
method public static short ceil(short);
+ method public static int compare(short, short);
+ method public int compareTo(android.util.Half);
method public static short copySign(short, short);
+ method public double doubleValue();
method public static boolean equals(short, short);
+ method public float floatValue();
method public static short floor(short);
method public static int getExponent(short);
method public static int getSign(short);
method public static int getSignificand(short);
method public static boolean greater(short, short);
method public static boolean greaterEquals(short, short);
+ method public static int halfToIntBits(short);
+ method public static int halfToRawIntBits(short);
+ method public static short halfToShortBits(short);
+ method public short halfValue();
+ method public static int hashCode(short);
+ method public static short intBitsToHalf(int);
+ method public int intValue();
method public static boolean isInfinite(short);
+ method public boolean isNaN();
method public static boolean isNaN(short);
method public static boolean isNormalized(short);
method public static boolean less(short, short);
method public static boolean lessEquals(short, short);
+ method public long longValue();
method public static short max(short, short);
method public static short min(short, short);
+ method public static short parseHalf(java.lang.String) throws java.lang.NumberFormatException;
method public static short round(short);
method public static float toFloat(short);
+ method public static short toHalf(float);
method public static java.lang.String toHexString(short);
method public static java.lang.String toString(short);
method public static short trunc(short);
- method public static short valueOf(float);
+ method public static android.util.Half valueOf(short);
+ method public static android.util.Half valueOf(float);
+ method public static android.util.Half valueOf(java.lang.String);
field public static final short EPSILON = 5120; // 0x1400
field public static final short LOWEST_VALUE = -1025; // 0xfffffbff
field public static final int MAX_EXPONENT = 15; // 0xf
@@ -46684,11 +46759,13 @@
field public static final int DRAW_DURATION = 4; // 0x4
field public static final int FIRST_DRAW_FRAME = 9; // 0x9
field public static final int INPUT_HANDLING_DURATION = 1; // 0x1
+ field public static final int INTENDED_VSYNC_TIMESTAMP = 10; // 0xa
field public static final int LAYOUT_MEASURE_DURATION = 3; // 0x3
field public static final int SWAP_BUFFERS_DURATION = 7; // 0x7
field public static final int SYNC_DURATION = 5; // 0x5
field public static final int TOTAL_DURATION = 8; // 0x8
field public static final int UNKNOWN_DELAY_DURATION = 0; // 0x0
+ field public static final int VSYNC_TIMESTAMP = 11; // 0xb
}
public abstract class FrameStats {
@@ -48061,8 +48138,8 @@
method public void drawableHotspotChanged(float, float);
method protected void drawableStateChanged();
method public android.view.View findFocus();
- method public final android.view.View findViewById(int);
- method public final android.view.View findViewWithTag(java.lang.Object);
+ method public final <T extends android.view.View> T findViewById(int);
+ method public final <T extends android.view.View> T findViewWithTag(java.lang.Object);
method public void findViewsWithText(java.util.ArrayList<android.view.View>, java.lang.CharSequence, int);
method protected deprecated boolean fitSystemWindows(android.graphics.Rect);
method public android.view.View focusSearch(int);
@@ -49187,6 +49264,7 @@
method public abstract void setAccessibilityFocused(boolean);
method public abstract void setActivated(boolean);
method public abstract void setAlpha(float);
+ method public abstract void setAutoFillOptions(java.lang.String[]);
method public abstract void setAutoFillType(android.view.autofill.AutoFillType);
method public abstract void setAutoFillValue(android.view.autofill.AutoFillValue);
method public abstract void setCheckable(boolean);
@@ -54733,6 +54811,8 @@
method public int resolveAdjustedSize(int, int);
method public void resume();
method public void seekTo(int);
+ method public void setAudioAttributes(android.media.AudioAttributes);
+ method public void setAudioFocusRequest(int);
method public void setMediaController(android.widget.MediaController);
method public void setOnCompletionListener(android.media.MediaPlayer.OnCompletionListener);
method public void setOnErrorListener(android.media.MediaPlayer.OnErrorListener);
@@ -54837,7 +54917,7 @@
package com.android.internal.util {
- public abstract interface Predicate<T> {
+ public abstract deprecated interface Predicate<T> {
method public abstract boolean apply(T);
}
diff --git a/api/system-removed.txt b/api/system-removed.txt
index 6773112..a3093e2 100644
--- a/api/system-removed.txt
+++ b/api/system-removed.txt
@@ -18,25 +18,14 @@
package android.content {
public abstract class Context {
- method public deprecated android.content.Context createCredentialEncryptedStorageContext();
- method public deprecated android.content.Context createDeviceEncryptedStorageContext();
method public abstract android.content.SharedPreferences getSharedPreferences(java.io.File, int);
method public abstract java.io.File getSharedPreferencesPath(java.lang.String);
- method public deprecated boolean isCredentialEncryptedStorage();
- method public deprecated boolean isDeviceEncryptedStorage();
- method public deprecated boolean migrateDatabaseFrom(android.content.Context, java.lang.String);
- method public deprecated boolean migrateSharedPreferencesFrom(android.content.Context, java.lang.String);
}
}
package android.content.pm {
- public class ApplicationInfo extends android.content.pm.PackageItemInfo implements android.os.Parcelable {
- field public deprecated java.lang.String credentialEncryptedDataDir;
- field public deprecated java.lang.String deviceEncryptedDataDir;
- }
-
public class ComponentInfo extends android.content.pm.PackageItemInfo {
field public deprecated boolean encryptionAware;
}
@@ -45,12 +34,6 @@
field public static final int REQUESTED_PERMISSION_REQUIRED = 1; // 0x1
}
- public abstract class PackageManager {
- field public static final deprecated int MATCH_ENCRYPTION_AWARE = 524288; // 0x80000
- field public static final deprecated int MATCH_ENCRYPTION_AWARE_AND_UNAWARE = 786432; // 0xc0000
- field public static final deprecated int MATCH_ENCRYPTION_UNAWARE = 262144; // 0x40000
- }
-
}
package android.database {
@@ -163,10 +146,6 @@
method public android.graphics.drawable.Drawable getBadgedDrawableForUser(android.graphics.drawable.Drawable, android.os.UserHandle, android.graphics.Rect, int);
method public android.graphics.drawable.Drawable getBadgedIconForUser(android.graphics.drawable.Drawable, android.os.UserHandle);
method public java.lang.CharSequence getBadgedLabelForUser(java.lang.CharSequence, android.os.UserHandle);
- method public deprecated boolean isUserRunningAndLocked();
- method public deprecated boolean isUserRunningAndLocked(android.os.UserHandle);
- method public deprecated boolean isUserRunningAndUnlocked();
- method public deprecated boolean isUserRunningAndUnlocked(android.os.UserHandle);
}
}
@@ -184,15 +163,6 @@
}
-package android.preference {
-
- public class PreferenceManager {
- method public deprecated void setStorageCredentialEncrypted();
- method public deprecated void setStorageDeviceEncrypted();
- }
-
-}
-
package android.provider {
public class Browser {
diff --git a/api/test-current.txt b/api/test-current.txt
index 41f279b..1a12b4c 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -16,6 +16,7 @@
field public static final java.lang.String ACCOUNT_MANAGER = "android.permission.ACCOUNT_MANAGER";
field public static final java.lang.String ADD_VOICEMAIL = "com.android.voicemail.permission.ADD_VOICEMAIL";
field public static final java.lang.String ALLOCATE_AGGRESSIVE = "android.permission.ALLOCATE_AGGRESSIVE";
+ field public static final java.lang.String ANSWER_PHONE_CALLS = "android.permission.ANSWER_PHONE_CALLS";
field public static final java.lang.String BATTERY_STATS = "android.permission.BATTERY_STATS";
field public static final java.lang.String BIND_ACCESSIBILITY_SERVICE = "android.permission.BIND_ACCESSIBILITY_SERVICE";
field public static final java.lang.String BIND_APPWIDGET = "android.permission.BIND_APPWIDGET";
@@ -305,7 +306,7 @@
field public static final int autoSizeMinTextSize = 16844088; // 0x1010538
field public static final int autoSizePresetSizes = 16844087; // 0x1010537
field public static final int autoSizeStepGranularity = 16844086; // 0x1010536
- field public static final int autoSizeText = 16844085; // 0x1010535
+ field public static final int autoSizeTextType = 16844085; // 0x1010535
field public static final int autoStart = 16843445; // 0x10102b5
field public static final deprecated int autoText = 16843114; // 0x101016a
field public static final int autoUrlDetect = 16843404; // 0x101028c
@@ -410,6 +411,7 @@
field public static final int colorControlHighlight = 16843820; // 0x101042c
field public static final int colorControlNormal = 16843817; // 0x1010429
field public static final int colorEdgeEffect = 16843982; // 0x10104ce
+ field public static final int colorError = 16844100; // 0x1010544
field public static final int colorFocusedHighlight = 16843663; // 0x101038f
field public static final int colorForeground = 16842800; // 0x1010030
field public static final int colorForegroundInverse = 16843270; // 0x1010206
@@ -1316,7 +1318,6 @@
field public static final int textCheckMarkInverse = 16842823; // 0x1010047
field public static final int textColor = 16842904; // 0x1010098
field public static final int textColorAlertDialogListItem = 16843526; // 0x1010306
- field public static final int textColorError = 16844100; // 0x1010544
field public static final int textColorHighlight = 16842905; // 0x1010099
field public static final int textColorHighlightInverse = 16843599; // 0x101034f
field public static final int textColorHint = 16842906; // 0x101009a
@@ -4153,6 +4154,7 @@
field public static final int MODE_ERRORED = 2; // 0x2
field public static final int MODE_IGNORED = 1; // 0x1
field public static final java.lang.String OPSTR_ADD_VOICEMAIL = "android:add_voicemail";
+ field public static final java.lang.String OPSTR_ANSWER_PHONE_CALLS = "android:answer_phone_calls";
field public static final java.lang.String OPSTR_BODY_SENSORS = "android:body_sensors";
field public static final java.lang.String OPSTR_CALL_PHONE = "android:call_phone";
field public static final java.lang.String OPSTR_CAMERA = "android:camera";
@@ -4747,6 +4749,7 @@
method public abstract android.app.Fragment getPrimaryNavigationFragment();
method public void invalidateOptionsMenu();
method public abstract boolean isDestroyed();
+ method public abstract boolean isStateSaved();
method public abstract void popBackStack();
method public abstract void popBackStack(java.lang.String, int);
method public abstract void popBackStack(int, int);
@@ -6573,6 +6576,7 @@
public static class AssistStructure.ViewNode {
method public float getAlpha();
method public android.view.autofill.AutoFillId getAutoFillId();
+ method public java.lang.String[] getAutoFillOptions();
method public android.view.autofill.AutoFillType getAutoFillType();
method public android.view.autofill.AutoFillValue getAutoFillValue();
method public android.app.assist.AssistStructure.ViewNode getChildAt(int);
@@ -6742,6 +6746,7 @@
method public android.app.job.JobInfo.TriggerContentUri[] getTriggerContentUris();
method public boolean isPeriodic();
method public boolean isPersisted();
+ method public boolean isRequireBatteryNotLow();
method public boolean isRequireCharging();
method public boolean isRequireDeviceIdle();
method public void writeToParcel(android.os.Parcel, int);
@@ -6768,6 +6773,7 @@
method public android.app.job.JobInfo.Builder setPeriodic(long, long);
method public android.app.job.JobInfo.Builder setPersisted(boolean);
method public android.app.job.JobInfo.Builder setRequiredNetworkType(int);
+ method public android.app.job.JobInfo.Builder setRequiresBatteryNotLow(boolean);
method public android.app.job.JobInfo.Builder setRequiresCharging(boolean);
method public android.app.job.JobInfo.Builder setRequiresDeviceIdle(boolean);
method public android.app.job.JobInfo.Builder setTransientExtras(android.os.Bundle);
@@ -6908,6 +6914,7 @@
method public long getFreeBytes(java.lang.String);
method public long getTotalBytes(java.lang.String);
method public android.app.usage.ExternalStorageStats queryExternalStatsForUser(java.lang.String, android.os.UserHandle);
+ method public android.app.usage.StorageStats queryStatsForPackage(java.lang.String, java.lang.String, android.os.UserHandle);
method public android.app.usage.StorageStats queryStatsForUid(java.lang.String, int);
method public android.app.usage.StorageStats queryStatsForUser(java.lang.String, android.os.UserHandle);
}
@@ -8697,6 +8704,7 @@
field public static final java.lang.String HARDWARE_PROPERTIES_SERVICE = "hardware_properties";
field public static final java.lang.String INPUT_METHOD_SERVICE = "input_method";
field public static final java.lang.String INPUT_SERVICE = "input";
+ field public static final java.lang.String IPSEC_SERVICE = "ipsec";
field public static final java.lang.String JOB_SCHEDULER_SERVICE = "jobscheduler";
field public static final java.lang.String KEYGUARD_SERVICE = "keyguard";
field public static final java.lang.String LAUNCHER_APPS_SERVICE = "launcherapps";
@@ -9067,6 +9075,7 @@
field public static final java.lang.String ACTION_CALL = "android.intent.action.CALL";
field public static final java.lang.String ACTION_CALL_BUTTON = "android.intent.action.CALL_BUTTON";
field public static final java.lang.String ACTION_CAMERA_BUTTON = "android.intent.action.CAMERA_BUTTON";
+ field public static final java.lang.String ACTION_CARRIER_SETUP = "android.intent.action.CARRIER_SETUP";
field public static final java.lang.String ACTION_CHOOSER = "android.intent.action.CHOOSER";
field public static final java.lang.String ACTION_CLEAR_PACKAGE = "android.intent.action.CLEAR_PACKAGE";
field public static final java.lang.String ACTION_CLOSE_SYSTEM_DIALOGS = "android.intent.action.CLOSE_SYSTEM_DIALOGS";
@@ -10131,10 +10140,12 @@
ctor public LauncherApps.ShortcutQuery();
method public android.content.pm.LauncherApps.ShortcutQuery setActivity(android.content.ComponentName);
method public android.content.pm.LauncherApps.ShortcutQuery setChangedSince(long);
+ method public android.content.pm.LauncherApps.ShortcutQuery setIntent(android.content.Intent);
method public android.content.pm.LauncherApps.ShortcutQuery setPackage(java.lang.String);
method public android.content.pm.LauncherApps.ShortcutQuery setQueryFlags(int);
method public android.content.pm.LauncherApps.ShortcutQuery setShortcutIds(java.util.List<java.lang.String>);
field public static final int FLAG_GET_KEY_FIELDS_ONLY = 4; // 0x4
+ field public static final int FLAG_MATCH_CHOOSER = 16; // 0x10
field public static final int FLAG_MATCH_DYNAMIC = 1; // 0x1
field public static final int FLAG_MATCH_MANIFEST = 8; // 0x8
field public static final int FLAG_MATCH_PINNED = 2; // 0x2
@@ -10190,9 +10201,11 @@
method public void unregisterSessionCallback(android.content.pm.PackageInstaller.SessionCallback);
method public void updateSessionAppIcon(int, android.graphics.Bitmap);
method public void updateSessionAppLabel(int, java.lang.CharSequence);
+ field public static final java.lang.String ACTION_SESSION_COMMITTED = "android.content.pm.action.SESSION_COMMITTED";
field public static final java.lang.String ACTION_SESSION_DETAILS = "android.content.pm.action.SESSION_DETAILS";
field public static final java.lang.String EXTRA_OTHER_PACKAGE_NAME = "android.content.pm.extra.OTHER_PACKAGE_NAME";
field public static final java.lang.String EXTRA_PACKAGE_NAME = "android.content.pm.extra.PACKAGE_NAME";
+ field public static final java.lang.String EXTRA_SESSION = "android.content.pm.extra.SESSION";
field public static final java.lang.String EXTRA_SESSION_ID = "android.content.pm.extra.SESSION_ID";
field public static final java.lang.String EXTRA_STATUS = "android.content.pm.extra.STATUS";
field public static final java.lang.String EXTRA_STATUS_MESSAGE = "android.content.pm.extra.STATUS_MESSAGE";
@@ -10235,6 +10248,7 @@
method public android.graphics.Bitmap getAppIcon();
method public java.lang.CharSequence getAppLabel();
method public java.lang.String getAppPackageName();
+ method public int getInstallReason();
method public java.lang.String getInstallerPackageName();
method public float getProgress();
method public int getSessionId();
@@ -10628,6 +10642,7 @@
field public android.content.pm.ActivityInfo activityInfo;
field public android.content.IntentFilter filter;
field public int icon;
+ field public boolean instantAppAvailable;
field public boolean isDefault;
field public int labelRes;
field public int match;
@@ -10677,6 +10692,9 @@
method public int describeContents();
method public android.content.ComponentName getActivity();
method public java.util.Set<java.lang.String> getCategories();
+ method public android.content.ComponentName[] getChooserComponentNames();
+ method public android.os.PersistableBundle getChooserExtras();
+ method public android.content.IntentFilter[] getChooserIntentFilters();
method public java.lang.CharSequence getDisabledMessage();
method public android.os.PersistableBundle getExtras();
method public java.lang.String getId();
@@ -10689,6 +10707,7 @@
method public java.lang.CharSequence getShortLabel();
method public android.os.UserHandle getUserHandle();
method public boolean hasKeyFieldsOnly();
+ method public boolean isChooser();
method public boolean isDeclaredInManifest();
method public boolean isDynamic();
method public boolean isEnabled();
@@ -10701,9 +10720,11 @@
public static class ShortcutInfo.Builder {
ctor public ShortcutInfo.Builder(android.content.Context, java.lang.String);
+ method public android.content.pm.ShortcutInfo.Builder addChooserIntentFilter(android.content.IntentFilter, android.content.ComponentName);
method public android.content.pm.ShortcutInfo build();
method public android.content.pm.ShortcutInfo.Builder setActivity(android.content.ComponentName);
method public android.content.pm.ShortcutInfo.Builder setCategories(java.util.Set<java.lang.String>);
+ method public android.content.pm.ShortcutInfo.Builder setChooserExtras(android.os.PersistableBundle);
method public android.content.pm.ShortcutInfo.Builder setDisabledMessage(java.lang.CharSequence);
method public android.content.pm.ShortcutInfo.Builder setExtras(android.os.PersistableBundle);
method public android.content.pm.ShortcutInfo.Builder setIcon(android.graphics.drawable.Icon);
@@ -12609,6 +12630,7 @@
method public static android.graphics.ColorSpace.Adaptation valueOf(java.lang.String);
method public static final android.graphics.ColorSpace.Adaptation[] values();
enum_constant public static final android.graphics.ColorSpace.Adaptation BRADFORD;
+ enum_constant public static final android.graphics.ColorSpace.Adaptation CIECAT02;
enum_constant public static final android.graphics.ColorSpace.Adaptation VON_KRIES;
}
@@ -14046,6 +14068,8 @@
public class ArcShape extends android.graphics.drawable.shapes.RectShape {
ctor public ArcShape(float, float);
+ method public final float getStartAngle();
+ method public final float getSweepAngle();
}
public class OvalShape extends android.graphics.drawable.shapes.RectShape {
@@ -20739,6 +20763,26 @@
field public static final int TYPE_WIRED_HEADSET = 3; // 0x3
}
+ public final class AudioFocusRequest {
+ method public boolean acceptsDelayedFocusGain();
+ method public android.media.AudioAttributes getAudioAttributes();
+ method public int getFocusGain();
+ method public android.media.AudioManager.OnAudioFocusChangeListener getOnAudioFocusChangeListener();
+ method public android.os.Handler getOnAudioFocusChangeListenerHandler();
+ method public boolean willPauseWhenDucked();
+ }
+
+ public static final class AudioFocusRequest.Builder {
+ ctor public AudioFocusRequest.Builder(int);
+ ctor public AudioFocusRequest.Builder(android.media.AudioFocusRequest);
+ method public android.media.AudioFocusRequest build();
+ method public android.media.AudioFocusRequest.Builder setAcceptsDelayedFocusGain(boolean);
+ method public android.media.AudioFocusRequest.Builder setAudioAttributes(android.media.AudioAttributes);
+ method public android.media.AudioFocusRequest.Builder setFocusGain(int);
+ method public android.media.AudioFocusRequest.Builder setOnAudioFocusChangeListener(android.media.AudioManager.OnAudioFocusChangeListener, android.os.Handler);
+ method public android.media.AudioFocusRequest.Builder setWillPauseWhenDucked(boolean);
+ }
+
public final class AudioFormat implements android.os.Parcelable {
method public int describeContents();
method public int getChannelCount();
@@ -20815,6 +20859,7 @@
public class AudioManager {
method public int abandonAudioFocus(android.media.AudioManager.OnAudioFocusChangeListener);
+ method public int abandonAudioFocusRequest(android.media.AudioFocusRequest);
method public void adjustStreamVolume(int, int, int);
method public void adjustSuggestedStreamVolume(int, int, int);
method public void adjustVolume(int, int);
@@ -20851,6 +20896,7 @@
method public deprecated void registerRemoteControlClient(android.media.RemoteControlClient);
method public deprecated boolean registerRemoteController(android.media.RemoteController);
method public int requestAudioFocus(android.media.AudioManager.OnAudioFocusChangeListener, int, int);
+ method public int requestAudioFocus(android.media.AudioFocusRequest);
method public deprecated void setBluetoothA2dpOn(boolean);
method public void setBluetoothScoOn(boolean);
method public void setMicrophoneMute(boolean);
@@ -20893,6 +20939,8 @@
field public static final int AUDIOFOCUS_LOSS = -1; // 0xffffffff
field public static final int AUDIOFOCUS_LOSS_TRANSIENT = -2; // 0xfffffffe
field public static final int AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK = -3; // 0xfffffffd
+ field public static final int AUDIOFOCUS_NONE = 0; // 0x0
+ field public static final int AUDIOFOCUS_REQUEST_DELAYED = 2; // 0x2
field public static final int AUDIOFOCUS_REQUEST_FAILED = 0; // 0x0
field public static final int AUDIOFOCUS_REQUEST_GRANTED = 1; // 0x1
field public static final int AUDIO_SESSION_ID_GENERATE = 0; // 0x0
@@ -21089,13 +21137,14 @@
field public long nanoTime;
}
- public class AudioTrack implements android.media.AudioRouting {
+ public class AudioTrack implements android.media.AudioRouting android.media.VolumeAutomation {
ctor public deprecated AudioTrack(int, int, int, int, int, int) throws java.lang.IllegalArgumentException;
ctor public deprecated AudioTrack(int, int, int, int, int, int, int) throws java.lang.IllegalArgumentException;
ctor public AudioTrack(android.media.AudioAttributes, android.media.AudioFormat, int, int, int) throws java.lang.IllegalArgumentException;
method public void addOnRoutingChangedListener(android.media.AudioRouting.OnRoutingChangedListener, android.os.Handler);
method public deprecated void addOnRoutingChangedListener(android.media.AudioTrack.OnRoutingChangedListener, android.os.Handler);
method public int attachAuxEffect(int);
+ method public android.media.VolumeShaper createVolumeShaper(android.media.VolumeShaper.Configuration);
method public void flush();
method public int getAudioFormat();
method public int getAudioSessionId();
@@ -21563,8 +21612,42 @@
field public static final int STOP_VIDEO_RECORDING = 3; // 0x3
}
+ public final class MediaCas {
+ ctor public MediaCas(int) throws android.media.UnsupportedCasException;
+ method public void closeSession(byte[]);
+ method public static android.media.MediaCas.PluginDescriptor[] enumeratePlugins();
+ method public static boolean isSystemIdSupported(int);
+ method public byte[] openSession(int);
+ method public byte[] openSession(int, int);
+ method public void processEcm(byte[], byte[], int, int);
+ method public void processEcm(byte[], byte[]);
+ method public void processEmm(byte[], int, int);
+ method public void processEmm(byte[]);
+ method public void provision(java.lang.String);
+ method public void refreshEntitlements(int, byte[]);
+ method public void release();
+ method public void sendEvent(int, int, byte[]);
+ method public void setEventListener(android.media.MediaCas.EventListener, android.os.Handler);
+ method public void setPrivateData(byte[]);
+ method public void setSessionPrivateData(byte[], byte[]);
+ }
+
+ public static abstract interface MediaCas.EventListener {
+ method public abstract void onEvent(android.media.MediaCas, int, int, byte[]);
+ }
+
+ public static class MediaCas.PluginDescriptor {
+ method public java.lang.String getName();
+ method public int getSystemId();
+ }
+
+ public class MediaCasException extends java.lang.Exception {
+ ctor public MediaCasException(java.lang.String);
+ }
+
public final class MediaCodec {
method public void configure(android.media.MediaFormat, android.view.Surface, android.media.MediaCrypto, int);
+ method public void configure(android.media.MediaFormat, android.view.Surface, int, android.media.MediaDescrambler);
method public static android.media.MediaCodec createByCodecName(java.lang.String) throws java.io.IOException;
method public static android.media.MediaCodec createDecoderByType(java.lang.String) throws java.io.IOException;
method public static android.media.MediaCodec createEncoderByType(java.lang.String) throws java.io.IOException;
@@ -21604,6 +21687,7 @@
field public static final int BUFFER_FLAG_CODEC_CONFIG = 2; // 0x2
field public static final int BUFFER_FLAG_END_OF_STREAM = 4; // 0x4
field public static final int BUFFER_FLAG_KEY_FRAME = 1; // 0x1
+ field public static final int BUFFER_FLAG_PARTIAL_FRAME = 8; // 0x8
field public static final deprecated int BUFFER_FLAG_SYNC_FRAME = 1; // 0x1
field public static final int CONFIGURE_FLAG_ENCODE = 1; // 0x1
field public static final int CRYPTO_MODE_AES_CBC = 2; // 0x2
@@ -21760,6 +21844,7 @@
field public static final deprecated int COLOR_TI_FormatYUV420PackedSemiPlanar = 2130706688; // 0x7f000100
field public static final java.lang.String FEATURE_AdaptivePlayback = "adaptive-playback";
field public static final java.lang.String FEATURE_IntraRefresh = "intra-refresh";
+ field public static final java.lang.String FEATURE_PartialFrame = "partial-frame";
field public static final java.lang.String FEATURE_SecurePlayback = "secure-playback";
field public static final java.lang.String FEATURE_TunneledPlayback = "tunneled-playback";
field public int[] colorFormats;
@@ -21984,6 +22069,14 @@
method public abstract int readAt(long, byte[], int, int) throws java.io.IOException;
}
+ public final class MediaDescrambler {
+ ctor public MediaDescrambler(int) throws android.media.UnsupportedCasException;
+ method public final int descramble(java.nio.ByteBuffer, int, java.nio.ByteBuffer, int, android.media.MediaCodec.CryptoInfo);
+ method public final void release();
+ method public final boolean requiresSecureDecoderComponent(java.lang.String);
+ method public final void setMediaCasSession(byte[]);
+ }
+
public class MediaDescription implements android.os.Parcelable {
method public int describeContents();
method public java.lang.CharSequence getDescription();
@@ -22140,8 +22233,10 @@
method public final void setDataSource(android.content.res.AssetFileDescriptor) throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException;
method public final void setDataSource(java.io.FileDescriptor) throws java.io.IOException;
method public final void setDataSource(java.io.FileDescriptor, long, long) throws java.io.IOException;
+ method public final void setMediaCas(android.media.MediaCas);
method public void unselectTrack(int);
field public static final int SAMPLE_FLAG_ENCRYPTED = 2; // 0x2
+ field public static final int SAMPLE_FLAG_PARTIAL_FRAME = 4; // 0x4
field public static final int SAMPLE_FLAG_SYNC = 1; // 0x1
field public static final int SEEK_TO_CLOSEST_SYNC = 2; // 0x2
field public static final int SEEK_TO_NEXT_SYNC = 1; // 0x1
@@ -22207,6 +22302,7 @@
field public static final java.lang.String KEY_IS_FORCED_SUBTITLE = "is-forced-subtitle";
field public static final java.lang.String KEY_I_FRAME_INTERVAL = "i-frame-interval";
field public static final java.lang.String KEY_LANGUAGE = "language";
+ field public static final java.lang.String KEY_LATENCY = "latency";
field public static final java.lang.String KEY_LEVEL = "level";
field public static final java.lang.String KEY_MAX_HEIGHT = "max-height";
field public static final java.lang.String KEY_MAX_INPUT_SIZE = "max-input-size";
@@ -22238,6 +22334,7 @@
field public static final java.lang.String MIMETYPE_AUDIO_OPUS = "audio/opus";
field public static final java.lang.String MIMETYPE_AUDIO_QCELP = "audio/qcelp";
field public static final java.lang.String MIMETYPE_AUDIO_RAW = "audio/raw";
+ field public static final java.lang.String MIMETYPE_AUDIO_SCRAMBLED = "audio/scrambled";
field public static final java.lang.String MIMETYPE_AUDIO_VORBIS = "audio/vorbis";
field public static final java.lang.String MIMETYPE_TEXT_CEA_608 = "text/cea-608";
field public static final java.lang.String MIMETYPE_TEXT_VTT = "text/vtt";
@@ -22248,6 +22345,7 @@
field public static final java.lang.String MIMETYPE_VIDEO_MPEG2 = "video/mpeg2";
field public static final java.lang.String MIMETYPE_VIDEO_MPEG4 = "video/mp4v-es";
field public static final java.lang.String MIMETYPE_VIDEO_RAW = "video/raw";
+ field public static final java.lang.String MIMETYPE_VIDEO_SCRAMBLED = "video/scrambled";
field public static final java.lang.String MIMETYPE_VIDEO_VP8 = "video/x-vnd.on2.vp8";
field public static final java.lang.String MIMETYPE_VIDEO_VP9 = "video/x-vnd.on2.vp9";
}
@@ -22388,7 +22486,7 @@
field public static final int MUXER_OUTPUT_WEBM = 1; // 0x1
}
- public class MediaPlayer {
+ public class MediaPlayer implements android.media.VolumeAutomation {
ctor public MediaPlayer();
method public void addTimedTextSource(java.lang.String, java.lang.String) throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException;
method public void addTimedTextSource(android.content.Context, android.net.Uri, java.lang.String) throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException;
@@ -22400,6 +22498,7 @@
method public static android.media.MediaPlayer create(android.content.Context, android.net.Uri, android.view.SurfaceHolder, android.media.AudioAttributes, int);
method public static android.media.MediaPlayer create(android.content.Context, int);
method public static android.media.MediaPlayer create(android.content.Context, int, android.media.AudioAttributes, int);
+ method public android.media.VolumeShaper createVolumeShaper(android.media.VolumeShaper.Configuration);
method public void deselectTrack(int) throws java.lang.IllegalStateException;
method public int getAudioSessionId();
method public android.media.BufferingParams getBufferingParams();
@@ -23219,10 +23318,18 @@
field public static final int TONE_SUP_RINGTONE = 23; // 0x17
}
+ public final class UnsupportedCasException extends android.media.MediaCasException {
+ ctor public UnsupportedCasException(java.lang.String);
+ }
+
public final class UnsupportedSchemeException extends android.media.MediaDrmException {
ctor public UnsupportedSchemeException(java.lang.String);
}
+ public abstract interface VolumeAutomation {
+ method public abstract android.media.VolumeShaper createVolumeShaper(android.media.VolumeShaper.Configuration);
+ }
+
public abstract class VolumeProvider {
ctor public VolumeProvider(int, int, int);
method public final int getCurrentVolume();
@@ -23236,6 +23343,53 @@
field public static final int VOLUME_CONTROL_RELATIVE = 1; // 0x1
}
+ public final class VolumeShaper implements java.lang.AutoCloseable {
+ method public void apply(android.media.VolumeShaper.Operation);
+ method public void close();
+ method public float getVolume();
+ method public void replace(android.media.VolumeShaper.Configuration, android.media.VolumeShaper.Operation, boolean);
+ }
+
+ public static final class VolumeShaper.Configuration implements android.os.Parcelable {
+ method public int describeContents();
+ method public double getDurationMs();
+ method public int getInterpolatorType();
+ method public static int getMaximumCurvePoints();
+ method public float[] getTimes();
+ method public float[] getVolumes();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.media.VolumeShaper.Configuration> CREATOR;
+ field public static final android.media.VolumeShaper.Configuration CUBIC_RAMP;
+ field public static final int INTERPOLATOR_TYPE_CUBIC = 2; // 0x2
+ field public static final int INTERPOLATOR_TYPE_CUBIC_MONOTONIC = 3; // 0x3
+ field public static final int INTERPOLATOR_TYPE_LINEAR = 1; // 0x1
+ field public static final int INTERPOLATOR_TYPE_STEP = 0; // 0x0
+ field public static final android.media.VolumeShaper.Configuration LINEAR_RAMP;
+ field public static final android.media.VolumeShaper.Configuration SCURVE_RAMP;
+ field public static final android.media.VolumeShaper.Configuration SINE_RAMP;
+ }
+
+ public static final class VolumeShaper.Configuration.Builder {
+ ctor public VolumeShaper.Configuration.Builder();
+ ctor public VolumeShaper.Configuration.Builder(android.media.VolumeShaper.Configuration);
+ method public android.media.VolumeShaper.Configuration build();
+ method public android.media.VolumeShaper.Configuration.Builder invertVolumes();
+ method public android.media.VolumeShaper.Configuration.Builder reflectTimes();
+ method public android.media.VolumeShaper.Configuration.Builder scaleToEndVolume(float);
+ method public android.media.VolumeShaper.Configuration.Builder scaleToStartVolume(float);
+ method public android.media.VolumeShaper.Configuration.Builder setCurve(float[], float[]);
+ method public android.media.VolumeShaper.Configuration.Builder setDurationMs(double);
+ method public android.media.VolumeShaper.Configuration.Builder setInterpolatorType(int);
+ }
+
+ public static final class VolumeShaper.Operation implements android.os.Parcelable {
+ method public int describeContents();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.media.VolumeShaper.Operation> CREATOR;
+ field public static final android.media.VolumeShaper.Operation PLAY;
+ field public static final android.media.VolumeShaper.Operation REVERSE;
+ }
+
}
package android.media.audiofx {
@@ -24081,17 +24235,79 @@
method public static final android.net.Uri buildProgramsUriForChannel(long, long, long);
method public static final android.net.Uri buildProgramsUriForChannel(android.net.Uri, long, long);
method public static final android.net.Uri buildRecordedProgramUri(long);
+ method public static final android.net.Uri buildWatchNextProgramUri(long);
method public static final boolean isChannelUri(android.net.Uri);
method public static final boolean isChannelUriForPassthroughInput(android.net.Uri);
method public static final boolean isChannelUriForTunerInput(android.net.Uri);
method public static final boolean isProgramUri(android.net.Uri);
+ field public static final java.lang.String ACTION_MAKE_CHANNEL_BROWSABLE = "android.media.tv.action.MAKE_CHANNEL_BROWSABLE";
+ field public static final java.lang.String ACTION_PREVIEW_PROGRAM_ADDED_TO_WATCH_NEXT = "android.media.tv.action.PREVIEW_PROGRAM_ADDED_TO_WATCH_NEXT";
+ field public static final java.lang.String ACTION_PREVIEW_PROGRAM_BROWSABLE_DISABLED = "android.media.tv.action.PREVIEW_PROGRAM_BROWSABLE_DISABLED";
+ field public static final java.lang.String ACTION_WATCH_NEXT_PROGRAM_BROWSABLE_DISABLED = "android.media.tv.action.WATCH_NEXT_PROGRAM_BROWSABLE_DISABLED";
field public static final java.lang.String AUTHORITY = "android.media.tv";
+ field public static final java.lang.String EXTRA_CHANNEL_ID = "android.media.tv.extra.CHANNEL_ID";
+ field public static final java.lang.String EXTRA_PACKAGE_NAME = "android.media.tv.extra.PACKAGE_NAME";
+ field public static final java.lang.String EXTRA_PREVIEW_PROGRAM_ID = "android.media.tv.extra.PREVIEW_PROGRAM_ID";
+ field public static final java.lang.String EXTRA_WATCH_NEXT_PROGRAM_ID = "android.media.tv.extra.WATCH_NEXT_PROGRAM_ID";
+ }
+
+ public static abstract interface TvContract.BasePreviewProgramColumns implements android.media.tv.TvContract.BaseProgramColumns {
+ field public static final java.lang.String ASPECT_RATIO_16_9 = "ASPECT_RATIO_16_9";
+ field public static final java.lang.String ASPECT_RATIO_1_1 = "ASPECT_RATIO_1_1";
+ field public static final java.lang.String ASPECT_RATIO_2_3 = "ASPECT_RATIO_2_3";
+ field public static final java.lang.String ASPECT_RATIO_3_2 = "ASPECT_RATIO_3_2";
+ field public static final java.lang.String AVAILABILITY_AVAILABLE = "AVAILABILITY_AVAILABLE";
+ field public static final java.lang.String AVAILABILITY_FREE_WITH_SUBSCRIPTION = "AVAILABILITY_FREE_WITH_SUBSCRIPTION";
+ field public static final java.lang.String AVAILABILITY_PAID_CONTENT = "AVAILABILITY_PAID_CONTENT";
+ field public static final java.lang.String COLUMN_APP_LINK_INTENT_URI = "app_link_intent_uri";
+ field public static final java.lang.String COLUMN_AUTHOR = "author";
+ field public static final java.lang.String COLUMN_AVAILABILITY = "availability";
+ field public static final java.lang.String COLUMN_BROWSABLE = "browsable";
+ field public static final java.lang.String COLUMN_CONTENT_ID = "content_id";
+ field public static final java.lang.String COLUMN_DURATION_MILLIS = "duration_millis";
+ field public static final java.lang.String COLUMN_INTERACTION_COUNT = "interaction_count";
+ field public static final java.lang.String COLUMN_INTERACTION_TYPE = "interaction_type";
+ field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_ID = "internal_provider_id";
+ field public static final java.lang.String COLUMN_ITEM_COUNT = "item_count";
+ field public static final java.lang.String COLUMN_LAST_PLAYBACK_POSITION_MILLIS = "last_playback_position_millis";
+ field public static final java.lang.String COLUMN_LIVE = "live";
+ field public static final java.lang.String COLUMN_LOGO_URI = "logo_uri";
+ field public static final java.lang.String COLUMN_OFFER_PRICE = "offer_price";
+ field public static final java.lang.String COLUMN_POSTER_ART_ASPECT_RATIO = "poster_art_aspect_ratio";
+ field public static final java.lang.String COLUMN_PREVIEW_VIDEO_URI = "preview_video_uri";
+ field public static final java.lang.String COLUMN_RELEASE_DATE = "release_date";
+ field public static final java.lang.String COLUMN_REVIEW_RATING = "review_rating";
+ field public static final java.lang.String COLUMN_REVIEW_RATING_STYLE = "review_rating_style";
+ field public static final java.lang.String COLUMN_STARTING_PRICE = "starting_price";
+ field public static final java.lang.String COLUMN_THUMBNAIL_ASPECT_RATIO = "poster_thumbnail_aspect_ratio";
+ field public static final java.lang.String COLUMN_TYPE = "type";
+ field public static final java.lang.String INTERACTION_TYPE_FANS = "INTERACTION_TYPE_FANS";
+ field public static final java.lang.String INTERACTION_TYPE_FOLLOWERS = "INTERACTION_TYPE_FOLLOWERS";
+ field public static final java.lang.String INTERACTION_TYPE_LIKES = "INTERACTION_TYPE_LIKES";
+ field public static final java.lang.String INTERACTION_TYPE_LISTENS = "INTERACTION_TYPE_LISTENS";
+ field public static final java.lang.String INTERACTION_TYPE_THUMBS = "INTERACTION_TYPE_THUMBS";
+ field public static final java.lang.String INTERACTION_TYPE_VIEWERS = "INTERACTION_TYPE_VIEWERS";
+ field public static final java.lang.String INTERACTION_TYPE_VIEWS = "INTERACTION_TYPE_VIEWS";
+ field public static final java.lang.String REVIEW_RATING_STYLE_PERCENTAGE = "REVIEW_RATING_STYLE_PERCENTAGE";
+ field public static final java.lang.String REVIEW_RATING_STYLE_STARS = "REVIEW_RATING_STYLE_STARS";
+ field public static final java.lang.String REVIEW_RATING_STYLE_THUMBS_UP_DOWN = "REVIEW_RATING_STYLE_THUMBS_UP_DOWN";
+ field public static final java.lang.String TYPE_ALBUM = "TYPE_ALBUM";
+ field public static final java.lang.String TYPE_ARTIST = "TYPE_ARTIST";
+ field public static final java.lang.String TYPE_CHANNEL = "TYPE_CHANNEL";
+ field public static final java.lang.String TYPE_CLIP = "TYPE_CLIP";
+ field public static final java.lang.String TYPE_EVENT = "TYPE_EVENT";
+ field public static final java.lang.String TYPE_MOVIE = "TYPE_MOVIE";
+ field public static final java.lang.String TYPE_PLAYLIST = "TYPE_PLAYLIST";
+ field public static final java.lang.String TYPE_STATION = "TYPE_STATION";
+ field public static final java.lang.String TYPE_TRACK = "TYPE_TRACK";
+ field public static final java.lang.String TYPE_TV_EPISODE = "TYPE_TV_EPISODE";
+ field public static final java.lang.String TYPE_TV_SEASON = "TYPE_TV_SEASON";
+ field public static final java.lang.String TYPE_TV_SERIES = "TYPE_TV_SERIES";
}
public static abstract interface TvContract.BaseProgramColumns implements android.media.tv.TvContract.BaseTvColumns {
field public static final java.lang.String COLUMN_AUDIO_LANGUAGE = "audio_language";
field public static final java.lang.String COLUMN_CANONICAL_GENRE = "canonical_genre";
- field public static final java.lang.String COLUMN_CHANNEL_ID = "channel_id";
field public static final java.lang.String COLUMN_CONTENT_RATING = "content_rating";
field public static final java.lang.String COLUMN_EPISODE_DISPLAY_NUMBER = "episode_display_number";
field public static final java.lang.String COLUMN_EPISODE_TITLE = "episode_title";
@@ -24124,6 +24340,7 @@
field public static final java.lang.String COLUMN_APP_LINK_INTENT_URI = "app_link_intent_uri";
field public static final java.lang.String COLUMN_APP_LINK_POSTER_ART_URI = "app_link_poster_art_uri";
field public static final java.lang.String COLUMN_APP_LINK_TEXT = "app_link_text";
+ field public static final java.lang.String COLUMN_BROWSABLE = "browsable";
field public static final java.lang.String COLUMN_DESCRIPTION = "description";
field public static final java.lang.String COLUMN_DISPLAY_NAME = "display_name";
field public static final java.lang.String COLUMN_DISPLAY_NUMBER = "display_number";
@@ -24196,69 +24413,17 @@
field public static final java.lang.String CONTENT_DIRECTORY = "logo";
}
- public static final class TvContract.PreviewPrograms implements android.media.tv.TvContract.BaseProgramColumns {
- field public static final java.lang.String ASPECT_RATIO_16_9 = "ASPECT_RATIO_16_9";
- field public static final java.lang.String ASPECT_RATIO_1_1 = "ASPECT_RATIO_1_1";
- field public static final java.lang.String ASPECT_RATIO_2_3 = "ASPECT_RATIO_2_3";
- field public static final java.lang.String ASPECT_RATIO_3_2 = "ASPECT_RATIO_3_2";
- field public static final java.lang.String AVAILABILITY_AVAILABLE = "AVAILABILITY_AVAILABLE";
- field public static final java.lang.String AVAILABILITY_FREE_WITH_SUBSCRIPTION = "AVAILABILITY_FREE_WITH_SUBSCRIPTION";
- field public static final java.lang.String AVAILABILITY_PAID_CONTENT = "AVAILABILITY_PAID_CONTENT";
- field public static final java.lang.String COLUMN_APP_LINK_INTENT_URI = "app_link_intent_uri";
- field public static final java.lang.String COLUMN_AUTHOR = "author";
- field public static final java.lang.String COLUMN_AVAILABILITY = "availability";
- field public static final java.lang.String COLUMN_BROWSABLE = "browsable";
- field public static final java.lang.String COLUMN_DURATION_MILLIS = "duration_millis";
- field public static final java.lang.String COLUMN_INTERACTION_COUNT = "interaction_count";
- field public static final java.lang.String COLUMN_INTERACTION_TYPE = "interaction_type";
- field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_ID = "internal_provider_id";
- field public static final java.lang.String COLUMN_ITEM_COUNT = "item_count";
- field public static final java.lang.String COLUMN_LAST_PLAYBACK_POSITION_MILLIS = "last_playback_position_millis";
- field public static final java.lang.String COLUMN_LIVE = "live";
- field public static final java.lang.String COLUMN_LOGO_URI = "logo_uri";
- field public static final java.lang.String COLUMN_OFFER_PRICE = "offer_price";
- field public static final java.lang.String COLUMN_POSTER_ART_ASPECT_RATIO = "poster_art_aspect_ratio";
- field public static final java.lang.String COLUMN_PREVIEW_VIDEO_URI = "preview_video_uri";
- field public static final java.lang.String COLUMN_RELEASE_DATE = "release_date";
- field public static final java.lang.String COLUMN_REVIEW_RATING = "review_rating";
- field public static final java.lang.String COLUMN_REVIEW_RATING_STYLE = "review_rating_style";
- field public static final java.lang.String COLUMN_STARTING_PRICE = "starting_price";
- field public static final java.lang.String COLUMN_THUMBNAIL_ASPECT_RATIO = "poster_thumbnail_aspect_ratio";
- field public static final java.lang.String COLUMN_TYPE = "type";
- field public static final java.lang.String COLUMN_WATCH_NEXT_TYPE = "watch_next_type";
+ public static final class TvContract.PreviewPrograms implements android.media.tv.TvContract.BasePreviewProgramColumns {
+ field public static final java.lang.String COLUMN_CHANNEL_ID = "channel_id";
field public static final java.lang.String COLUMN_WEIGHT = "weight";
field public static final java.lang.String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/preview_program";
field public static final java.lang.String CONTENT_TYPE = "vnd.android.cursor.dir/preview_program";
field public static final android.net.Uri CONTENT_URI;
- field public static final java.lang.String INTERACTION_TYPE_FANS = "INTERACTION_TYPE_FANS";
- field public static final java.lang.String INTERACTION_TYPE_FOLLOWERS = "INTERACTION_TYPE_FOLLOWERS";
- field public static final java.lang.String INTERACTION_TYPE_LIKES = "INTERACTION_TYPE_LIKES";
- field public static final java.lang.String INTERACTION_TYPE_LISTENS = "INTERACTION_TYPE_LISTENS";
- field public static final java.lang.String INTERACTION_TYPE_THUMBS = "INTERACTION_TYPE_THUMBS";
- field public static final java.lang.String INTERACTION_TYPE_VIEWERS = "INTERACTION_TYPE_VIEWERS";
- field public static final java.lang.String INTERACTION_TYPE_VIEWS = "INTERACTION_TYPE_VIEWS";
- field public static final java.lang.String REVIEW_RATING_STYLE_PERCENTAGE = "REVIEW_RATING_STYLE_PERCENTAGE";
- field public static final java.lang.String REVIEW_RATING_STYLE_STARS = "REVIEW_RATING_STYLE_STARS";
- field public static final java.lang.String REVIEW_RATING_STYLE_THUMBS_UP_DOWN = "REVIEW_RATING_STYLE_THUMBS_UP_DOWN";
- field public static final java.lang.String TYPE_ALBUM = "TYPE_ALBUM";
- field public static final java.lang.String TYPE_ARTIST = "TYPE_ARTIST";
- field public static final java.lang.String TYPE_CHANNEL = "TYPE_CHANNEL";
- field public static final java.lang.String TYPE_CLIP = "TYPE_CLIP";
- field public static final java.lang.String TYPE_EVENT = "TYPE_EVENT";
- field public static final java.lang.String TYPE_MOVIE = "TYPE_MOVIE";
- field public static final java.lang.String TYPE_PLAYLIST = "TYPE_PLAYLIST";
- field public static final java.lang.String TYPE_STATION = "TYPE_STATION";
- field public static final java.lang.String TYPE_TRACK = "TYPE_TRACK";
- field public static final java.lang.String TYPE_TV_EPISODE = "TYPE_TV_EPISODE";
- field public static final java.lang.String TYPE_TV_SEASON = "TYPE_TV_SEASON";
- field public static final java.lang.String TYPE_TV_SERIES = "TYPE_TV_SERIES";
- field public static final java.lang.String WATCH_NEXT_TYPE_CONTINUE = "WATCH_NEXT_TYPE_CONTINUE";
- field public static final java.lang.String WATCH_NEXT_TYPE_NEW = "WATCH_NEXT_TYPE_NEW";
- field public static final java.lang.String WATCH_NEXT_TYPE_NEXT = "WATCH_NEXT_TYPE_NEXT";
}
public static final class TvContract.Programs implements android.media.tv.TvContract.BaseProgramColumns {
field public static final java.lang.String COLUMN_BROADCAST_GENRE = "broadcast_genre";
+ field public static final java.lang.String COLUMN_CHANNEL_ID = "channel_id";
field public static final java.lang.String COLUMN_END_TIME_UTC_MILLIS = "end_time_utc_millis";
field public static final deprecated java.lang.String COLUMN_EPISODE_NUMBER = "episode_number";
field public static final java.lang.String COLUMN_RECORDING_PROHIBITED = "recording_prohibited";
@@ -24294,6 +24459,7 @@
public static final class TvContract.RecordedPrograms implements android.media.tv.TvContract.BaseProgramColumns {
field public static final java.lang.String COLUMN_BROADCAST_GENRE = "broadcast_genre";
+ field public static final java.lang.String COLUMN_CHANNEL_ID = "channel_id";
field public static final java.lang.String COLUMN_END_TIME_UTC_MILLIS = "end_time_utc_millis";
field public static final java.lang.String COLUMN_INPUT_ID = "input_id";
field public static final java.lang.String COLUMN_RECORDING_DATA_BYTES = "recording_data_bytes";
@@ -24306,6 +24472,19 @@
field public static final android.net.Uri CONTENT_URI;
}
+ public static final class TvContract.WatchNextPrograms implements android.media.tv.TvContract.BasePreviewProgramColumns {
+ ctor public TvContract.WatchNextPrograms();
+ field public static final java.lang.String COLUMN_LAST_ENGAGEMENT_TIME_UTC_MILLIS = "last_engagement_time_utc_millis";
+ field public static final java.lang.String COLUMN_WATCH_NEXT_TYPE = "watch_next_type";
+ field public static final java.lang.String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/watch_next_program";
+ field public static final java.lang.String CONTENT_TYPE = "vnd.android.cursor.dir/watch_next_program";
+ field public static final android.net.Uri CONTENT_URI;
+ field public static final java.lang.String WATCH_NEXT_TYPE_CONTINUE = "WATCH_NEXT_TYPE_CONTINUE";
+ field public static final java.lang.String WATCH_NEXT_TYPE_NEW = "WATCH_NEXT_TYPE_NEW";
+ field public static final java.lang.String WATCH_NEXT_TYPE_NEXT = "WATCH_NEXT_TYPE_NEXT";
+ field public static final java.lang.String WATCH_NEXT_TYPE_WATCHLIST = "WATCH_NEXT_TYPE_WATCHLIST";
+ }
+
public final class TvInputInfo implements android.os.Parcelable {
method public boolean canRecord();
method public android.content.Intent createSettingsIntent();
@@ -24355,15 +24534,10 @@
method public void unregisterCallback(android.media.tv.TvInputManager.TvInputCallback);
method public void updateTvInputInfo(android.media.tv.TvInputInfo);
field public static final java.lang.String ACTION_BLOCKED_RATINGS_CHANGED = "android.media.tv.action.BLOCKED_RATINGS_CHANGED";
- field public static final java.lang.String ACTION_MAKE_CHANNEL_BROWSABLE = "android.media.tv.action.MAKE_CHANNEL_BROWSABLE";
field public static final java.lang.String ACTION_PARENTAL_CONTROLS_ENABLED_CHANGED = "android.media.tv.action.PARENTAL_CONTROLS_ENABLED_CHANGED";
- field public static final java.lang.String ACTION_PROGRAM_BROWSABLE_DISABLED = "android.media.tv.action.PROGRAM_BROWSABLE_DISABLED";
field public static final java.lang.String ACTION_QUERY_CONTENT_RATING_SYSTEMS = "android.media.tv.action.QUERY_CONTENT_RATING_SYSTEMS";
field public static final java.lang.String ACTION_SETUP_INPUTS = "android.media.tv.action.SETUP_INPUTS";
field public static final java.lang.String ACTION_VIEW_RECORDING_SCHEDULES = "android.media.tv.action.VIEW_RECORDING_SCHEDULES";
- field public static final java.lang.String EXTRA_CHANNEL_ID = "android.media.tv.extra.CHANNEL_ID";
- field public static final java.lang.String EXTRA_PACKAGE_NAME = "android.media.tv.extra.PACKAGE_NAME";
- field public static final java.lang.String EXTRA_PROGRAM_ID = "android.media.tv.extra.PROGRAM_ID";
field public static final int INPUT_STATE_CONNECTED = 0; // 0x0
field public static final int INPUT_STATE_CONNECTED_STANDBY = 1; // 0x1
field public static final int INPUT_STATE_DISCONNECTED = 2; // 0x2
@@ -24935,6 +25109,68 @@
field public static final android.os.Parcelable.Creator<android.net.IpPrefix> CREATOR;
}
+ public final class IpSecAlgorithm implements android.os.Parcelable {
+ ctor public IpSecAlgorithm(java.lang.String, byte[]);
+ ctor public IpSecAlgorithm(java.lang.String, byte[], int);
+ method public int describeContents();
+ method public byte[] getKey();
+ method public java.lang.String getName();
+ method public int getTruncationLengthBits();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final java.lang.String ALGO_AUTH_HMAC_MD5 = "hmac(md5)";
+ field public static final java.lang.String ALGO_AUTH_HMAC_SHA1 = "hmac(sha1)";
+ field public static final java.lang.String ALGO_AUTH_HMAC_SHA256 = "hmac(sha256)";
+ field public static final java.lang.String ALGO_AUTH_HMAC_SHA384 = "hmac(sha384)";
+ field public static final java.lang.String ALGO_AUTH_HMAC_SHA512 = "hmac(sha512)";
+ field public static final java.lang.String ALGO_CRYPT_AES_CBC = "cbc(aes)";
+ field public static final android.os.Parcelable.Creator<android.net.IpSecAlgorithm> CREATOR;
+ }
+
+ public final class IpSecManager {
+ method public void applyTransportModeTransform(java.net.Socket, android.net.IpSecTransform) throws java.io.IOException;
+ method public void applyTransportModeTransform(java.net.DatagramSocket, android.net.IpSecTransform) throws java.io.IOException;
+ method public android.net.IpSecManager.UdpEncapsulationSocket openUdpEncapsulationSocket(int) throws java.io.IOException, android.net.IpSecManager.ResourceUnavailableException;
+ method public android.net.IpSecManager.UdpEncapsulationSocket openUdpEncapsulationSocket() throws java.io.IOException, android.net.IpSecManager.ResourceUnavailableException;
+ method public void removeTransportModeTransform(java.net.Socket, android.net.IpSecTransform);
+ method public void removeTransportModeTransform(java.net.DatagramSocket, android.net.IpSecTransform);
+ method public android.net.IpSecManager.SecurityParameterIndex reserveSecurityParameterIndex(java.net.InetAddress, int) throws android.net.IpSecManager.ResourceUnavailableException, android.net.IpSecManager.SpiUnavailableException;
+ field public static final int INVALID_SECURITY_PARAMETER_INDEX = 0; // 0x0
+ }
+
+ public static final class IpSecManager.ResourceUnavailableException extends android.util.AndroidException {
+ }
+
+ public static final class IpSecManager.SecurityParameterIndex implements java.lang.AutoCloseable {
+ method public void close();
+ method public int getSpi();
+ }
+
+ public static final class IpSecManager.SpiUnavailableException extends android.util.AndroidException {
+ method public int getSpi();
+ }
+
+ public static final class IpSecManager.UdpEncapsulationSocket implements java.lang.AutoCloseable {
+ method public void close();
+ method public int getPort();
+ method public java.io.FileDescriptor getSocket();
+ }
+
+ public final class IpSecTransform implements java.lang.AutoCloseable {
+ method public void close();
+ field public static final int DIRECTION_IN = 0; // 0x0
+ field public static final int DIRECTION_OUT = 1; // 0x1
+ }
+
+ public static class IpSecTransform.Builder {
+ ctor public IpSecTransform.Builder(android.content.Context);
+ method public android.net.IpSecTransform buildTransportModeTransform(java.net.InetAddress) throws java.io.IOException, android.net.IpSecManager.ResourceUnavailableException, android.net.IpSecManager.SpiUnavailableException;
+ method public android.net.IpSecTransform.Builder setAuthentication(int, android.net.IpSecAlgorithm);
+ method public android.net.IpSecTransform.Builder setEncryption(int, android.net.IpSecAlgorithm);
+ method public android.net.IpSecTransform.Builder setIpv4Encapsulation(android.net.IpSecManager.UdpEncapsulationSocket, int);
+ method public android.net.IpSecTransform.Builder setSpi(int, int);
+ method public android.net.IpSecTransform.Builder setSpi(int, android.net.IpSecManager.SecurityParameterIndex);
+ }
+
public class LinkAddress implements android.os.Parcelable {
method public int describeContents();
method public java.net.InetAddress getAddress();
@@ -26115,8 +26351,6 @@
public class DiscoverySession {
method public java.lang.String createNetworkSpecifier(android.net.wifi.aware.PeerHandle, byte[]);
method public void destroy();
- method public static int getMaxSendRetryCount();
- method public void sendMessage(android.net.wifi.aware.PeerHandle, int, byte[], int);
method public void sendMessage(android.net.wifi.aware.PeerHandle, int, byte[]);
}
@@ -29987,7 +30221,7 @@
field public static final int BATTERY_PLUGGED_AC = 1; // 0x1
field public static final int BATTERY_PLUGGED_USB = 2; // 0x2
field public static final int BATTERY_PLUGGED_WIRELESS = 4; // 0x4
- field public static final int BATTERY_PROPERTY_BATTERY_STATUS = 6; // 0x6
+ field public static final int BATTERY_PROPERTY_STATUS = 6; // 0x6
field public static final int BATTERY_PROPERTY_CAPACITY = 4; // 0x4
field public static final int BATTERY_PROPERTY_CHARGE_COUNTER = 1; // 0x1
field public static final int BATTERY_PROPERTY_CURRENT_AVERAGE = 3; // 0x3
@@ -36404,10 +36638,10 @@
public static final class FillResponse.Builder {
ctor public FillResponse.Builder();
method public android.service.autofill.FillResponse.Builder addDataset(android.service.autofill.Dataset);
- method public android.service.autofill.FillResponse.Builder addSavableFields(android.view.autofill.AutoFillId...);
method public android.service.autofill.FillResponse build();
method public android.service.autofill.FillResponse.Builder setAuthentication(android.content.IntentSender, android.widget.RemoteViews);
method public android.service.autofill.FillResponse.Builder setExtras(android.os.Bundle);
+ method public android.service.autofill.FillResponse.Builder setSaveInfo(android.service.autofill.SaveInfo);
}
public final class SaveCallback {
@@ -36415,6 +36649,23 @@
method public void onSuccess();
}
+ public final class SaveInfo implements android.os.Parcelable {
+ method public int describeContents();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.service.autofill.SaveInfo> CREATOR;
+ field public static final int SAVE_DATA_TYPE_ADDRESS = 2; // 0x2
+ field public static final int SAVE_DATA_TYPE_CREDIT_CARD = 3; // 0x3
+ field public static final int SAVE_DATA_TYPE_GENERIC = 0; // 0x0
+ field public static final int SAVE_DATA_TYPE_PASSWORD = 1; // 0x1
+ }
+
+ public static final class SaveInfo.Builder {
+ ctor public SaveInfo.Builder(int);
+ method public android.service.autofill.SaveInfo.Builder addSavableIds(android.view.autofill.AutoFillId...);
+ method public android.service.autofill.SaveInfo build();
+ method public android.service.autofill.SaveInfo.Builder setDescription(java.lang.CharSequence);
+ }
+
}
package android.service.carrier {
@@ -38177,9 +38428,6 @@
field public static final int RTT_MODE_VCO = 3; // 0x3
}
- public static abstract class Call.RttCall.RttAudioMode implements java.lang.annotation.Annotation {
- }
-
public final class CallAudioState implements android.os.Parcelable {
ctor public CallAudioState(boolean, int, int);
method public static java.lang.String audioRouteToString(int);
@@ -38720,6 +38968,8 @@
}
public class TelecomManager {
+ method public void acceptRingingCall();
+ method public void acceptRingingCall(int);
method public void addNewIncomingCall(android.telecom.PhoneAccountHandle, android.os.Bundle);
method public void cancelMissedCallsNotification();
method public android.content.Intent createManageBlockedNumbersIntent();
@@ -40340,7 +40590,7 @@
package android.test.suitebuilder {
- public class TestMethod {
+ public deprecated class TestMethod {
ctor public TestMethod(java.lang.reflect.Method, java.lang.Class<? extends junit.framework.TestCase>);
ctor public TestMethod(java.lang.String, java.lang.Class<? extends junit.framework.TestCase>);
ctor public TestMethod(junit.framework.TestCase);
@@ -40351,7 +40601,7 @@
method public java.lang.String getName();
}
- public class TestSuiteBuilder {
+ public deprecated class TestSuiteBuilder {
ctor public TestSuiteBuilder(java.lang.Class);
ctor public TestSuiteBuilder(java.lang.String, java.lang.ClassLoader);
method public android.test.suitebuilder.TestSuiteBuilder addRequirements(java.util.List<com.android.internal.util.Predicate<android.test.suitebuilder.TestMethod>>);
@@ -40364,7 +40614,7 @@
method public android.test.suitebuilder.TestSuiteBuilder named(java.lang.String);
}
- public static class TestSuiteBuilder.FailedToCreateTests extends junit.framework.TestCase {
+ public static deprecated class TestSuiteBuilder.FailedToCreateTests extends junit.framework.TestCase {
ctor public TestSuiteBuilder.FailedToCreateTests(java.lang.Exception);
method public void testSuiteConstructionFailed();
}
@@ -42580,30 +42830,51 @@
method public abstract void setValue(T, float);
}
- public final class Half {
+ public final class Half extends java.lang.Number implements java.lang.Comparable {
+ ctor public Half(short);
+ ctor public Half(float);
+ ctor public Half(double);
+ ctor public Half(java.lang.String) throws java.lang.NumberFormatException;
method public static short abs(short);
method public static short ceil(short);
+ method public static int compare(short, short);
+ method public int compareTo(android.util.Half);
method public static short copySign(short, short);
+ method public double doubleValue();
method public static boolean equals(short, short);
+ method public float floatValue();
method public static short floor(short);
method public static int getExponent(short);
method public static int getSign(short);
method public static int getSignificand(short);
method public static boolean greater(short, short);
method public static boolean greaterEquals(short, short);
+ method public static int halfToIntBits(short);
+ method public static int halfToRawIntBits(short);
+ method public static short halfToShortBits(short);
+ method public short halfValue();
+ method public static int hashCode(short);
+ method public static short intBitsToHalf(int);
+ method public int intValue();
method public static boolean isInfinite(short);
+ method public boolean isNaN();
method public static boolean isNaN(short);
method public static boolean isNormalized(short);
method public static boolean less(short, short);
method public static boolean lessEquals(short, short);
+ method public long longValue();
method public static short max(short, short);
method public static short min(short, short);
+ method public static short parseHalf(java.lang.String) throws java.lang.NumberFormatException;
method public static short round(short);
method public static float toFloat(short);
+ method public static short toHalf(float);
method public static java.lang.String toHexString(short);
method public static java.lang.String toString(short);
method public static short trunc(short);
- method public static short valueOf(float);
+ method public static android.util.Half valueOf(short);
+ method public static android.util.Half valueOf(float);
+ method public static android.util.Half valueOf(java.lang.String);
field public static final short EPSILON = 5120; // 0x1400
field public static final short LOWEST_VALUE = -1025; // 0xfffffbff
field public static final int MAX_EXPONENT = 15; // 0xf
@@ -43492,11 +43763,13 @@
field public static final int DRAW_DURATION = 4; // 0x4
field public static final int FIRST_DRAW_FRAME = 9; // 0x9
field public static final int INPUT_HANDLING_DURATION = 1; // 0x1
+ field public static final int INTENDED_VSYNC_TIMESTAMP = 10; // 0xa
field public static final int LAYOUT_MEASURE_DURATION = 3; // 0x3
field public static final int SWAP_BUFFERS_DURATION = 7; // 0x7
field public static final int SYNC_DURATION = 5; // 0x5
field public static final int TOTAL_DURATION = 8; // 0x8
field public static final int UNKNOWN_DELAY_DURATION = 0; // 0x0
+ field public static final int VSYNC_TIMESTAMP = 11; // 0xb
}
public abstract class FrameStats {
@@ -44871,8 +45144,8 @@
method public void drawableHotspotChanged(float, float);
method protected void drawableStateChanged();
method public android.view.View findFocus();
- method public final android.view.View findViewById(int);
- method public final android.view.View findViewWithTag(java.lang.Object);
+ method public final <T extends android.view.View> T findViewById(int);
+ method public final <T extends android.view.View> T findViewWithTag(java.lang.Object);
method public void findViewsWithText(java.util.ArrayList<android.view.View>, java.lang.CharSequence, int);
method protected deprecated boolean fitSystemWindows(android.graphics.Rect);
method public android.view.View focusSearch(int);
@@ -46004,6 +46277,7 @@
method public abstract void setAccessibilityFocused(boolean);
method public abstract void setActivated(boolean);
method public abstract void setAlpha(float);
+ method public abstract void setAutoFillOptions(java.lang.String[]);
method public abstract void setAutoFillType(android.view.autofill.AutoFillType);
method public abstract void setAutoFillValue(android.view.autofill.AutoFillValue);
method public abstract void setCheckable(boolean);
@@ -51203,6 +51477,8 @@
method public int resolveAdjustedSize(int, int);
method public void resume();
method public void seekTo(int);
+ method public void setAudioAttributes(android.media.AudioAttributes);
+ method public void setAudioFocusRequest(int);
method public void setMediaController(android.widget.MediaController);
method public void setOnCompletionListener(android.media.MediaPlayer.OnCompletionListener);
method public void setOnErrorListener(android.media.MediaPlayer.OnErrorListener);
@@ -51307,7 +51583,7 @@
package com.android.internal.util {
- public abstract interface Predicate<T> {
+ public abstract deprecated interface Predicate<T> {
method public abstract boolean apply(T);
}
diff --git a/api/test-removed.txt b/api/test-removed.txt
index e467811..c5dbf8d 100644
--- a/api/test-removed.txt
+++ b/api/test-removed.txt
@@ -20,25 +20,14 @@
package android.content {
public abstract class Context {
- method public deprecated android.content.Context createCredentialEncryptedStorageContext();
- method public deprecated android.content.Context createDeviceEncryptedStorageContext();
method public abstract android.content.SharedPreferences getSharedPreferences(java.io.File, int);
method public abstract java.io.File getSharedPreferencesPath(java.lang.String);
- method public deprecated boolean isCredentialEncryptedStorage();
- method public deprecated boolean isDeviceEncryptedStorage();
- method public deprecated boolean migrateDatabaseFrom(android.content.Context, java.lang.String);
- method public deprecated boolean migrateSharedPreferencesFrom(android.content.Context, java.lang.String);
}
}
package android.content.pm {
- public class ApplicationInfo extends android.content.pm.PackageItemInfo implements android.os.Parcelable {
- field public deprecated java.lang.String credentialEncryptedDataDir;
- field public deprecated java.lang.String deviceEncryptedDataDir;
- }
-
public class ComponentInfo extends android.content.pm.PackageItemInfo {
field public deprecated boolean encryptionAware;
}
@@ -47,12 +36,6 @@
field public static final int REQUESTED_PERMISSION_REQUIRED = 1; // 0x1
}
- public abstract class PackageManager {
- field public static final deprecated int MATCH_ENCRYPTION_AWARE = 524288; // 0x80000
- field public static final deprecated int MATCH_ENCRYPTION_AWARE_AND_UNAWARE = 786432; // 0xc0000
- field public static final deprecated int MATCH_ENCRYPTION_UNAWARE = 262144; // 0x40000
- }
-
}
package android.database {
@@ -169,10 +152,6 @@
method public android.graphics.drawable.Drawable getBadgedDrawableForUser(android.graphics.drawable.Drawable, android.os.UserHandle, android.graphics.Rect, int);
method public android.graphics.drawable.Drawable getBadgedIconForUser(android.graphics.drawable.Drawable, android.os.UserHandle);
method public java.lang.CharSequence getBadgedLabelForUser(java.lang.CharSequence, android.os.UserHandle);
- method public deprecated boolean isUserRunningAndLocked();
- method public deprecated boolean isUserRunningAndLocked(android.os.UserHandle);
- method public deprecated boolean isUserRunningAndUnlocked();
- method public deprecated boolean isUserRunningAndUnlocked(android.os.UserHandle);
}
}
@@ -190,15 +169,6 @@
}
-package android.preference {
-
- public class PreferenceManager {
- method public deprecated void setStorageCredentialEncrypted();
- method public deprecated void setStorageDeviceEncrypted();
- }
-
-}
-
package android.provider {
public class Browser {
diff --git a/cmds/idmap/Android.mk b/cmds/idmap/Android.mk
index 50ccb07..eb6da18e 100644
--- a/cmds/idmap/Android.mk
+++ b/cmds/idmap/Android.mk
@@ -15,7 +15,7 @@
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
-LOCAL_SRC_FILES := idmap.cpp create.cpp scan.cpp inspect.cpp
+LOCAL_SRC_FILES := idmap.cpp create.cpp inspect.cpp
LOCAL_SHARED_LIBRARIES := liblog libutils libandroidfw
diff --git a/cmds/idmap/idmap.cpp b/cmds/idmap/idmap.cpp
index 3ab1915..d388977 100644
--- a/cmds/idmap/idmap.cpp
+++ b/cmds/idmap/idmap.cpp
@@ -13,8 +13,6 @@
idmap --help \n\
idmap --fd target overlay fd \n\
idmap --path target overlay idmap \n\
- idmap --scan target-package-name-to-look-for path-to-target-apk dir-to-hold-idmaps \\\
- dir-to-scan [additional-dir-to-scan [additional-dir-to-scan [...]]]\n\
idmap --inspect idmap \n\
\n\
DESCRIPTION \n\
@@ -49,11 +47,6 @@
--path: create idmap for target package 'target' (path to apk) and overlay package \n\
'overlay' (path to apk); write results to 'idmap' (path). \n\
\n\
- --scan: non-recursively search directory 'dir-to-scan' (path) for overlay packages with \n\
- target package 'target-package-name-to-look-for' (package name) present at\n\
- 'path-to-target-apk' (path to apk). For each overlay package found, create an\n\
- idmap file in 'dir-to-hold-idmaps' (path). \n\
-\n\
--inspect: decode the binary format of 'idmap' (path) and display the contents in a \n\
debug-friendly format. \n\
\n\
@@ -97,16 +90,6 @@
NOTES \n\
This tool and its expected invocation from installd is modelled on dexopt.";
- bool verify_directory_readable(const char *path)
- {
- return access(path, R_OK | X_OK) == 0;
- }
-
- bool verify_directory_writable(const char *path)
- {
- return access(path, W_OK) == 0;
- }
-
bool verify_file_readable(const char *path)
{
return access(path, R_OK) == 0;
@@ -167,36 +150,6 @@
return idmap_create_path(target_apk_path, overlay_apk_path, idmap_path);
}
- int maybe_scan(const char *target_package_name, const char *target_apk_path,
- const char *idmap_dir, const android::Vector<const char *> *overlay_dirs)
- {
- if (!verify_root_or_system()) {
- fprintf(stderr, "error: permission denied: not user root or user system\n");
- return -1;
- }
-
- if (!verify_file_readable(target_apk_path)) {
- ALOGD("error: failed to read apk %s: %s\n", target_apk_path, strerror(errno));
- return -1;
- }
-
- if (!verify_directory_writable(idmap_dir)) {
- ALOGD("error: no write access to %s: %s\n", idmap_dir, strerror(errno));
- return -1;
- }
-
- const size_t N = overlay_dirs->size();
- for (size_t i = 0; i < N; i++) {
- const char *dir = overlay_dirs->itemAt(i);
- if (!verify_directory_readable(dir)) {
- ALOGD("error: no read access to %s: %s\n", dir, strerror(errno));
- return -1;
- }
- }
-
- return idmap_scan(target_package_name, target_apk_path, idmap_dir, overlay_dirs);
- }
-
int maybe_inspect(const char *idmap_path)
{
// anyone (not just root or system) may do --inspect
@@ -235,14 +188,6 @@
return maybe_create_path(argv[2], argv[3], argv[4]);
}
- if (argc >= 6 && !strcmp(argv[1], "--scan")) {
- android::Vector<const char *> v;
- for (int i = 5; i < argc; i++) {
- v.push(argv[i]);
- }
- return maybe_scan(argv[2], argv[3], argv[4], &v);
- }
-
if (argc == 3 && !strcmp(argv[1], "--inspect")) {
return maybe_inspect(argv[2]);
}
diff --git a/cmds/idmap/idmap.h b/cmds/idmap/idmap.h
index 8d4210b..5914de9 100644
--- a/cmds/idmap/idmap.h
+++ b/cmds/idmap/idmap.h
@@ -25,12 +25,6 @@
int idmap_create_fd(const char *target_apk_path, const char *overlay_apk_path, int fd);
-// Regarding target_package_name: the idmap_scan implementation should
-// be able to extract this from the manifest in target_apk_path,
-// simplifying the external API.
-int idmap_scan(const char *target_package_name, const char *target_apk_path,
- const char *idmap_dir, const android::Vector<const char *> *overlay_dirs);
-
int idmap_inspect(const char *idmap_path);
#endif // _IDMAP_H_
diff --git a/cmds/idmap/scan.cpp b/cmds/idmap/scan.cpp
deleted file mode 100644
index ab6adfb..0000000
--- a/cmds/idmap/scan.cpp
+++ /dev/null
@@ -1,239 +0,0 @@
-#include <dirent.h>
-#include <inttypes.h>
-#include <sys/file.h>
-#include <sys/stat.h>
-
-#include "idmap.h"
-
-#include <memory>
-#include <androidfw/ResourceTypes.h>
-#include <androidfw/StreamingZipInflater.h>
-#include <androidfw/ZipFileRO.h>
-#include <private/android_filesystem_config.h> // for AID_SYSTEM
-#include <utils/SortedVector.h>
-#include <utils/String16.h>
-#include <utils/String8.h>
-
-#define NO_OVERLAY_TAG (-1000)
-
-using namespace android;
-
-namespace {
- struct Overlay {
- Overlay() {}
- Overlay(const String8& a, const String8& i, int p) :
- apk_path(a), idmap_path(i), priority(p) {}
-
- bool operator<(Overlay const& rhs) const
- {
- return rhs.priority > priority;
- }
-
- String8 apk_path;
- String8 idmap_path;
- int priority;
- };
-
- bool writePackagesList(const char *filename, const SortedVector<Overlay>& overlayVector)
- {
- // the file is opened for appending so that it doesn't get truncated
- // before we can guarantee mutual exclusion via the flock
- FILE* fout = fopen(filename, "a");
- if (fout == NULL) {
- return false;
- }
-
- if (TEMP_FAILURE_RETRY(flock(fileno(fout), LOCK_EX)) != 0) {
- fclose(fout);
- return false;
- }
-
- if (TEMP_FAILURE_RETRY(ftruncate(fileno(fout), 0)) != 0) {
- TEMP_FAILURE_RETRY(flock(fileno(fout), LOCK_UN));
- fclose(fout);
- return false;
- }
-
- for (size_t i = 0; i < overlayVector.size(); ++i) {
- const Overlay& overlay = overlayVector[i];
- fprintf(fout, "%s %s\n", overlay.apk_path.string(), overlay.idmap_path.string());
- }
-
- TEMP_FAILURE_RETRY(fflush(fout));
- TEMP_FAILURE_RETRY(flock(fileno(fout), LOCK_UN));
- fclose(fout);
-
- // Make file world readable since Zygote (running as root) will read
- // it when creating the initial AssetManger object
- const mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH; // 0644
- if (chmod(filename, mode) == -1) {
- unlink(filename);
- return false;
- }
-
- return true;
- }
-
- String8 flatten_path(const char *path)
- {
- String16 tmp(path);
- tmp.replaceAll('/', '@');
- return String8(tmp);
- }
-
- int parse_overlay_tag(const ResXMLTree& parser, const char *target_package_name)
- {
- const size_t N = parser.getAttributeCount();
- String16 target;
- int priority = -1;
- for (size_t i = 0; i < N; ++i) {
- size_t len;
- String16 key(parser.getAttributeName(i, &len));
- if (key == String16("targetPackage")) {
- const char16_t *p = parser.getAttributeStringValue(i, &len);
- if (p != NULL) {
- target = String16(p, len);
- }
- } else if (key == String16("priority")) {
- Res_value v;
- if (parser.getAttributeValue(i, &v) == sizeof(Res_value)) {
- priority = v.data;
- if (priority < 0 || priority > 9999) {
- return -1;
- }
- }
- }
- }
- if (target == String16(target_package_name)) {
- return priority;
- }
- return NO_OVERLAY_TAG;
- }
-
- int parse_manifest(const void *data, size_t size, const char *target_package_name)
- {
- ResXMLTree parser;
- parser.setTo(data, size);
- if (parser.getError() != NO_ERROR) {
- ALOGD("%s failed to init xml parser, error=0x%08x\n", __FUNCTION__, parser.getError());
- return -1;
- }
-
- ResXMLParser::event_code_t type;
- do {
- type = parser.next();
- if (type == ResXMLParser::START_TAG) {
- size_t len;
- String16 tag(parser.getElementName(&len));
- if (tag == String16("overlay")) {
- return parse_overlay_tag(parser, target_package_name);
- }
- }
- } while (type != ResXMLParser::BAD_DOCUMENT && type != ResXMLParser::END_DOCUMENT);
-
- return NO_OVERLAY_TAG;
- }
-
- int parse_apk(const char *path, const char *target_package_name)
- {
- std::unique_ptr<ZipFileRO> zip(ZipFileRO::open(path));
- if (zip.get() == NULL) {
- ALOGW("%s: failed to open zip %s\n", __FUNCTION__, path);
- return -1;
- }
- ZipEntryRO entry;
- if ((entry = zip->findEntryByName("AndroidManifest.xml")) == NULL) {
- ALOGW("%s: failed to find entry AndroidManifest.xml\n", __FUNCTION__);
- return -1;
- }
- uint32_t uncompLen = 0;
- uint16_t method;
- if (!zip->getEntryInfo(entry, &method, &uncompLen, NULL, NULL, NULL, NULL)) {
- ALOGW("%s: failed to read entry info\n", __FUNCTION__);
- return -1;
- }
- if (method != ZipFileRO::kCompressDeflated) {
- ALOGW("%s: cannot handle zip compression method %" PRIu16 "\n", __FUNCTION__, method);
- return -1;
- }
- FileMap *dataMap = zip->createEntryFileMap(entry);
- if (dataMap == NULL) {
- ALOGW("%s: failed to create FileMap\n", __FUNCTION__);
- return -1;
- }
- char *buf = new char[uncompLen];
- if (NULL == buf) {
- ALOGW("%s: failed to allocate %" PRIu32 " byte\n", __FUNCTION__, uncompLen);
- delete dataMap;
- return -1;
- }
- StreamingZipInflater inflater(dataMap, uncompLen);
- if (inflater.read(buf, uncompLen) < 0) {
- ALOGW("%s: failed to inflate %" PRIu32 " byte\n", __FUNCTION__, uncompLen);
- delete[] buf;
- delete dataMap;
- return -1;
- }
-
- int priority = parse_manifest(buf, static_cast<size_t>(uncompLen), target_package_name);
- delete[] buf;
- delete dataMap;
- return priority;
- }
-}
-
-int idmap_scan(const char *target_package_name, const char *target_apk_path,
- const char *idmap_dir, const android::Vector<const char *> *overlay_dirs)
-{
- String8 filename = String8(idmap_dir);
- filename.appendPath("overlays.list");
-
- SortedVector<Overlay> overlayVector;
- const size_t N = overlay_dirs->size();
- for (size_t i = 0; i < N; ++i) {
- const char *overlay_dir = overlay_dirs->itemAt(i);
- DIR *dir = opendir(overlay_dir);
- if (dir == NULL) {
- return EXIT_FAILURE;
- }
-
- struct dirent *dirent;
- while ((dirent = readdir(dir)) != NULL) {
- struct stat st;
- char overlay_apk_path[PATH_MAX + 1];
- snprintf(overlay_apk_path, PATH_MAX, "%s/%s", overlay_dir, dirent->d_name);
- if (stat(overlay_apk_path, &st) < 0) {
- continue;
- }
- if (!S_ISREG(st.st_mode)) {
- continue;
- }
-
- int priority = parse_apk(overlay_apk_path, target_package_name);
- if (priority < 0) {
- continue;
- }
-
- String8 idmap_path(idmap_dir);
- idmap_path.appendPath(flatten_path(overlay_apk_path + 1));
- idmap_path.append("@idmap");
-
- if (idmap_create_path(target_apk_path, overlay_apk_path, idmap_path.string()) != 0) {
- ALOGE("error: failed to create idmap for target=%s overlay=%s idmap=%s\n",
- target_apk_path, overlay_apk_path, idmap_path.string());
- continue;
- }
-
- Overlay overlay(String8(overlay_apk_path), idmap_path, priority);
- overlayVector.add(overlay);
- }
-
- closedir(dir);
- }
-
- if (!writePackagesList(filename.string(), overlayVector)) {
- return EXIT_FAILURE;
- }
-
- return EXIT_SUCCESS;
-}
diff --git a/cmds/pm/src/com/android/commands/pm/Pm.java b/cmds/pm/src/com/android/commands/pm/Pm.java
index 1aef363..91520f1 100644
--- a/cmds/pm/src/com/android/commands/pm/Pm.java
+++ b/cmds/pm/src/com/android/commands/pm/Pm.java
@@ -547,6 +547,12 @@
throw new IllegalArgumentException("Missing inherit package name");
}
break;
+ case "--pkg":
+ sessionParams.appPackageName = nextOptionData();
+ if (sessionParams.appPackageName == null) {
+ throw new IllegalArgumentException("Missing package name");
+ }
+ break;
case "-S":
final long sizeBytes = Long.parseLong(nextOptionData());
if (sizeBytes <= 0) {
diff --git a/core/java/android/annotation/HalfFloat.java b/core/java/android/annotation/HalfFloat.java
index d3e9f08..256008c 100644
--- a/core/java/android/annotation/HalfFloat.java
+++ b/core/java/android/annotation/HalfFloat.java
@@ -37,7 +37,7 @@
* }</pre>
*
* @see android.util.Half
- * @see android.util.Half#valueOf(float)
+ * @see android.util.Half#toHalf(float)
* @see android.util.Half#toFloat(short)
*
* @hide
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index a820da4..0193c5f 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -2822,7 +2822,9 @@
return;
}
- if (!mFragments.getFragmentManager().popBackStackImmediate()) {
+ FragmentManager fragmentManager = mFragments.getFragmentManager();
+
+ if (fragmentManager.isStateSaved() || !fragmentManager.popBackStackImmediate()) {
finishAfterTransition();
}
}
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 7ff11ec..ce9d91f 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -2773,7 +2773,7 @@
for (int id : dm.getDisplayIds()) {
if (id != Display.DEFAULT_DISPLAY) {
Display display =
- dm.getCompatibleDisplay(id, appContext.getDisplayAdjustments(id));
+ dm.getCompatibleDisplay(id, appContext.getResources());
appContext = (ContextImpl) appContext.createDisplayContext(display);
break;
}
@@ -4970,7 +4970,7 @@
LoadedApk apk = ref != null ? ref.get() : null;
if (apk != null) {
final ArrayList<String> oldPaths = new ArrayList<>();
- LoadedApk.makePaths(this, apk.getApplicationInfo(), oldPaths, null /*outLibPaths*/);
+ LoadedApk.makePaths(this, apk.getApplicationInfo(), oldPaths);
apk.updateApplicationInfo(ai, oldPaths);
}
@@ -4978,7 +4978,7 @@
apk = ref != null ? ref.get() : null;
if (apk != null) {
final ArrayList<String> oldPaths = new ArrayList<>();
- LoadedApk.makePaths(this, apk.getApplicationInfo(), oldPaths, null /*outLibPaths*/);
+ LoadedApk.makePaths(this, apk.getApplicationInfo(), oldPaths);
apk.updateApplicationInfo(ai, oldPaths);
}
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index 6dd31a8..0f2ce3c 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -249,8 +249,10 @@
public static final int OP_ENTER_PICTURE_IN_PICTURE_ON_HIDE = 67;
/** @hide Instant app start foreground service. */
public static final int OP_INSTANT_APP_START_FOREGROUND = 68;
+ /** @hide Answer incoming phone calls */
+ public static final int OP_ANSWER_PHONE_CALLS = 69;
/** @hide */
- public static final int _NUM_OP = 69;
+ public static final int _NUM_OP = 70;
/** Access to coarse location information. */
public static final String OPSTR_COARSE_LOCATION = "android:coarse_location";
@@ -356,6 +358,9 @@
/** @hide */
public static final String OPSTR_INSTANT_APP_START_FOREGROUND
= "android:instant_app_start_foreground";
+ /** Answer incoming phone calls */
+ public static final String OPSTR_ANSWER_PHONE_CALLS
+ = "android:answer_phone_calls";
private static final int[] RUNTIME_AND_APPOP_PERMISSIONS_OPS = {
// RUNTIME PERMISSIONS
@@ -388,6 +393,7 @@
OP_ADD_VOICEMAIL,
OP_USE_SIP,
OP_PROCESS_OUTGOING_CALLS,
+ OP_ANSWER_PHONE_CALLS,
// Microphone
OP_RECORD_AUDIO,
// Camera
@@ -480,6 +486,7 @@
OP_REQUEST_INSTALL_PACKAGES,
OP_ENTER_PICTURE_IN_PICTURE_ON_HIDE,
OP_INSTANT_APP_START_FOREGROUND,
+ OP_ANSWER_PHONE_CALLS
};
/**
@@ -556,6 +563,7 @@
null, // OP_REQUEST_INSTALL_PACKAGES
null,
OPSTR_INSTANT_APP_START_FOREGROUND,
+ OPSTR_ANSWER_PHONE_CALLS,
};
/**
@@ -632,6 +640,7 @@
"REQUEST_INSTALL_PACKAGES",
"OP_ENTER_PICTURE_IN_PICTURE_ON_HIDE",
"INSTANT_APP_START_FOREGROUND",
+ "ANSWER_PHONE_CALLS",
};
/**
@@ -708,6 +717,7 @@
Manifest.permission.REQUEST_INSTALL_PACKAGES,
null, // no permission for entering picture-in-picture on hide
Manifest.permission.INSTANT_APP_FOREGROUND_SERVICE,
+ Manifest.permission.ANSWER_PHONE_CALLS,
};
/**
@@ -785,6 +795,7 @@
null, // REQUEST_INSTALL_PACKAGES
null, // ENTER_PICTURE_IN_PICTURE_ON_HIDE
null, // INSTANT_APP_START_FOREGROUND
+ null, // ANSWER_PHONE_CALLS
};
/**
@@ -861,6 +872,7 @@
false, // REQUEST_INSTALL_PACKAGES
false, // ENTER_PICTURE_IN_PICTURE_ON_HIDE
false, // INSTANT_APP_START_FOREGROUND
+ false, // ANSWER_PHONE_CALLS
};
/**
@@ -936,6 +948,7 @@
AppOpsManager.MODE_DEFAULT, // OP_REQUEST_INSTALL_PACKAGES
AppOpsManager.MODE_ALLOWED, // OP_ENTER_PICTURE_IN_PICTURE_ON_HIDE
AppOpsManager.MODE_DEFAULT, // OP_INSTANT_APP_START_FOREGROUND
+ AppOpsManager.MODE_ALLOWED, // ANSWER_PHONE_CALLS
};
/**
@@ -1015,6 +1028,7 @@
false, // OP_REQUEST_INSTALL_PACKAGES
false, // OP_ENTER_PICTURE_IN_PICTURE_ON_HIDE
false,
+ false, // ANSWER_PHONE_CALLS
};
/**
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index 1652299..0608acb 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -1024,12 +1024,18 @@
}
@Override
- @SuppressWarnings("unchecked")
public List<ProviderInfo> queryContentProviders(String processName,
int uid, int flags) {
+ return queryContentProviders(processName, uid, flags, null);
+ }
+
+ @Override
+ @SuppressWarnings("unchecked")
+ public List<ProviderInfo> queryContentProviders(String processName,
+ int uid, int flags, String metaDataKey) {
try {
ParceledListSlice<ProviderInfo> slice =
- mPM.queryContentProviders(processName, uid, flags);
+ mPM.queryContentProviders(processName, uid, flags, metaDataKey);
return slice != null ? slice.getList() : Collections.<ProviderInfo>emptyList();
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 045bd0a..7ee93d0 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -38,6 +38,7 @@
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.res.AssetManager;
+import android.content.res.CompatResources;
import android.content.res.CompatibilityInfo;
import android.content.res.Configuration;
import android.content.res.Resources;
@@ -49,6 +50,7 @@
import android.net.Uri;
import android.os.Binder;
import android.os.Build;
+import android.os.Build.VERSION_CODES;
import android.os.Bundle;
import android.os.Debug;
import android.os.Environment;
@@ -1925,8 +1927,8 @@
final int displayId = mDisplay != null
? mDisplay.getDisplayId() : Display.DEFAULT_DISPLAY;
- c.mResources = createResources(mActivityToken, pi, displayId, null,
- getDisplayAdjustments(displayId).getCompatibilityInfo());
+ c.setResources(createResources(mActivityToken, pi, displayId, null,
+ getDisplayAdjustments(displayId).getCompatibilityInfo()));
if (c.mResources != null) {
return c;
}
@@ -1962,8 +1964,8 @@
final int displayId = mDisplay != null
? mDisplay.getDisplayId() : Display.DEFAULT_DISPLAY;
- c.mResources = createResources(mActivityToken, pi, displayId, null,
- getDisplayAdjustments(displayId).getCompatibilityInfo());
+ c.setResources(createResources(mActivityToken, pi, displayId, null,
+ getDisplayAdjustments(displayId).getCompatibilityInfo()));
if (c.mResources != null) {
return c;
}
@@ -1990,7 +1992,7 @@
final int displayId = mDisplay != null
? mDisplay.getDisplayId() : Display.DEFAULT_DISPLAY;
- context.mResources = ResourcesManager.getInstance().getResources(
+ context.setResources(ResourcesManager.getInstance().getResources(
mActivityToken,
mPackageInfo.getResDir(),
paths,
@@ -1999,7 +2001,7 @@
displayId,
null,
mPackageInfo.getCompatibilityInfo(),
- classLoader);
+ classLoader));
return context;
}
@@ -2013,8 +2015,8 @@
mUser, mFlags, mClassLoader);
final int displayId = mDisplay != null ? mDisplay.getDisplayId() : Display.DEFAULT_DISPLAY;
- context.mResources = createResources(mActivityToken, mPackageInfo, displayId,
- overrideConfiguration, getDisplayAdjustments(displayId).getCompatibilityInfo());
+ context.setResources(createResources(mActivityToken, mPackageInfo, displayId,
+ overrideConfiguration, getDisplayAdjustments(displayId).getCompatibilityInfo()));
return context;
}
@@ -2028,8 +2030,8 @@
mUser, mFlags, mClassLoader);
final int displayId = display.getDisplayId();
- context.mResources = createResources(mActivityToken, mPackageInfo, displayId, null,
- getDisplayAdjustments(displayId).getCompatibilityInfo());
+ context.setResources(createResources(mActivityToken, mPackageInfo, displayId, null,
+ getDisplayAdjustments(displayId).getCompatibilityInfo()));
context.mDisplay = display;
return context;
}
@@ -2067,24 +2069,17 @@
@Override
public Display getDisplay() {
- final DisplayAdjustments displayAdjustments = mResources.getDisplayAdjustments();
if (mDisplay == null) {
return mResourcesManager.getAdjustedDisplay(Display.DEFAULT_DISPLAY,
- displayAdjustments);
+ mResources);
}
- if (!mDisplay.getDisplayAdjustments().equals(displayAdjustments)) {
- mDisplay = mResourcesManager.getAdjustedDisplay(mDisplay.getDisplayId(),
- displayAdjustments);
- }
return mDisplay;
}
@Override
public void updateDisplay(int displayId) {
- final DisplayAdjustments displayAdjustments = mResources.getDisplayAdjustments();
- mDisplay = mResourcesManager.getAdjustedDisplay(displayId,
- displayAdjustments);
+ mDisplay = mResourcesManager.getAdjustedDisplay(displayId, mResources);
}
@Override
@@ -2143,7 +2138,7 @@
LoadedApk packageInfo = new LoadedApk(mainThread);
ContextImpl context = new ContextImpl(null, mainThread, packageInfo, null, null, 0,
null);
- context.mResources = packageInfo.getResources();
+ context.setResources(packageInfo.getResources());
context.mResources.updateConfiguration(context.mResourcesManager.getConfiguration(),
context.mResourcesManager.getDisplayMetrics());
return context;
@@ -2153,7 +2148,7 @@
if (packageInfo == null) throw new IllegalArgumentException("packageInfo");
ContextImpl context = new ContextImpl(null, mainThread, packageInfo, null, null, 0,
null);
- context.mResources = packageInfo.getResources();
+ context.setResources(packageInfo.getResources());
return context;
}
@@ -2192,7 +2187,7 @@
// Create the base resources for which all configuration contexts for this Activity
// will be rebased upon.
- context.mResources = resourcesManager.createBaseActivityResources(activityToken,
+ context.setResources(resourcesManager.createBaseActivityResources(activityToken,
packageInfo.getResDir(),
splitDirs,
packageInfo.getOverlayDirs(),
@@ -2200,9 +2195,9 @@
displayId,
overrideConfiguration,
compatInfo,
- classLoader);
+ classLoader));
context.mDisplay = resourcesManager.getAdjustedDisplay(displayId,
- context.mResources.getDisplayAdjustments());
+ context.getResources());
return context;
}
@@ -2239,7 +2234,7 @@
if (container != null) {
mBasePackageName = container.mBasePackageName;
mOpPackageName = container.mOpPackageName;
- mResources = container.mResources;
+ setResources(container.mResources);
mDisplay = container.mDisplay;
} else {
mBasePackageName = packageInfo.mPackageName;
@@ -2258,6 +2253,14 @@
mContentResolver = new ApplicationContentResolver(this, mainThread, user);
}
+ void setResources(Resources r) {
+ if (mPackageInfo.getTargetSdkVersion() < VERSION_CODES.O) {
+ mResources = new CompatResources(r, this);
+ } else {
+ mResources = r;
+ }
+ }
+
void installSystemApplicationInfo(ApplicationInfo info, ClassLoader classLoader) {
mPackageInfo.installSystemApplicationInfo(info, classLoader);
}
diff --git a/core/java/android/app/FragmentManager.java b/core/java/android/app/FragmentManager.java
index 8ad7810..977931a 100644
--- a/core/java/android/app/FragmentManager.java
+++ b/core/java/android/app/FragmentManager.java
@@ -397,6 +397,19 @@
public void invalidateOptionsMenu() { }
/**
+ * Returns {@code true} if the FragmentManager's state has already been saved
+ * by its host. Any operations that would change saved state should not be performed
+ * if this method returns true. For example, any popBackStack() method, such as
+ * {@link #popBackStackImmediate()} or any FragmentTransaction using
+ * {@link FragmentTransaction#commit()} instead of
+ * {@link FragmentTransaction#commitAllowingStateLoss()} will change
+ * the state and will result in an error.
+ *
+ * @return true if this FragmentManager's state has already been saved by its host
+ */
+ public abstract boolean isStateSaved();
+
+ /**
* Callback interface for listening to fragment state changes that happen
* within a given FragmentManager.
*/
@@ -1787,6 +1800,7 @@
}
}
+ @Override
public boolean isStateSaved() {
return mStateSaved;
}
diff --git a/core/java/android/app/LoadedApk.java b/core/java/android/app/LoadedApk.java
index 7ed96af..1c33e38 100644
--- a/core/java/android/app/LoadedApk.java
+++ b/core/java/android/app/LoadedApk.java
@@ -278,7 +278,7 @@
setApplicationInfo(aInfo);
final List<String> newPaths = new ArrayList<>();
- makePaths(mActivityThread, aInfo, newPaths, null /*libPaths*/);
+ makePaths(mActivityThread, aInfo, newPaths);
final List<String> addedPaths = new ArrayList<>(newPaths.size());
if (oldPaths != null) {
@@ -341,8 +341,17 @@
}
}
- public static void makePaths(ActivityThread activityThread, ApplicationInfo aInfo,
- List<String> outZipPaths, List<String> outLibPaths) {
+ public static void makePaths(ActivityThread activityThread,
+ ApplicationInfo aInfo,
+ List<String> outZipPaths) {
+ makePaths(activityThread, false, aInfo, outZipPaths, null);
+ }
+
+ public static void makePaths(ActivityThread activityThread,
+ boolean isBundledApp,
+ ApplicationInfo aInfo,
+ List<String> outZipPaths,
+ List<String> outLibPaths) {
final String appDir = aInfo.sourceDir;
final String libDir = aInfo.nativeLibraryDir;
final String[] sharedLibraries = aInfo.sharedLibraryFiles;
@@ -431,7 +440,7 @@
}
}
- if (aInfo.isSystemApp() && !aInfo.isUpdatedSystemApp()) {
+ if (isBundledApp) {
// Add path to system libraries to libPaths;
// Access to system libs should be limited
// to bundled applications; this is why updated
@@ -614,11 +623,12 @@
// space and initialize to a small value (instead of incurring growth code).
final List<String> zipPaths = new ArrayList<>(10);
final List<String> libPaths = new ArrayList<>(10);
- makePaths(mActivityThread, mApplicationInfo, zipPaths, libPaths);
final boolean isBundledApp = mApplicationInfo.isSystemApp()
&& !mApplicationInfo.isUpdatedSystemApp();
+ makePaths(mActivityThread, isBundledApp, mApplicationInfo, zipPaths, libPaths);
+
String libraryPermittedPath = mDataDir;
if (isBundledApp) {
// This is necessary to grant bundled apps access to
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 812daf8..64fc44b 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -2702,11 +2702,11 @@
}
/**
- * Specifies the time at which this notification should be canceled, if it is not already
- * canceled.
+ * Specifies a duration in milliseconds after which this notification should be canceled,
+ * if it is not already canceled.
*/
- public Builder setTimeout(long when) {
- mN.mTimeout = when;
+ public Builder setTimeout(long durationMs) {
+ mN.mTimeout = durationMs;
return this;
}
diff --git a/core/java/android/app/NotificationManager.java b/core/java/android/app/NotificationManager.java
index 5205959..d37e209 100644
--- a/core/java/android/app/NotificationManager.java
+++ b/core/java/android/app/NotificationManager.java
@@ -447,6 +447,19 @@
}
/**
+ * @hide
+ */
+ public void createNotificationChannelsForPackage(String pkg,
+ @NonNull List<NotificationChannel> channels) {
+ INotificationManager service = getService();
+ try {
+ service.createNotificationChannels(pkg, new ParceledListSlice(channels));
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* Returns the notification channel settings for a given channel id.
*/
public NotificationChannel getNotificationChannel(String channelId) {
diff --git a/core/java/android/app/ResourcesManager.java b/core/java/android/app/ResourcesManager.java
index 55f7df3..52ec045 100644
--- a/core/java/android/app/ResourcesManager.java
+++ b/core/java/android/app/ResourcesManager.java
@@ -104,10 +104,17 @@
new WeakHashMap<>();
/**
- * A cache of DisplayId to DisplayAdjustments.
+ * A cache of DisplayId, DisplayAdjustments to Display.
*/
- private final ArrayMap<Pair<Integer, DisplayAdjustments>, WeakReference<Display>> mDisplays =
- new ArrayMap<>();
+ private final ArrayMap<Pair<Integer, DisplayAdjustments>, WeakReference<Display>>
+ mAdjustedDisplays = new ArrayMap<>();
+
+ /**
+ * A cache of DisplayId, Resources to Display. These display adjustments associated with these
+ * {@link Display}s will change as the resources change.
+ */
+ private final ArrayMap<Pair<Integer, Resources>, WeakReference<Display>> mResourceDisplays =
+ new ArrayMap<>();
public static ResourcesManager getInstance() {
synchronized (ResourcesManager.class) {
@@ -201,19 +208,21 @@
/**
* Returns an adjusted {@link Display} object based on the inputs or null if display isn't
- * available.
+ * available. This method is only used within {@link ResourcesManager} to calculate display
+ * metrics based on a set {@link DisplayAdjustments}. All other usages should instead call
+ * {@link ResourcesManager#getAdjustedDisplay(int, Resources)}.
*
* @param displayId display Id.
* @param displayAdjustments display adjustments.
*/
- public Display getAdjustedDisplay(final int displayId,
+ private Display getAdjustedDisplay(final int displayId,
@Nullable DisplayAdjustments displayAdjustments) {
final DisplayAdjustments displayAdjustmentsCopy = (displayAdjustments != null)
? new DisplayAdjustments(displayAdjustments) : new DisplayAdjustments();
final Pair<Integer, DisplayAdjustments> key =
Pair.create(displayId, displayAdjustmentsCopy);
synchronized (this) {
- WeakReference<Display> wd = mDisplays.get(key);
+ WeakReference<Display> wd = mAdjustedDisplays.get(key);
if (wd != null) {
final Display display = wd.get();
if (display != null) {
@@ -227,7 +236,37 @@
}
final Display display = dm.getCompatibleDisplay(displayId, key.second);
if (display != null) {
- mDisplays.put(key, new WeakReference<>(display));
+ mAdjustedDisplays.put(key, new WeakReference<>(display));
+ }
+ return display;
+ }
+ }
+
+ /**
+ * Returns an adjusted {@link Display} object based on the inputs or null if display isn't
+ * available.
+ *
+ * @param displayId display Id.
+ * @param resources The {@link Resources} backing the display adjustments.
+ */
+ public Display getAdjustedDisplay(final int displayId, Resources resources) {
+ final Pair<Integer, Resources> key = Pair.create(displayId, resources);
+ synchronized (this) {
+ WeakReference<Display> wd = mResourceDisplays.get(key);
+ if (wd != null) {
+ final Display display = wd.get();
+ if (display != null) {
+ return display;
+ }
+ }
+ final DisplayManagerGlobal dm = DisplayManagerGlobal.getInstance();
+ if (dm == null) {
+ // may be null early in system startup
+ return null;
+ }
+ final Display display = dm.getCompatibleDisplay(displayId, resources);
+ if (display != null) {
+ mResourceDisplays.put(key, new WeakReference<>(display));
}
return display;
}
@@ -316,6 +355,7 @@
final DisplayMetrics dm = getDisplayMetrics(key.mDisplayId, daj);
final Configuration config = generateConfig(key, dm);
final ResourcesImpl impl = new ResourcesImpl(assets, dm, config, daj);
+
if (DEBUG) {
Slog.d(TAG, "- creating impl=" + impl + " with key: " + key);
}
@@ -811,7 +851,9 @@
}
int changes = mResConfiguration.updateFrom(config);
// Things might have changed in display manager, so clear the cached displays.
- mDisplays.clear();
+ mAdjustedDisplays.clear();
+ mResourceDisplays.clear();
+
DisplayMetrics defaultDisplayMetrics = getDisplayMetrics();
if (compat != null && (mResCompatibilityInfo == null ||
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 9cb3dd6..6585793 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -3346,6 +3346,17 @@
public static final int KEYGUARD_DISABLE_FEATURES_ALL = 0x7fffffff;
/**
+ * Keyguard features that when set on a managed profile that doesn't have its own challenge will
+ * affect the profile's parent user. These can also be set on the managed profile's parent
+ * {@link DevicePolicyManager} instance.
+ *
+ * @hide
+ */
+ public static final int PROFILE_KEYGUARD_FEATURES_AFFECT_OWNER =
+ DevicePolicyManager.KEYGUARD_DISABLE_TRUST_AGENTS
+ | DevicePolicyManager.KEYGUARD_DISABLE_FINGERPRINT;
+
+ /**
* Called by an application that is administering the device to request that the storage system
* be encrypted.
* <p>
@@ -7697,7 +7708,34 @@
/**
* Called by a device owner to control the network logging feature.
*
- * <p> Network logs contain DNS lookup and connect() library call events.
+ * <p> Network logs contain DNS lookup and connect() library call events. The following library
+ * functions are recorded while network logging is active:
+ * <ul>
+ * <li>{@code getaddrinfo()}</li>
+ * <li>{@code gethostbyname()}</li>
+ * <li>{@code connect()}</li>
+ * </ul>
+ *
+ * <p> Network logging is a low-overhead tool for forensics but it is not guaranteed to use
+ * full system call logging; event reporting is enabled by default for all processes but not
+ * strongly enforced.
+ * Events from applications using alternative implementations of libc, making direct kernel
+ * calls, or deliberately obfuscating traffic may not be recorded.
+ *
+ * <p> Some common network events may not be reported. For example:
+ * <ul>
+ * <li>Applications may hardcode IP addresses to reduce the number of DNS lookups, or use
+ * an alternative system for name resolution, and so avoid calling
+ * {@code getaddrinfo()} or {@code gethostbyname}.</li>
+ * <li>Applications may use datagram sockets for performance reasons, for example
+ * for a game client. Calling {@code connect()} is unnecessary for this kind of
+ * socket, so it will not trigger a network event.</li>
+ * </ul>
+ *
+ * <p> It is possible to directly intercept layer 3 traffic leaving the device using an
+ * always-on VPN service.
+ * See {@link #setAlwaysOnVpnPackage(ComponentName, String, boolean)}
+ * and {@link android.net.VpnService} for details.
*
* <p><strong>Note:</strong> The device owner won't be able to retrieve network logs if there
* are unaffiliated secondary users or profiles on the device, regardless of whether the
diff --git a/core/java/android/app/assist/AssistStructure.java b/core/java/android/app/assist/AssistStructure.java
index 678c017..483a7a1 100644
--- a/core/java/android/app/assist/AssistStructure.java
+++ b/core/java/android/app/assist/AssistStructure.java
@@ -538,6 +538,7 @@
AutoFillId mAutoFillId;
AutoFillType mAutoFillType;
AutoFillValue mAutoFillValue;
+ String[] mAutoFillOptions;
boolean mSanitized;
int mX;
int mY;
@@ -618,6 +619,7 @@
mAutoFillId = in.readParcelable(null);
mAutoFillType = in.readParcelable(null);
mAutoFillValue = in.readParcelable(null);
+ mAutoFillOptions = in.readStringArray();
}
if ((flags&FLAGS_HAS_LARGE_COORDS) != 0) {
mX = in.readInt();
@@ -720,7 +722,14 @@
}
pwriter.writeString(mClassName);
- out.writeInt(flags);
+
+ int writtenFlags = flags;
+ if ((flags&FLAGS_HAS_AUTO_FILL_DATA) != 0 && (mSanitized || !sanitizeOnWrite)) {
+ // Remove 'checked' from sanitized auto-fill request.
+ writtenFlags = flags & ~FLAGS_CHECKED;
+ }
+
+ out.writeInt(writtenFlags);
if ((flags&FLAGS_HAS_ID) != 0) {
out.writeInt(mId);
if (mId != 0) {
@@ -738,6 +747,7 @@
out.writeParcelable(mAutoFillType, 0);
final AutoFillValue sanitizedValue = writeSensitive ? mAutoFillValue : null;
out.writeParcelable(sanitizedValue, 0);
+ out.writeStringArray(mAutoFillOptions);
}
if ((flags&FLAGS_HAS_LARGE_COORDS) != 0) {
out.writeInt(mX);
@@ -844,6 +854,19 @@
return mAutoFillValue;
}
+ /**
+ * Gets the options that can be used to auto-fill this structure.
+ *
+ * <p>Typically used by nodes whose {@link AutoFillType} is a list to indicate the meaning
+ * of each possible value in the list.
+ *
+ * <p>It's only set when the {@link AssistStructure} is used for auto-filling purposes, not
+ * for assist.
+ */
+ public String[] getAutoFillOptions() {
+ return mAutoFillOptions;
+ }
+
/** @hide */
public boolean isSanitized() {
return mSanitized;
@@ -1506,6 +1529,11 @@
mNode.mAutoFillValue = value;
}
+ @Override
+ public void setAutoFillOptions(String[] options) {
+ mNode.mAutoFillOptions = options;
+ }
+
/**
* @hide
*/
diff --git a/core/java/android/app/job/JobInfo.java b/core/java/android/app/job/JobInfo.java
index 2d6b45d..3887556 100644
--- a/core/java/android/app/job/JobInfo.java
+++ b/core/java/android/app/job/JobInfo.java
@@ -174,12 +174,26 @@
*/
public static final int FLAG_WILL_BE_FOREGROUND = 1 << 0;
+ /**
+ * @hide
+ */
+ public static final int CONSTRAINT_FLAG_CHARGING = 1 << 0;
+
+ /**
+ * @hide
+ */
+ public static final int CONSTRAINT_FLAG_BATTERY_NOT_LOW = 1 << 1;
+
+ /**
+ * @hide
+ */
+ public static final int CONSTRAINT_FLAG_DEVICE_IDLE = 1 << 2;
+
private final int jobId;
private final PersistableBundle extras;
private final Bundle transientExtras;
private final ComponentName service;
- private final boolean requireCharging;
- private final boolean requireDeviceIdle;
+ private final int constraintFlags;
private final TriggerContentUri[] triggerContentUris;
private final long triggerContentUpdateDelay;
private final long triggerContentMaxDelay;
@@ -241,14 +255,28 @@
* Whether this job needs the device to be plugged in.
*/
public boolean isRequireCharging() {
- return requireCharging;
+ return (constraintFlags & CONSTRAINT_FLAG_CHARGING) != 0;
+ }
+
+ /**
+ * Whether this job needs the device's battery level to not be at below the critical threshold.
+ */
+ public boolean isRequireBatteryNotLow() {
+ return (constraintFlags & CONSTRAINT_FLAG_BATTERY_NOT_LOW) != 0;
}
/**
* Whether this job needs the device to be in an Idle maintenance window.
*/
public boolean isRequireDeviceIdle() {
- return requireDeviceIdle;
+ return (constraintFlags & CONSTRAINT_FLAG_DEVICE_IDLE) != 0;
+ }
+
+ /**
+ * @hide
+ */
+ public int getConstraintFlags() {
+ return constraintFlags;
}
/**
@@ -376,8 +404,7 @@
extras = in.readPersistableBundle();
transientExtras = in.readBundle();
service = in.readParcelable(null);
- requireCharging = in.readInt() == 1;
- requireDeviceIdle = in.readInt() == 1;
+ constraintFlags = in.readInt();
triggerContentUris = in.createTypedArray(TriggerContentUri.CREATOR);
triggerContentUpdateDelay = in.readLong();
triggerContentMaxDelay = in.readLong();
@@ -401,8 +428,7 @@
extras = b.mExtras.deepcopy();
transientExtras = b.mTransientExtras.deepcopy();
service = b.mJobService;
- requireCharging = b.mRequiresCharging;
- requireDeviceIdle = b.mRequiresDeviceIdle;
+ constraintFlags = b.mConstraintFlags;
triggerContentUris = b.mTriggerContentUris != null
? b.mTriggerContentUris.toArray(new TriggerContentUri[b.mTriggerContentUris.size()])
: null;
@@ -434,8 +460,7 @@
out.writePersistableBundle(extras);
out.writeBundle(transientExtras);
out.writeParcelable(service, flags);
- out.writeInt(requireCharging ? 1 : 0);
- out.writeInt(requireDeviceIdle ? 1 : 0);
+ out.writeInt(constraintFlags);
out.writeTypedArray(triggerContentUris, flags);
out.writeLong(triggerContentUpdateDelay);
out.writeLong(triggerContentMaxDelay);
@@ -563,8 +588,7 @@
private int mPriority = PRIORITY_DEFAULT;
private int mFlags;
// Requirements.
- private boolean mRequiresCharging;
- private boolean mRequiresDeviceIdle;
+ private int mConstraintFlags;
private int mNetworkType;
private ArrayList<TriggerContentUri> mTriggerContentUris;
private long mTriggerContentUpdateDelay = -1;
@@ -651,7 +675,21 @@
* @param requiresCharging Whether or not the device is plugged in.
*/
public Builder setRequiresCharging(boolean requiresCharging) {
- mRequiresCharging = requiresCharging;
+ mConstraintFlags = (mConstraintFlags&~CONSTRAINT_FLAG_CHARGING)
+ | (requiresCharging ? CONSTRAINT_FLAG_CHARGING : 0);
+ return this;
+ }
+
+ /**
+ * Specify that to run this job, the device's battery level must not be low.
+ * This defaults to false. If true, the job will only run when the battery level
+ * is not low, which is generally the point where the user is given a "low battery"
+ * warning.
+ * @param batteryNotLow Whether or not the device's battery level must not be low.
+ */
+ public Builder setRequiresBatteryNotLow(boolean batteryNotLow) {
+ mConstraintFlags = (mConstraintFlags&~CONSTRAINT_FLAG_BATTERY_NOT_LOW)
+ | (batteryNotLow ? CONSTRAINT_FLAG_BATTERY_NOT_LOW : 0);
return this;
}
@@ -666,7 +704,8 @@
* window.
*/
public Builder setRequiresDeviceIdle(boolean requiresDeviceIdle) {
- mRequiresDeviceIdle = requiresDeviceIdle;
+ mConstraintFlags = (mConstraintFlags&~CONSTRAINT_FLAG_DEVICE_IDLE)
+ | (requiresDeviceIdle ? CONSTRAINT_FLAG_DEVICE_IDLE : 0);
return this;
}
@@ -816,8 +855,8 @@
*/
public JobInfo build() {
// Allow jobs with no constraints - What am I, a database?
- if (!mHasEarlyConstraint && !mHasLateConstraint && !mRequiresCharging &&
- !mRequiresDeviceIdle && mNetworkType == NETWORK_TYPE_NONE &&
+ if (!mHasEarlyConstraint && !mHasLateConstraint && mConstraintFlags == 0 &&
+ mNetworkType == NETWORK_TYPE_NONE &&
mTriggerContentUris == null) {
throw new IllegalArgumentException("You're trying to build a job with no " +
"constraints, this is not allowed.");
@@ -843,7 +882,7 @@
throw new IllegalArgumentException("Can't call setTransientExtras() on a " +
"persisted job");
}
- if (mBackoffPolicySet && mRequiresDeviceIdle) {
+ if (mBackoffPolicySet && (mConstraintFlags & CONSTRAINT_FLAG_DEVICE_IDLE) != 0) {
throw new IllegalArgumentException("An idle mode job will not respect any" +
" back-off policy, so calling setBackoffCriteria with" +
" setRequiresDeviceIdle is an error.");
diff --git a/core/java/android/app/usage/IStorageStatsManager.aidl b/core/java/android/app/usage/IStorageStatsManager.aidl
index f4c18dd..76c0293 100644
--- a/core/java/android/app/usage/IStorageStatsManager.aidl
+++ b/core/java/android/app/usage/IStorageStatsManager.aidl
@@ -24,6 +24,7 @@
boolean isQuotaSupported(String volumeUuid, String callingPackage);
long getTotalBytes(String volumeUuid, String callingPackage);
long getFreeBytes(String volumeUuid, String callingPackage);
+ StorageStats queryStatsForPackage(String volumeUuid, String packageName, int userId, String callingPackage);
StorageStats queryStatsForUid(String volumeUuid, int uid, String callingPackage);
StorageStats queryStatsForUser(String volumeUuid, int userId, String callingPackage);
ExternalStorageStats queryExternalStatsForUser(String volumeUuid, int userId, String callingPackage);
diff --git a/core/java/android/app/usage/StorageStatsManager.java b/core/java/android/app/usage/StorageStatsManager.java
index 7d4efb9..081ccd9 100644
--- a/core/java/android/app/usage/StorageStatsManager.java
+++ b/core/java/android/app/usage/StorageStatsManager.java
@@ -19,6 +19,7 @@
import android.annotation.WorkerThread;
import android.content.Context;
import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageInfo;
import android.os.RemoteException;
import android.os.UserHandle;
@@ -100,6 +101,37 @@
}
/**
+ * Return storage statistics for a specific package on the requested storage
+ * volume.
+ * <p>
+ * This method may take several seconds to calculate the requested values,
+ * so it should only be called from a worker thread.
+ * <p class="note">
+ * Note: if the requested package uses the {@code android:sharedUserId}
+ * manifest feature, this call will be forced into a slower manual
+ * calculation path. If possible, consider always using
+ * {@link #queryStatsForUid(String, int)}, which is typically faster.
+ * </p>
+ *
+ * @param volumeUuid the UUID of the storage volume you're interested in, or
+ * {@code null} to specify the default internal storage.
+ * @param packageName the package name you're interested in.
+ * @param user the user you're interested in.
+ * @see ApplicationInfo#volumeUuid
+ * @see PackageInfo#packageName
+ */
+ @WorkerThread
+ public StorageStats queryStatsForPackage(String volumeUuid, String packageName,
+ UserHandle user) {
+ try {
+ return mService.queryStatsForPackage(volumeUuid, packageName, user.getIdentifier(),
+ mContext.getOpPackageName());
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* Return storage statistics for a specific UID on the requested storage
* volume.
* <p>
diff --git a/core/java/android/content/ContentResolver.java b/core/java/android/content/ContentResolver.java
index 4480b41..be49f24 100644
--- a/core/java/android/content/ContentResolver.java
+++ b/core/java/android/content/ContentResolver.java
@@ -36,6 +36,7 @@
import android.graphics.Point;
import android.graphics.drawable.Drawable;
import android.net.Uri;
+import android.os.Build;
import android.os.Bundle;
import android.os.CancellationSignal;
import android.os.DeadObjectException;
@@ -500,6 +501,12 @@
public ContentResolver(Context context) {
mContext = context != null ? context : ActivityThread.currentApplication();
mPackageName = mContext.getOpPackageName();
+ if (android.os.Process.myUid() == android.os.Process.PHONE_UID) {
+ // STOPSHIP: Telephony needs to fix b/35792675
+ mTargetSdkVersion = Build.VERSION_CODES.N_MR1;
+ } else {
+ mTargetSdkVersion = mContext.getApplicationInfo().targetSdkVersion;
+ }
}
/** @hide */
@@ -1868,13 +1875,18 @@
/**
* Register an observer class that gets callbacks when data identified by a
* given content URI changes.
+ * <p>
+ * Starting in {@link android.os.Build.VERSION_CODES#O}, all content
+ * notifications must be backed by a valid {@link ContentProvider}.
*
- * @param uri The URI to watch for changes. This can be a specific row URI, or a base URI
- * for a whole class of content.
- * @param notifyForDescendants When false, the observer will be notified whenever a
- * change occurs to the exact URI specified by <code>uri</code> or to one of the
- * URI's ancestors in the path hierarchy. When true, the observer will also be notified
- * whenever a change occurs to the URI's descendants in the path hierarchy.
+ * @param uri The URI to watch for changes. This can be a specific row URI,
+ * or a base URI for a whole class of content.
+ * @param notifyForDescendants When false, the observer will be notified
+ * whenever a change occurs to the exact URI specified by
+ * <code>uri</code> or to one of the URI's ancestors in the path
+ * hierarchy. When true, the observer will also be notified
+ * whenever a change occurs to the URI's descendants in the path
+ * hierarchy.
* @param observer The object that receives callbacks when changes occur.
* @see #unregisterContentObserver
*/
@@ -1894,7 +1906,7 @@
ContentObserver observer, @UserIdInt int userHandle) {
try {
getContentService().registerContentObserver(uri, notifyForDescendents,
- observer.getContentObserver(), userHandle);
+ observer.getContentObserver(), userHandle, mTargetSdkVersion);
} catch (RemoteException e) {
}
}
@@ -1918,16 +1930,22 @@
}
/**
- * Notify registered observers that a row was updated and attempt to sync changes
- * to the network.
- * To register, call {@link #registerContentObserver(android.net.Uri , boolean, android.database.ContentObserver) registerContentObserver()}.
- * By default, CursorAdapter objects will get this notification.
+ * Notify registered observers that a row was updated and attempt to sync
+ * changes to the network.
+ * <p>
+ * To observe events sent through this call, use
+ * {@link #registerContentObserver(Uri, boolean, ContentObserver)}.
+ * <p>
+ * Starting in {@link android.os.Build.VERSION_CODES#O}, all content
+ * notifications must be backed by a valid {@link ContentProvider}.
*
* @param uri The uri of the content that was changed.
- * @param observer The observer that originated the change, may be <code>null</null>.
- * The observer that originated the change will only receive the notification if it
- * has requested to receive self-change notifications by implementing
- * {@link ContentObserver#deliverSelfNotifications()} to return true.
+ * @param observer The observer that originated the change, may be
+ * <code>null</null>. The observer that originated the change
+ * will only receive the notification if it has requested to
+ * receive self-change notifications by implementing
+ * {@link ContentObserver#deliverSelfNotifications()} to return
+ * true.
*/
public void notifyChange(@NonNull Uri uri, @Nullable ContentObserver observer) {
notifyChange(uri, observer, true /* sync to network */);
@@ -1935,17 +1953,25 @@
/**
* Notify registered observers that a row was updated.
- * To register, call {@link #registerContentObserver(android.net.Uri , boolean, android.database.ContentObserver) registerContentObserver()}.
- * By default, CursorAdapter objects will get this notification.
- * If syncToNetwork is true, this will attempt to schedule a local sync using the sync
- * adapter that's registered for the authority of the provided uri. No account will be
- * passed to the sync adapter, so all matching accounts will be synchronized.
+ * <p>
+ * To observe events sent through this call, use
+ * {@link #registerContentObserver(Uri, boolean, ContentObserver)}.
+ * <p>
+ * If syncToNetwork is true, this will attempt to schedule a local sync
+ * using the sync adapter that's registered for the authority of the
+ * provided uri. No account will be passed to the sync adapter, so all
+ * matching accounts will be synchronized.
+ * <p>
+ * Starting in {@link android.os.Build.VERSION_CODES#O}, all content
+ * notifications must be backed by a valid {@link ContentProvider}.
*
* @param uri The uri of the content that was changed.
- * @param observer The observer that originated the change, may be <code>null</null>.
- * The observer that originated the change will only receive the notification if it
- * has requested to receive self-change notifications by implementing
- * {@link ContentObserver#deliverSelfNotifications()} to return true.
+ * @param observer The observer that originated the change, may be
+ * <code>null</null>. The observer that originated the change
+ * will only receive the notification if it has requested to
+ * receive self-change notifications by implementing
+ * {@link ContentObserver#deliverSelfNotifications()} to return
+ * true.
* @param syncToNetwork If true, same as {@link #NOTIFY_SYNC_TO_NETWORK}.
* @see #requestSync(android.accounts.Account, String, android.os.Bundle)
*/
@@ -1961,17 +1987,25 @@
/**
* Notify registered observers that a row was updated.
- * To register, call {@link #registerContentObserver(android.net.Uri, boolean, android.database.ContentObserver) registerContentObserver()}.
- * By default, CursorAdapter objects will get this notification.
- * If syncToNetwork is true, this will attempt to schedule a local sync using the sync
- * adapter that's registered for the authority of the provided uri. No account will be
- * passed to the sync adapter, so all matching accounts will be synchronized.
+ * <p>
+ * To observe events sent through this call, use
+ * {@link #registerContentObserver(Uri, boolean, ContentObserver)}.
+ * <p>
+ * If syncToNetwork is true, this will attempt to schedule a local sync
+ * using the sync adapter that's registered for the authority of the
+ * provided uri. No account will be passed to the sync adapter, so all
+ * matching accounts will be synchronized.
+ * <p>
+ * Starting in {@link android.os.Build.VERSION_CODES#O}, all content
+ * notifications must be backed by a valid {@link ContentProvider}.
*
* @param uri The uri of the content that was changed.
- * @param observer The observer that originated the change, may be <code>null</null>.
- * The observer that originated the change will only receive the notification if it
- * has requested to receive self-change notifications by implementing
- * {@link ContentObserver#deliverSelfNotifications()} to return true.
+ * @param observer The observer that originated the change, may be
+ * <code>null</null>. The observer that originated the change
+ * will only receive the notification if it has requested to
+ * receive self-change notifications by implementing
+ * {@link ContentObserver#deliverSelfNotifications()} to return
+ * true.
* @param flags Additional flags: {@link #NOTIFY_SYNC_TO_NETWORK}.
* @see #requestSync(android.accounts.Account, String, android.os.Bundle)
*/
@@ -1997,7 +2031,7 @@
uri, observer == null ? null : observer.getContentObserver(),
observer != null && observer.deliverSelfNotifications(),
syncToNetwork ? NOTIFY_SYNC_TO_NETWORK : 0,
- userHandle);
+ userHandle, mTargetSdkVersion);
} catch (RemoteException e) {
}
}
@@ -2013,7 +2047,7 @@
getContentService().notifyChange(
uri, observer == null ? null : observer.getContentObserver(),
observer != null && observer.deliverSelfNotifications(), flags,
- userHandle);
+ userHandle, mTargetSdkVersion);
} catch (RemoteException e) {
}
}
@@ -2932,6 +2966,7 @@
private final Context mContext;
final String mPackageName;
+ final int mTargetSdkVersion;
private static final String TAG = "ContentResolver";
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 44f6c43..de503c0 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -730,12 +730,6 @@
*/
public abstract boolean moveSharedPreferencesFrom(Context sourceContext, String name);
- /** @removed */
- @Deprecated
- public boolean migrateSharedPreferencesFrom(Context sourceContext, String name) {
- return moveSharedPreferencesFrom(sourceContext, name);
- }
-
/**
* Delete an existing shared preferences file.
*
@@ -1451,12 +1445,6 @@
*/
public abstract boolean moveDatabaseFrom(Context sourceContext, String name);
- /** @removed */
- @Deprecated
- public boolean migrateDatabaseFrom(Context sourceContext, String name) {
- return moveDatabaseFrom(sourceContext, name);
- }
-
/**
* Delete an existing private SQLiteDatabase associated with this Context's
* application package.
@@ -2723,6 +2711,7 @@
VIBRATOR_SERVICE,
//@hide: STATUS_BAR_SERVICE,
CONNECTIVITY_SERVICE,
+ IPSEC_SERVICE,
//@hide: UPDATE_LOCK_SERVICE,
//@hide: NETWORKMANAGEMENT_SERVICE,
NETWORK_STATS_SERVICE,
@@ -2826,6 +2815,9 @@
* <dt> {@link #CONNECTIVITY_SERVICE} ("connection")
* <dd> A {@link android.net.ConnectivityManager ConnectivityManager} for
* handling management of network connections.
+ * <dt> {@link #IPSEC_SERVICE} ("ipsec")
+ * <dd> A {@link android.net.IpSecManager IpSecManager} for managing IPSec on
+ * sockets and networks.
* <dt> {@link #WIFI_SERVICE} ("wifi")
* <dd> A {@link android.net.wifi.WifiManager WifiManager} for management of Wi-Fi
* connectivity. On releases before NYC, it should only be obtained from an application
@@ -3166,6 +3158,15 @@
public static final String CONNECTIVITY_SERVICE = "connectivity";
/**
+ * Use with {@link #getSystemService} to retrieve a
+ * {@link android.net.IpSecManager} for encrypting Sockets or Networks with
+ * IPSec.
+ *
+ * @see #getSystemService
+ */
+ public static final String IPSEC_SERVICE = "ipsec";
+
+ /**
* Use with {@link #getSystemService} to retrieve a {@link
* android.os.IUpdateLock} for managing runtime sequences that
* must not be interrupted by headless OTA application or similar.
@@ -4382,12 +4383,6 @@
*/
public abstract Context createDeviceProtectedStorageContext();
- /** @removed */
- @Deprecated
- public Context createDeviceEncryptedStorageContext() {
- return createDeviceProtectedStorageContext();
- }
-
/**
* Return a new Context object for the current Context but whose storage
* APIs are backed by credential-protected storage. This is the default
@@ -4416,12 +4411,6 @@
@SystemApi
public abstract Context createCredentialProtectedStorageContext();
- /** @removed */
- @Deprecated
- public Context createCredentialEncryptedStorageContext() {
- return createCredentialProtectedStorageContext();
- }
-
/**
* Gets the display adjustments holder for this context. This information
* is provided on a per-application or activity basis and is used to simulate lower density
@@ -4462,12 +4451,6 @@
*/
public abstract boolean isDeviceProtectedStorage();
- /** @removed */
- @Deprecated
- public boolean isDeviceEncryptedStorage() {
- return isDeviceProtectedStorage();
- }
-
/**
* Indicates if the storage APIs of this Context are backed by
* credential-protected storage.
@@ -4478,12 +4461,6 @@
@SystemApi
public abstract boolean isCredentialProtectedStorage();
- /** @removed */
- @Deprecated
- public boolean isCredentialEncryptedStorage() {
- return isCredentialProtectedStorage();
- }
-
/**
* @hide
*/
diff --git a/core/java/android/content/IContentService.aidl b/core/java/android/content/IContentService.aidl
index 3446e03..c500116 100644
--- a/core/java/android/content/IContentService.aidl
+++ b/core/java/android/content/IContentService.aidl
@@ -42,7 +42,7 @@
* USER_CURRENT are properly handled.
*/
void registerContentObserver(in Uri uri, boolean notifyForDescendants,
- IContentObserver observer, int userHandle);
+ IContentObserver observer, int userHandle, int targetSdkVersion);
/**
* Notify observers of a particular user's view of the provider.
@@ -53,7 +53,7 @@
*/
void notifyChange(in Uri uri, IContentObserver observer,
boolean observerWantsSelfNotifications, int flags,
- int userHandle);
+ int userHandle, int targetSdkVersion);
void requestSync(in Account account, String authority, in Bundle extras);
/**
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 28068c5..870db217 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -1115,6 +1115,15 @@
public static final String ACTION_SIM_ACTIVATION_REQUEST =
"android.intent.action.SIM_ACTIVATION_REQUEST";
/**
+ * Activity Action: Main entry point for carrier setup apps.
+ * <p>Carrier apps that provide an implementation for this action may be invoked to configure
+ * carrier service and typically require
+ * {@link android.telephony.TelephonyManager#hasCarrierPrivileges() carrier privileges} to
+ * fulfill their duties.
+ */
+ @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+ public static final String ACTION_CARRIER_SETUP = "android.intent.action.CARRIER_SETUP";
+ /**
* Activity Action: Send a message to someone specified by the data.
* <p>Input: {@link #getData} is URI describing the target.
* <p>Output: nothing.
@@ -9260,6 +9269,13 @@
mClipData.prepareToLeaveProcess(leavingPackage, getFlags());
}
+ if (mExtras != null && !mExtras.isParcelled()) {
+ final Object intent = mExtras.get(Intent.EXTRA_INTENT);
+ if (intent instanceof Intent) {
+ ((Intent) intent).prepareToLeaveProcess(leavingPackage);
+ }
+ }
+
if (mAction != null && mData != null && StrictMode.vmFileUriExposureEnabled()
&& leavingPackage) {
switch (mAction) {
diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java
index 9737b11..b4d77a0 100644
--- a/core/java/android/content/pm/ApplicationInfo.java
+++ b/core/java/android/content/pm/ApplicationInfo.java
@@ -720,10 +720,6 @@
*/
public String deviceProtectedDataDir;
- /** @removed */
- @Deprecated
- public String deviceEncryptedDataDir;
-
/**
* Full path to the credential-protected directory assigned to the package
* for its persistent data.
@@ -733,10 +729,6 @@
@SystemApi
public String credentialProtectedDataDir;
- /** @removed */
- @Deprecated
- public String credentialEncryptedDataDir;
-
/**
* Full path to the directory where native JNI libraries are stored.
*/
@@ -1140,8 +1132,8 @@
seInfoUser = orig.seInfoUser;
sharedLibraryFiles = orig.sharedLibraryFiles;
dataDir = orig.dataDir;
- deviceEncryptedDataDir = deviceProtectedDataDir = orig.deviceProtectedDataDir;
- credentialEncryptedDataDir = credentialProtectedDataDir = orig.credentialProtectedDataDir;
+ deviceProtectedDataDir = orig.deviceProtectedDataDir;
+ credentialProtectedDataDir = orig.credentialProtectedDataDir;
uid = orig.uid;
minSdkVersion = orig.minSdkVersion;
targetSdkVersion = orig.targetSdkVersion;
@@ -1264,8 +1256,8 @@
seInfoUser = source.readString();
sharedLibraryFiles = source.readStringArray();
dataDir = source.readString();
- deviceEncryptedDataDir = deviceProtectedDataDir = source.readString();
- credentialEncryptedDataDir = credentialProtectedDataDir = source.readString();
+ deviceProtectedDataDir = source.readString();
+ credentialProtectedDataDir = source.readString();
uid = source.readInt();
minSdkVersion = source.readInt();
targetSdkVersion = source.readInt();
@@ -1336,10 +1328,10 @@
return;
}
- deviceEncryptedDataDir = deviceProtectedDataDir = Environment
+ deviceProtectedDataDir = Environment
.getDataUserDePackageDirectory(volumeUuid, userId, packageName)
.getAbsolutePath();
- credentialEncryptedDataDir = credentialProtectedDataDir = Environment
+ credentialProtectedDataDir = Environment
.getDataUserCePackageDirectory(volumeUuid, userId, packageName)
.getAbsolutePath();
diff --git a/core/java/android/content/pm/AuxiliaryResolveInfo.java b/core/java/android/content/pm/AuxiliaryResolveInfo.java
new file mode 100644
index 0000000..7d7784a
--- /dev/null
+++ b/core/java/android/content/pm/AuxiliaryResolveInfo.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.content.pm;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.Intent;
+import android.content.IntentFilter;
+
+/**
+ * Auxiliary application resolution response.
+ * <p>
+ * Used when resolution occurs, but, the target is not actually on the device.
+ * This happens resolving instant apps that haven't been installed yet or if
+ * the application consists of multiple feature splits and the needed split
+ * hasn't been installed.
+ * @hide
+ */
+public final class AuxiliaryResolveInfo extends IntentFilter {
+ /** Resolved information returned from the external ephemeral resolver */
+ public final EphemeralResolveInfo resolveInfo;
+ /** The resolved package. Copied from {@link #resolveInfo}. */
+ public final String packageName;
+ /** The resolve split. Copied from the matched filter in {@link #resolveInfo}. */
+ public final String splitName;
+ /** Whether or not ephemeral resolution needs the second phase */
+ public final boolean needsPhaseTwo;
+ /** Opaque token to track the ephemeral application resolution */
+ public final String token;
+ /** The version code of the package */
+ public final int versionCode;
+
+ /** Create a response for installing an instant application. */
+ public AuxiliaryResolveInfo(@NonNull EphemeralResolveInfo resolveInfo,
+ @NonNull IntentFilter orig,
+ @Nullable String splitName,
+ @NonNull String token,
+ boolean needsPhase2) {
+ super(orig);
+ this.resolveInfo = resolveInfo;
+ this.packageName = resolveInfo.getPackageName();
+ this.splitName = splitName;
+ this.token = token;
+ this.needsPhaseTwo = needsPhase2;
+ this.versionCode = resolveInfo.getVersionCode();
+ }
+
+ /** Create a response for installing a split on demand. */
+ public AuxiliaryResolveInfo(@NonNull String packageName,
+ @Nullable String splitName,
+ int versionCode) {
+ super();
+ this.packageName = packageName;
+ this.splitName = splitName;
+ this.versionCode = versionCode;
+ this.resolveInfo = null;
+ this.token = null;
+ this.needsPhaseTwo = false;
+ }
+}
\ No newline at end of file
diff --git a/core/java/android/content/pm/BaseParceledListSlice.java b/core/java/android/content/pm/BaseParceledListSlice.java
new file mode 100644
index 0000000..c4e4e06
--- /dev/null
+++ b/core/java/android/content/pm/BaseParceledListSlice.java
@@ -0,0 +1,201 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.content.pm;
+
+import android.os.Binder;
+import android.os.IBinder;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.os.RemoteException;
+import android.util.Log;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Transfer a large list of Parcelable objects across an IPC. Splits into
+ * multiple transactions if needed.
+ *
+ * Caveat: for efficiency and security, all elements must be the same concrete type.
+ * In order to avoid writing the class name of each object, we must ensure that
+ * each object is the same type, or else unparceling then reparceling the data may yield
+ * a different result if the class name encoded in the Parcelable is a Base type.
+ * See b/17671747.
+ *
+ * @hide
+ */
+abstract class BaseParceledListSlice<T> implements Parcelable {
+ private static String TAG = "ParceledListSlice";
+ private static boolean DEBUG = false;
+
+ /*
+ * TODO get this number from somewhere else. For now set it to a quarter of
+ * the 1MB limit.
+ */
+ private static final int MAX_IPC_SIZE = IBinder.MAX_IPC_SIZE;
+
+ private final List<T> mList;
+
+ public BaseParceledListSlice(List<T> list) {
+ mList = list;
+ }
+
+ @SuppressWarnings("unchecked")
+ BaseParceledListSlice(Parcel p, ClassLoader loader) {
+ final int N = p.readInt();
+ mList = new ArrayList<T>(N);
+ if (DEBUG) Log.d(TAG, "Retrieving " + N + " items");
+ if (N <= 0) {
+ return;
+ }
+
+ Parcelable.Creator<?> creator = readParcelableCreator(p, loader);
+ Class<?> listElementClass = null;
+
+ int i = 0;
+ while (i < N) {
+ if (p.readInt() == 0) {
+ break;
+ }
+
+ final T parcelable = readCreator(creator, p, loader);
+ if (listElementClass == null) {
+ listElementClass = parcelable.getClass();
+ } else {
+ verifySameType(listElementClass, parcelable.getClass());
+ }
+
+ mList.add(parcelable);
+
+ if (DEBUG) Log.d(TAG, "Read inline #" + i + ": " + mList.get(mList.size()-1));
+ i++;
+ }
+ if (i >= N) {
+ return;
+ }
+ final IBinder retriever = p.readStrongBinder();
+ while (i < N) {
+ if (DEBUG) Log.d(TAG, "Reading more @" + i + " of " + N + ": retriever=" + retriever);
+ Parcel data = Parcel.obtain();
+ Parcel reply = Parcel.obtain();
+ data.writeInt(i);
+ try {
+ retriever.transact(IBinder.FIRST_CALL_TRANSACTION, data, reply, 0);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Failure retrieving array; only received " + i + " of " + N, e);
+ return;
+ }
+ while (i < N && reply.readInt() != 0) {
+ final T parcelable = reply.readCreator(creator, loader);
+ verifySameType(listElementClass, parcelable.getClass());
+
+ mList.add(parcelable);
+
+ if (DEBUG) Log.d(TAG, "Read extra #" + i + ": " + mList.get(mList.size()-1));
+ i++;
+ }
+ reply.recycle();
+ data.recycle();
+ }
+ }
+
+ private T readCreator(Parcelable.Creator<?> creator, Parcel p, ClassLoader loader) {
+ if (creator instanceof Parcelable.ClassLoaderCreator<?>) {
+ Parcelable.ClassLoaderCreator<?> classLoaderCreator =
+ (Parcelable.ClassLoaderCreator<?>) creator;
+ return (T) classLoaderCreator.createFromParcel(p, loader);
+ }
+ return (T) creator.createFromParcel(p);
+ }
+
+ private static void verifySameType(final Class<?> expected, final Class<?> actual) {
+ if (!actual.equals(expected)) {
+ throw new IllegalArgumentException("Can't unparcel type "
+ + actual.getName() + " in list of type "
+ + expected.getName());
+ }
+ }
+
+ public List<T> getList() {
+ return mList;
+ }
+
+ /**
+ * Write this to another Parcel. Note that this discards the internal Parcel
+ * and should not be used anymore. This is so we can pass this to a Binder
+ * where we won't have a chance to call recycle on this.
+ */
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ final int N = mList.size();
+ final int callFlags = flags;
+ dest.writeInt(N);
+ if (DEBUG) Log.d(TAG, "Writing " + N + " items");
+ if (N > 0) {
+ final Class<?> listElementClass = mList.get(0).getClass();
+ writeParcelableCreator(mList.get(0), dest);
+ int i = 0;
+ while (i < N && dest.dataSize() < MAX_IPC_SIZE) {
+ dest.writeInt(1);
+
+ final T parcelable = mList.get(i);
+ verifySameType(listElementClass, parcelable.getClass());
+ writeElement(parcelable, dest, callFlags);
+
+ if (DEBUG) Log.d(TAG, "Wrote inline #" + i + ": " + mList.get(i));
+ i++;
+ }
+ if (i < N) {
+ dest.writeInt(0);
+ Binder retriever = new Binder() {
+ @Override
+ protected boolean onTransact(int code, Parcel data, Parcel reply, int flags)
+ throws RemoteException {
+ if (code != FIRST_CALL_TRANSACTION) {
+ return super.onTransact(code, data, reply, flags);
+ }
+ int i = data.readInt();
+ if (DEBUG) Log.d(TAG, "Writing more @" + i + " of " + N);
+ while (i < N && reply.dataSize() < MAX_IPC_SIZE) {
+ reply.writeInt(1);
+
+ final T parcelable = mList.get(i);
+ verifySameType(listElementClass, parcelable.getClass());
+ writeElement(parcelable, reply, callFlags);
+
+ if (DEBUG) Log.d(TAG, "Wrote extra #" + i + ": " + mList.get(i));
+ i++;
+ }
+ if (i < N) {
+ if (DEBUG) Log.d(TAG, "Breaking @" + i + " of " + N);
+ reply.writeInt(0);
+ }
+ return true;
+ }
+ };
+ if (DEBUG) Log.d(TAG, "Breaking @" + i + " of " + N + ": retriever=" + retriever);
+ dest.writeStrongBinder(retriever);
+ }
+ }
+ }
+
+ protected abstract void writeElement(T parcelable, Parcel reply, int callFlags);
+
+ protected abstract void writeParcelableCreator(T parcelable, Parcel dest);
+
+ protected abstract Parcelable.Creator<?> readParcelableCreator(Parcel from, ClassLoader loader);
+}
diff --git a/core/java/android/content/pm/EphemeralRequest.java b/core/java/android/content/pm/EphemeralRequest.java
index 7f2b3ee1..58099c2b 100644
--- a/core/java/android/content/pm/EphemeralRequest.java
+++ b/core/java/android/content/pm/EphemeralRequest.java
@@ -24,24 +24,21 @@
*/
public final class EphemeralRequest {
/** Response from the first phase of ephemeral application resolution */
- public final EphemeralResponse responseObj;
+ public final AuxiliaryResolveInfo responseObj;
/** The original intent that triggered ephemeral application resolution */
public final Intent origIntent;
/** Resolved type of the intent */
public final String resolvedType;
- /** The intent that would launch if there were no ephemeral applications */
- public final Intent launchIntent;
/** The name of the package requesting the ephemeral application */
public final String callingPackage;
/** ID of the user requesting the ephemeral application */
public final int userId;
- public EphemeralRequest(EphemeralResponse responseObj, Intent origIntent,
- String resolvedType, Intent launchIntent, String callingPackage, int userId) {
+ public EphemeralRequest(AuxiliaryResolveInfo responseObj, Intent origIntent,
+ String resolvedType, String callingPackage, int userId) {
this.responseObj = responseObj;
this.origIntent = origIntent;
this.resolvedType = resolvedType;
- this.launchIntent = launchIntent;
this.callingPackage = callingPackage;
this.userId = userId;
}
diff --git a/core/java/android/content/pm/EphemeralResponse.java b/core/java/android/content/pm/EphemeralResponse.java
deleted file mode 100644
index 6e569f7..0000000
--- a/core/java/android/content/pm/EphemeralResponse.java
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.content.pm;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.content.IntentFilter;
-
-/**
- * Ephemeral application resolution response.
- * @hide
- */
-public final class EphemeralResponse extends IntentFilter {
- /** Resolved information returned from the external ephemeral resolver */
- public final EphemeralResolveInfo resolveInfo;
- /** The resolved package. Copied from {@link #resolveInfo}. */
- public final String packageName;
- /** The resolve split. Copied from the matched filter in {@link #resolveInfo}. */
- public final String splitName;
- /** Whether or not ephemeral resolution needs the second phase */
- public final boolean needsPhase2;
- /** Opaque token to track the ephemeral application resolution */
- public final String token;
-
- public EphemeralResponse(@NonNull EphemeralResolveInfo resolveInfo,
- @NonNull IntentFilter orig,
- @Nullable String splitName,
- @NonNull String token,
- boolean needsPhase2) {
- super(orig);
- this.resolveInfo = resolveInfo;
- this.packageName = resolveInfo.getPackageName();
- this.splitName = splitName;
- this.token = token;
- this.needsPhase2 = needsPhase2;
- }
-}
\ No newline at end of file
diff --git a/core/java/android/content/pm/ILauncherApps.aidl b/core/java/android/content/pm/ILauncherApps.aidl
index c08bd1d..41311eb 100644
--- a/core/java/android/content/pm/ILauncherApps.aidl
+++ b/core/java/android/content/pm/ILauncherApps.aidl
@@ -55,7 +55,8 @@
String callingPackage, String packageName, int flags, in UserHandle user);
ParceledListSlice getShortcuts(String callingPackage, long changedSince, String packageName,
- in List shortcutIds, in ComponentName componentName, int flags, in UserHandle user);
+ in List shortcutIds, in ComponentName componentName, in Intent intent, int flags,
+ in UserHandle user);
void pinShortcuts(String callingPackage, String packageName, in List<String> shortcutIds,
in UserHandle user);
boolean startShortcut(String callingPackage, String packageName, String id,
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index ffb777d..147b3e1 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -22,7 +22,6 @@
import android.content.IntentFilter;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
-import android.content.pm.ContainerEncryptionParams;
import android.content.pm.ChangedPackages;
import android.content.pm.InstantAppInfo;
import android.content.pm.FeatureInfo;
@@ -38,7 +37,6 @@
import android.content.pm.InstrumentationInfo;
import android.content.pm.KeySet;
import android.content.pm.PackageInfo;
-import android.content.pm.ManifestDigest;
import android.content.pm.PackageCleanItem;
import android.content.pm.ParceledListSlice;
import android.content.pm.ProviderInfo;
@@ -213,7 +211,7 @@
inout List<ProviderInfo> outInfo);
ParceledListSlice queryContentProviders(
- String processName, int uid, int flags);
+ String processName, int uid, int flags, String metaDataKey);
InstrumentationInfo getInstrumentationInfo(
in ComponentName className, int flags);
diff --git a/core/java/android/content/pm/IPinItemRequest.aidl b/core/java/android/content/pm/IPinItemRequest.aidl
index efe2835..eddce58 100644
--- a/core/java/android/content/pm/IPinItemRequest.aidl
+++ b/core/java/android/content/pm/IPinItemRequest.aidl
@@ -16,6 +16,8 @@
package android.content.pm;
import android.os.Bundle;
+import android.appwidget.AppWidgetProviderInfo;
+import android.content.pm.ShortcutInfo;
/**
* {@hide}
@@ -23,4 +25,6 @@
interface IPinItemRequest {
boolean isValid();
boolean accept(in Bundle options);
+ ShortcutInfo getShortcutInfo();
+ AppWidgetProviderInfo getAppWidgetProviderInfo();
}
diff --git a/core/java/android/content/pm/InstantAppInfo.java b/core/java/android/content/pm/InstantAppInfo.java
index 898ee110..67afc92 100644
--- a/core/java/android/content/pm/InstantAppInfo.java
+++ b/core/java/android/content/pm/InstantAppInfo.java
@@ -75,7 +75,7 @@
}
/**
- * @return The pakcage name.
+ * @return The package name.
*/
public @NonNull String getPackageName() {
if (mApplicationInfo != null) {
diff --git a/core/java/android/content/pm/LauncherApps.java b/core/java/android/content/pm/LauncherApps.java
index 0866af2..776492a 100644
--- a/core/java/android/content/pm/LauncherApps.java
+++ b/core/java/android/content/pm/LauncherApps.java
@@ -275,7 +275,18 @@
@Deprecated
public static final int FLAG_GET_MANIFEST = FLAG_MATCH_MANIFEST;
- /** @hide */
+ /**
+ * Include chooser shortcuts in the result.
+ * STOPSHIP TODO: Unless explicitly requesting chooser fields, we should strip out chooser
+ * relevant fields from the Shortcut. This should also be adequately documented.
+ */
+ public static final int FLAG_MATCH_CHOOSER = 1 << 4;
+
+ /**
+ * Does not retrieve CHOOSER only shortcuts.
+ * TODO: Add another flag for MATCH_ALL_PINNED
+ * @hide
+ */
public static final int FLAG_MATCH_ALL_KINDS =
FLAG_GET_DYNAMIC | FLAG_GET_PINNED | FLAG_GET_MANIFEST;
@@ -308,6 +319,7 @@
FLAG_MATCH_DYNAMIC,
FLAG_MATCH_PINNED,
FLAG_MATCH_MANIFEST,
+ FLAG_MATCH_CHOOSER,
FLAG_GET_KEY_FIELDS_ONLY,
})
@Retention(RetentionPolicy.SOURCE)
@@ -324,6 +336,9 @@
@Nullable
ComponentName mActivity;
+ @Nullable
+ Intent mIntent;
+
@QueryFlags
int mQueryFlags;
@@ -368,6 +383,14 @@
}
/**
+ * If non-null, returns only shortcuts with intent filters that match this intent.
+ */
+ public ShortcutQuery setIntent(@Nullable Intent intent) {
+ mIntent = intent;
+ return this;
+ }
+
+ /**
* Set query options. At least one of the {@code MATCH} flags should be set. Otherwise,
* no shortcuts will be returned.
*
@@ -681,7 +704,7 @@
try {
return mService.getShortcuts(mContext.getPackageName(),
query.mChangedSince, query.mPackage, query.mShortcutIds, query.mActivity,
- query.mQueryFlags, user)
+ query.mIntent, query.mQueryFlags, user)
.getList();
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
@@ -1291,28 +1314,14 @@
public @interface RequestType {}
private final int mRequestType;
- private final ShortcutInfo mShortcutInfo;
- private final AppWidgetProviderInfo mAppWidgetInfo;
private final IPinItemRequest mInner;
/**
* @hide
*/
- public PinItemRequest(ShortcutInfo shortcutInfo, IPinItemRequest inner) {
- mRequestType = REQUEST_TYPE_SHORTCUT;
- mShortcutInfo = shortcutInfo;
- mAppWidgetInfo = null;
+ public PinItemRequest(IPinItemRequest inner, int type) {
mInner = inner;
- }
-
- /**
- * @hide
- */
- public PinItemRequest(AppWidgetProviderInfo appWidgetInfo, IPinItemRequest inner) {
- mRequestType = REQUEST_TYPE_APPWIDGET;
- mShortcutInfo = null;
- mAppWidgetInfo = appWidgetInfo;
- mInner = inner;
+ mRequestType = type;
}
/**
@@ -1330,7 +1339,11 @@
*/
@Nullable
public ShortcutInfo getShortcutInfo() {
- return mShortcutInfo;
+ try {
+ return mInner.getShortcutInfo();
+ } catch (RemoteException e) {
+ throw e.rethrowAsRuntimeException();
+ }
}
/**
@@ -1339,12 +1352,16 @@
*/
@Nullable
public AppWidgetProviderInfo getAppWidgetProviderInfo(Context context) {
- if (mAppWidgetInfo != null) {
- AppWidgetProviderInfo info = mAppWidgetInfo.clone();
+ try {
+ final AppWidgetProviderInfo info = mInner.getAppWidgetProviderInfo();
+ if (info == null) {
+ return null;
+ }
info.updateDimensions(context.getResources().getDisplayMetrics());
return info;
+ } catch (RemoteException e) {
+ throw e.rethrowAsRuntimeException();
}
- return null;
}
/**
@@ -1381,22 +1398,12 @@
final ClassLoader cl = getClass().getClassLoader();
mRequestType = source.readInt();
- mShortcutInfo = mRequestType == REQUEST_TYPE_SHORTCUT ?
- (ShortcutInfo) source.readParcelable(cl) : null;
- mAppWidgetInfo = mRequestType == REQUEST_TYPE_APPWIDGET ?
- (AppWidgetProviderInfo) source.readParcelable(cl) : null;
mInner = IPinItemRequest.Stub.asInterface(source.readStrongBinder());
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(mRequestType);
- if (mRequestType == REQUEST_TYPE_SHORTCUT) {
- dest.writeParcelable(mShortcutInfo, flags);
- }
- if (mRequestType == REQUEST_TYPE_APPWIDGET) {
- dest.writeParcelable(mAppWidgetInfo, flags);
- }
dest.writeStrongBinder(mInner.asBinder());
}
diff --git a/core/java/android/content/pm/ManifestDigest.aidl b/core/java/android/content/pm/ManifestDigest.aidl
deleted file mode 100644
index ebabab0..0000000
--- a/core/java/android/content/pm/ManifestDigest.aidl
+++ /dev/null
@@ -1,19 +0,0 @@
-/*
- * Copyright 2011, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.content.pm;
-
-parcelable ManifestDigest;
diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java
index 278a6d0..9d04cc9 100644
--- a/core/java/android/content/pm/PackageInstaller.java
+++ b/core/java/android/content/pm/PackageInstaller.java
@@ -95,6 +95,18 @@
@SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
public static final String ACTION_SESSION_DETAILS = "android.content.pm.action.SESSION_DETAILS";
+ /**
+ * Broadcast Action: Explicit broadcast sent to the last known default launcher when a session
+ * for a new install is committed. For managed profile, this is sent to the default launcher
+ * of the primary profile.
+ * <p>
+ * The associated session is defined in {@link #EXTRA_SESSION} and the user for which this
+ * session was created in {@link Intent#EXTRA_USER}.
+ */
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ public static final String ACTION_SESSION_COMMITTED =
+ "android.content.pm.action.SESSION_COMMITTED";
+
/** {@hide} */
public static final String
ACTION_CONFIRM_PERMISSIONS = "android.content.pm.action.CONFIRM_PERMISSIONS";
@@ -107,6 +119,13 @@
public static final String EXTRA_SESSION_ID = "android.content.pm.extra.SESSION_ID";
/**
+ * {@link SessionInfo} that an operation is working with.
+ *
+ * @see Intent#getParcelableExtra(String)
+ */
+ public static final String EXTRA_SESSION = "android.content.pm.extra.SESSION";
+
+ /**
* Package name that an operation is working with.
*
* @see Intent#getStringExtra(String)
@@ -1184,6 +1203,8 @@
/** {@hide} */
public int mode;
/** {@hide} */
+ public int installReason;
+ /** {@hide} */
public long sizeBytes;
/** {@hide} */
public String appPackageName;
@@ -1206,6 +1227,7 @@
active = source.readInt() != 0;
mode = source.readInt();
+ installReason = source.readInt();
sizeBytes = source.readLong();
appPackageName = source.readString();
appIcon = source.readParcelable(null);
@@ -1256,6 +1278,15 @@
return active;
}
+ /**
+ * Return the reason for installing this package.
+ *
+ * @see PackageManager#INSTALL_REASON_UNKNOWN
+ */
+ public int getInstallReason() {
+ return installReason;
+ }
+
/** {@hide} */
@Deprecated
public boolean isOpen() {
@@ -1324,6 +1355,7 @@
dest.writeInt(active ? 1 : 0);
dest.writeInt(mode);
+ dest.writeInt(installReason);
dest.writeLong(sizeBytes);
dest.writeString(appPackageName);
dest.writeParcelable(appIcon, flags);
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 5733982..0482f51 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -411,17 +411,6 @@
*/
public static final int MATCH_DIRECT_BOOT_AWARE = 0x00080000;
- /** @removed */
- @Deprecated
- public static final int MATCH_ENCRYPTION_UNAWARE = 0x00040000;
- /** @removed */
- @Deprecated
- public static final int MATCH_ENCRYPTION_AWARE = 0x00080000;
- /** @removed */
- @Deprecated
- public static final int MATCH_ENCRYPTION_AWARE_AND_UNAWARE = MATCH_ENCRYPTION_AWARE
- | MATCH_ENCRYPTION_UNAWARE;
-
/**
* Querying flag: include only components from applications that are marked
* with {@link ApplicationInfo#FLAG_SYSTEM}.
@@ -624,8 +613,10 @@
* should be installed as forward locked, i.e. only the app itself should
* have access to its code and non-resource assets.
*
+ * @deprecated new installs into ASEC containers are no longer supported.
* @hide
*/
+ @Deprecated
public static final int INSTALL_FORWARD_LOCK = 0x00000001;
/**
@@ -648,8 +639,11 @@
* Flag parameter for {@link #installPackage} to indicate that this package
* must be installed to an ASEC on a {@link VolumeInfo#TYPE_PUBLIC}.
*
+ * @deprecated new installs into ASEC containers are no longer supported;
+ * use adoptable storage instead.
* @hide
*/
+ @Deprecated
public static final int INSTALL_EXTERNAL = 0x00000008;
/**
@@ -4468,6 +4462,27 @@
String processName, int uid, @ComponentInfoFlags int flags);
/**
+ * Same as {@link #queryContentProviders}, except when {@code metaDataKey} is not null,
+ * it only returns providers which have metadata with the {@code metaDataKey} key.
+ *
+ * <p>DO NOT USE the {@code metaDataKey} parameter, unless you're the contacts provider.
+ * You really shouldn't need it. Other apps should use {@link #queryIntentContentProviders}
+ * instead.
+ *
+ * <p>The {@code metaDataKey} parameter was added to allow the contacts provider to quickly
+ * scan the GAL providers on the device. Unfortunately the discovery protocol used metadata
+ * to mark GAL providers, rather than intent filters, so we can't use
+ * {@link #queryIntentContentProviders} for that.
+ *
+ * @hide
+ */
+ public List<ProviderInfo> queryContentProviders(
+ String processName, int uid, @ComponentInfoFlags int flags, String metaDataKey) {
+ // Provide the default implementation for mocks.
+ return queryContentProviders(processName, uid, flags);
+ }
+
+ /**
* Retrieve all of the information we know about a particular
* instrumentation class.
*
diff --git a/core/java/android/content/pm/PackageManagerInternal.java b/core/java/android/content/pm/PackageManagerInternal.java
index 7d59bd6..6272822 100644
--- a/core/java/android/content/pm/PackageManagerInternal.java
+++ b/core/java/android/content/pm/PackageManagerInternal.java
@@ -213,12 +213,11 @@
* @param responseObj The response of the first phase of ephemeral resolution
* @param origIntent The original intent that triggered ephemeral resolution
* @param resolvedType The resolved type of the intent
- * @param launchIntent The intent that would launch if there was no ephemeral application
* @param callingPackage The name of the package requesting the ephemeral application
* @param userId The ID of the user that triggered ephemeral resolution
*/
- public abstract void requestEphemeralResolutionPhaseTwo(EphemeralResponse responseObj,
- Intent origIntent, String resolvedType, Intent launchIntent, String callingPackage,
+ public abstract void requestInstantAppResolutionPhaseTwo(AuxiliaryResolveInfo responseObj,
+ Intent origIntent, String resolvedType, String callingPackage,
int userId);
/**
@@ -307,4 +306,10 @@
*/
public abstract boolean setEnabledOverlayPackages(int userId, String targetPackageName,
List<String> overlayPackageNames);
+
+ /**
+ * Resolves an intent, allowing instant apps to be resolved.
+ */
+ public abstract ResolveInfo resolveIntent(Intent intent, String resolvedType,
+ int flags, int userId);
}
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 56f1e0c..f801e45 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -2065,9 +2065,6 @@
com.android.internal.R.styleable.AndroidManifestResourceOverlay);
pkg.mOverlayTarget = sa.getString(
com.android.internal.R.styleable.AndroidManifestResourceOverlay_targetPackage);
- pkg.mOverlayPriority = sa.getInt(
- com.android.internal.R.styleable.AndroidManifestResourceOverlay_priority,
- -1);
sa.recycle();
if (pkg.mOverlayTarget == null) {
@@ -2075,12 +2072,6 @@
mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
return null;
}
- if (pkg.mOverlayPriority < 0 || pkg.mOverlayPriority > 9999) {
- outError[0] = "<overlay> priority must be between 0 and 9999";
- mParseError =
- PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
- return null;
- }
XmlUtils.skipCurrentTag(parser);
} else if (tagName.equals(TAG_KEY_SETS)) {
@@ -5518,7 +5509,6 @@
public String mRequiredAccountType;
public String mOverlayTarget;
- public int mOverlayPriority;
public boolean mTrustedOverlay;
/**
@@ -5995,7 +5985,6 @@
mRestrictedAccountType = dest.readString();
mRequiredAccountType = dest.readString();
mOverlayTarget = dest.readString();
- mOverlayPriority = dest.readInt();
mTrustedOverlay = (dest.readInt() == 1);
mSigningKeys = (ArraySet<PublicKey>) dest.readArraySet(boot);
mUpgradeKeySets = (ArraySet<String>) dest.readArraySet(boot);
@@ -6111,7 +6100,6 @@
dest.writeString(mRestrictedAccountType);
dest.writeString(mRequiredAccountType);
dest.writeString(mOverlayTarget);
- dest.writeInt(mOverlayPriority);
dest.writeInt(mTrustedOverlay ? 1 : 0);
dest.writeArraySet(mSigningKeys);
dest.writeArraySet(mUpgradeKeySets);
@@ -6560,6 +6548,7 @@
ai.category = FallbackCategoryProvider.getFallbackCategory(ai.packageName);
}
ai.seInfoUser = SELinuxUtil.assignSeinfoUser(state);
+ ai.resourceDirs = state.resourceDirs;
}
public static ApplicationInfo generateApplicationInfo(Package p, int flags,
diff --git a/core/java/android/content/pm/PackageUserState.java b/core/java/android/content/pm/PackageUserState.java
index 24f1164..ee56a18 100644
--- a/core/java/android/content/pm/PackageUserState.java
+++ b/core/java/android/content/pm/PackageUserState.java
@@ -31,6 +31,8 @@
import com.android.internal.util.ArrayUtils;
+import java.util.Arrays;
+
/**
* Per-user state information about a package.
* @hide
@@ -54,6 +56,8 @@
public ArraySet<String> disabledComponents;
public ArraySet<String> enabledComponents;
+ public String[] resourceDirs;
+
public PackageUserState() {
installed = true;
hidden = false;
@@ -81,6 +85,8 @@
installReason = o.installReason;
disabledComponents = ArrayUtils.cloneOrNull(o.disabledComponents);
enabledComponents = ArrayUtils.cloneOrNull(o.enabledComponents);
+ resourceDirs =
+ o.resourceDirs == null ? null : Arrays.copyOf(o.resourceDirs, o.resourceDirs.length);
}
/**
diff --git a/core/java/android/content/pm/ParceledListSlice.java b/core/java/android/content/pm/ParceledListSlice.java
index 945858e6..d12e884 100644
--- a/core/java/android/content/pm/ParceledListSlice.java
+++ b/core/java/android/content/pm/ParceledListSlice.java
@@ -16,14 +16,9 @@
package android.content.pm;
-import android.os.Binder;
-import android.os.IBinder;
import android.os.Parcel;
import android.os.Parcelable;
-import android.os.RemoteException;
-import android.util.Log;
-import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@@ -31,171 +26,46 @@
* Transfer a large list of Parcelable objects across an IPC. Splits into
* multiple transactions if needed.
*
- * Caveat: for efficiency and security, all elements must be the same concrete type.
- * In order to avoid writing the class name of each object, we must ensure that
- * each object is the same type, or else unparceling then reparceling the data may yield
- * a different result if the class name encoded in the Parcelable is a Base type.
- * See b/17671747.
+ * @see BaseParceledListSlice
*
* @hide
*/
-public class ParceledListSlice<T extends Parcelable> implements Parcelable {
- private static String TAG = "ParceledListSlice";
- private static boolean DEBUG = false;
+public class ParceledListSlice<T extends Parcelable> extends BaseParceledListSlice<T> {
+ public ParceledListSlice(List<T> list) {
+ super(list);
+ }
- /*
- * TODO get this number from somewhere else. For now set it to a quarter of
- * the 1MB limit.
- */
- private static final int MAX_IPC_SIZE = IBinder.MAX_IPC_SIZE;
-
- private final List<T> mList;
+ private ParceledListSlice(Parcel in, ClassLoader loader) {
+ super(in, loader);
+ }
public static <T extends Parcelable> ParceledListSlice<T> emptyList() {
return new ParceledListSlice<T>(Collections.<T> emptyList());
}
- public ParceledListSlice(List<T> list) {
- mList = list;
- }
-
- @SuppressWarnings("unchecked")
- private ParceledListSlice(Parcel p, ClassLoader loader) {
- final int N = p.readInt();
- mList = new ArrayList<T>(N);
- if (DEBUG) Log.d(TAG, "Retrieving " + N + " items");
- if (N <= 0) {
- return;
- }
-
- Parcelable.Creator<?> creator = p.readParcelableCreator(loader);
- Class<?> listElementClass = null;
-
- int i = 0;
- while (i < N) {
- if (p.readInt() == 0) {
- break;
- }
-
- final T parcelable = p.readCreator(creator, loader);
- if (listElementClass == null) {
- listElementClass = parcelable.getClass();
- } else {
- verifySameType(listElementClass, parcelable.getClass());
- }
-
- mList.add(parcelable);
-
- if (DEBUG) Log.d(TAG, "Read inline #" + i + ": " + mList.get(mList.size()-1));
- i++;
- }
- if (i >= N) {
- return;
- }
- final IBinder retriever = p.readStrongBinder();
- while (i < N) {
- if (DEBUG) Log.d(TAG, "Reading more @" + i + " of " + N + ": retriever=" + retriever);
- Parcel data = Parcel.obtain();
- Parcel reply = Parcel.obtain();
- data.writeInt(i);
- try {
- retriever.transact(IBinder.FIRST_CALL_TRANSACTION, data, reply, 0);
- } catch (RemoteException e) {
- Log.w(TAG, "Failure retrieving array; only received " + i + " of " + N, e);
- return;
- }
- while (i < N && reply.readInt() != 0) {
- final T parcelable = reply.readCreator(creator, loader);
- verifySameType(listElementClass, parcelable.getClass());
-
- mList.add(parcelable);
-
- if (DEBUG) Log.d(TAG, "Read extra #" + i + ": " + mList.get(mList.size()-1));
- i++;
- }
- reply.recycle();
- data.recycle();
- }
- }
-
- private static void verifySameType(final Class<?> expected, final Class<?> actual) {
- if (!actual.equals(expected)) {
- throw new IllegalArgumentException("Can't unparcel type "
- + actual.getName() + " in list of type "
- + expected.getName());
- }
- }
-
- public List<T> getList() {
- return mList;
- }
-
@Override
public int describeContents() {
int contents = 0;
- for (int i=0; i<mList.size(); i++) {
- contents |= mList.get(i).describeContents();
+ final List<T> list = getList();
+ for (int i=0; i<list.size(); i++) {
+ contents |= list.get(i).describeContents();
}
return contents;
}
- /**
- * Write this to another Parcel. Note that this discards the internal Parcel
- * and should not be used anymore. This is so we can pass this to a Binder
- * where we won't have a chance to call recycle on this.
- */
@Override
- public void writeToParcel(Parcel dest, int flags) {
- final int N = mList.size();
- final int callFlags = flags;
- dest.writeInt(N);
- if (DEBUG) Log.d(TAG, "Writing " + N + " items");
- if (N > 0) {
- final Class<?> listElementClass = mList.get(0).getClass();
- dest.writeParcelableCreator(mList.get(0));
- int i = 0;
- while (i < N && dest.dataSize() < MAX_IPC_SIZE) {
- dest.writeInt(1);
+ protected void writeElement(T parcelable, Parcel dest, int callFlags) {
+ parcelable.writeToParcel(dest, callFlags);
+ }
- final T parcelable = mList.get(i);
- verifySameType(listElementClass, parcelable.getClass());
- parcelable.writeToParcel(dest, callFlags);
+ @Override
+ protected void writeParcelableCreator(T parcelable, Parcel dest) {
+ dest.writeParcelableCreator((Parcelable) parcelable);
+ }
- if (DEBUG) Log.d(TAG, "Wrote inline #" + i + ": " + mList.get(i));
- i++;
- }
- if (i < N) {
- dest.writeInt(0);
- Binder retriever = new Binder() {
- @Override
- protected boolean onTransact(int code, Parcel data, Parcel reply, int flags)
- throws RemoteException {
- if (code != FIRST_CALL_TRANSACTION) {
- return super.onTransact(code, data, reply, flags);
- }
- int i = data.readInt();
- if (DEBUG) Log.d(TAG, "Writing more @" + i + " of " + N);
- while (i < N && reply.dataSize() < MAX_IPC_SIZE) {
- reply.writeInt(1);
-
- final T parcelable = mList.get(i);
- verifySameType(listElementClass, parcelable.getClass());
- parcelable.writeToParcel(reply, callFlags);
-
- if (DEBUG) Log.d(TAG, "Wrote extra #" + i + ": " + mList.get(i));
- i++;
- }
- if (i < N) {
- if (DEBUG) Log.d(TAG, "Breaking @" + i + " of " + N);
- reply.writeInt(0);
- }
- return true;
- }
- };
- if (DEBUG) Log.d(TAG, "Breaking @" + i + " of " + N + ": retriever=" + retriever);
- dest.writeStrongBinder(retriever);
- }
- }
+ @Override
+ protected Parcelable.Creator<?> readParcelableCreator(Parcel from, ClassLoader loader) {
+ return from.readParcelableCreator(loader);
}
@SuppressWarnings("unchecked")
@@ -210,6 +80,7 @@
return new ParceledListSlice(in, loader);
}
+ @Override
public ParceledListSlice[] newArray(int size) {
return new ParceledListSlice[size];
}
diff --git a/core/java/android/content/pm/ResolveInfo.java b/core/java/android/content/pm/ResolveInfo.java
index f8b4570..650b4c0 100644
--- a/core/java/android/content/pm/ResolveInfo.java
+++ b/core/java/android/content/pm/ResolveInfo.java
@@ -61,11 +61,17 @@
public ProviderInfo providerInfo;
/**
- * The ephemeral application that corresponds to this resolution match. This will
- * only be set in specific circumstances.
+ * An auxiliary response that may modify the resolved information. This is
+ * only set under certain circumstances; such as when resolving instant apps
+ * or components defined in un-installed splits.
* @hide
*/
- public EphemeralResponse ephemeralResponse;
+ public AuxiliaryResolveInfo auxiliaryInfo;
+
+ /**
+ * Whether or not an instant app is available for the resolved intent.
+ */
+ public boolean instantAppAvailable;
/**
* The IntentFilter that was matched for this ResolveInfo.
@@ -324,6 +330,7 @@
system = orig.system;
targetUserId = orig.targetUserId;
handleAllWebDataURI = orig.handleAllWebDataURI;
+ instantAppAvailable = orig.instantAppAvailable;
}
public String toString() {
@@ -387,6 +394,7 @@
dest.writeInt(noResourceId ? 1 : 0);
dest.writeInt(iconResourceId);
dest.writeInt(handleAllWebDataURI ? 1 : 0);
+ dest.writeInt(instantAppAvailable ? 1 : 0);
}
public static final Creator<ResolveInfo> CREATOR
@@ -434,6 +442,7 @@
noResourceId = source.readInt() != 0;
iconResourceId = source.readInt();
handleAllWebDataURI = source.readInt() != 0;
+ instantAppAvailable = source.readInt() != 0;
}
public static class DisplayNameComparator
diff --git a/core/java/android/content/pm/ShortcutInfo.java b/core/java/android/content/pm/ShortcutInfo.java
index f1f2683..d3d3c66 100644
--- a/core/java/android/content/pm/ShortcutInfo.java
+++ b/core/java/android/content/pm/ShortcutInfo.java
@@ -21,8 +21,10 @@
import android.annotation.UserIdInt;
import android.app.TaskStackBuilder;
import android.content.ComponentName;
+import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
+import android.content.IntentFilter;
import android.content.pm.LauncherApps.ShortcutQuery;
import android.content.res.Resources;
import android.content.res.Resources.NotFoundException;
@@ -38,10 +40,12 @@
import android.util.Log;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.MemInfoReader;
import com.android.internal.util.Preconditions;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
import java.util.List;
import java.util.Set;
@@ -95,6 +99,14 @@
public static final int FLAG_MASKABLE_BITMAP = 1 << 9;
/** @hide */
+ public static final int FLAG_CHOOSER = 1 << 10;
+
+ /**
+ * TODO: Add FLAG_CHOOSER_INFO_OMITTED to reflect that chooser info was omitted in the Shortcut
+ * due to the context in which it was retrieved.
+ * TODO: Add a FLAG_LAUNCHABLE to reflect whether or not the Shortcut has a launchable intent
+ * @hide
+ */
@IntDef(flag = true,
value = {
FLAG_DYNAMIC,
@@ -107,6 +119,7 @@
FLAG_STRINGS_RESOLVED,
FLAG_IMMUTABLE,
FLAG_MASKABLE_BITMAP,
+ FLAG_CHOOSER,
})
@Retention(RetentionPolicy.SOURCE)
public @interface ShortcutFlags {}
@@ -201,6 +214,24 @@
@Nullable
private PersistableBundle[] mIntentPersistableExtrases;
+ /**
+ * If used in a chooser, extras that should be added into the intent passed through.
+ */
+ @Nullable
+ private PersistableBundle mChooserExtras;
+
+ /**
+ * Intent filters to be used if the shortcut is to be used in a chooser context.
+ */
+ @Nullable
+ private IntentFilter[] mChooserIntentFilters;
+
+ /**
+ * Component names corresponding to the above intent filters.
+ */
+ @Nullable
+ private ComponentName[] mChooserComponentNames;
+
private int mRank;
/**
@@ -250,6 +281,13 @@
mDisabledMessageResId = b.mDisabledMessageResId;
mCategories = cloneCategories(b.mCategories);
mIntents = cloneIntents(b.mIntents);
+ if (b.mChooserIntentFilters != null) {
+ mChooserIntentFilters = b.mChooserIntentFilters.toArray(new IntentFilter[0]);
+ }
+ if (b.mChooserComponentNames != null) {
+ mChooserComponentNames = b.mChooserComponentNames.toArray(new ComponentName[0]);
+ }
+ mChooserExtras = b.mChooserExtras;
fixUpIntentExtras();
mRank = b.mRank;
mExtras = b.mExtras;
@@ -330,8 +368,28 @@
if (mTitle == null && mTitleResId == 0) {
throw new IllegalArgumentException("Short label must be provided");
}
- Preconditions.checkNotNull(mIntents, "Shortcut Intent must be provided");
- Preconditions.checkArgument(mIntents.length > 0, "Shortcut Intent must be provided");
+
+ // For a shortcut to be valid, there should either be an Intent, or a non-empty set of
+ // intent filters.
+ if (mIntents == null || mIntents.length == 0) {
+ Preconditions.checkNotNull(mChooserIntentFilters,
+ "Intent must be provided if not a chooser target");
+ Preconditions.checkNotNull(mChooserComponentNames,
+ "Intent must be provided if not a chooser target");
+ }
+
+ // If ChooserIntentFilter are provided, they should match the length of the provided
+ // component names.
+ if (mChooserIntentFilters != null) {
+ if (mChooserComponentNames == null
+ || mChooserIntentFilters.length != mChooserComponentNames.length) {
+ throw new IllegalArgumentException("Inconsistent intent filters and "
+ + "component names given");
+ }
+ if (mChooserIntentFilters.length == 0 || mChooserComponentNames.length == 0) {
+ throw new IllegalArgumentException("Empty intent filter and component names given");
+ }
+ }
}
/**
@@ -376,6 +434,10 @@
mDisabledMessageResName = source.mDisabledMessageResName;
mIconResName = source.mIconResName;
}
+ // TODO: Omit these by default and add a new clone flag.
+ mChooserIntentFilters = source.mChooserIntentFilters;
+ mChooserComponentNames = source.mChooserComponentNames;
+ mChooserExtras = source.mChooserExtras;
} else {
// Set this bit.
mFlags |= FLAG_KEY_FIELDS_ONLY;
@@ -503,6 +565,25 @@
}
/**
+ * Whether the shortcut has any intentFilter matching the passed in one.
+ * @hide
+ */
+ @VisibleForTesting
+ public boolean hasMatchingFilter(ContentResolver resolver, Intent intent) {
+ if (mChooserIntentFilters == null) {
+ return false;
+ }
+ for (IntentFilter filter : mChooserIntentFilters) {
+ int match = filter.match(resolver, intent, false, TAG);
+ if (match > 0) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+
+ /**
* Extract the entry name from a fully-donated resource name.
* e.g. "com.android.app1:drawable/icon1" -> "icon1"
* @hide
@@ -685,6 +766,15 @@
if (source.mExtras != null) {
mExtras = source.mExtras;
}
+ if (source.mChooserExtras != null) {
+ mChooserExtras = source.mChooserExtras;
+ }
+ if (source.mChooserIntentFilters != null) {
+ mChooserIntentFilters = source.mChooserIntentFilters;
+ }
+ if (source.mChooserComponentNames != null) {
+ mChooserComponentNames = source.mChooserComponentNames;
+ }
}
/**
@@ -746,6 +836,12 @@
private PersistableBundle mExtras;
+ private PersistableBundle mChooserExtras;
+
+ private List<IntentFilter> mChooserIntentFilters;
+
+ private List<ComponentName> mChooserComponentNames;
+
/**
* Old style constructor.
* @hide
@@ -1032,6 +1128,40 @@
}
/**
+ * Extras that can be added which will be added to the Intent used to launch the app if
+ * launched from a chooser context.
+ */
+ @NonNull
+ public Builder setChooserExtras(@NonNull PersistableBundle extras) {
+ mChooserExtras = extras;
+ return this;
+ }
+
+ /**
+ * IntentFilters and the components that should resolve a match for a given chooser target.
+ * If multiple matches are found, the component corresponding to the closest match will be
+ * used.
+ *
+ * @param filter IntendFilter that if matched will have the intent forwarded to the given
+ * component
+ * @param name The component that an intent that passes this filter will resolve to.
+ */
+ public Builder addChooserIntentFilter(@NonNull IntentFilter filter,
+ @NonNull ComponentName name) {
+ Preconditions.checkNotNull(filter, "intent filter cannot be null");
+ Preconditions.checkNotNull(name, "component name cannot be null");
+
+ if (mChooserIntentFilters == null || mChooserComponentNames == null) {
+ mChooserIntentFilters = new ArrayList<>();
+ mChooserComponentNames = new ArrayList<>();
+ }
+
+ mChooserIntentFilters.add(filter);
+ mChooserComponentNames.add(name);
+ return this;
+ }
+
+ /**
* Creates a {@link ShortcutInfo} instance.
*/
@NonNull
@@ -1232,6 +1362,30 @@
}
/**
+ * Retrieve the extras that will be added in to any intent launched through the chooser.
+ */
+ @NonNull
+ public PersistableBundle getChooserExtras() {
+ return mChooserExtras;
+ }
+
+ /**
+ * Retrieve the list of intent filters for chooser targets.
+ */
+ @NonNull
+ public IntentFilter[] getChooserIntentFilters() {
+ return mChooserIntentFilters;
+ }
+
+ /**
+ * Retrieve the list of component names corresponding to the above intent filters.
+ */
+ @NonNull
+ public ComponentName[] getChooserComponentNames() {
+ return mChooserComponentNames;
+ }
+
+ /**
* "Rank" of a shortcut, which is a non-negative, sequential value that's unique for each
* {@link #getActivity} for each of the two types of shortcuts (static and dynamic).
*
@@ -1352,6 +1506,11 @@
return hasFlags(FLAG_PINNED);
}
+ /** Return whether a shortcut can be shown in the chooser. */
+ public boolean isChooser() {
+ return hasFlags(FLAG_CHOOSER);
+ }
+
/**
* Return whether a shortcut is static; that is, whether a shortcut is
* published from AndroidManifest.xml. If {@code true}, the shortcut is
@@ -1380,6 +1539,14 @@
return isPinned() && !(isDynamic() || isManifestShortcut());
}
+ /**
+ * @return true if pinned but neither static nor dynamic.
+ * @hide
+ */
+ public boolean isDynamicOrChooser() {
+ return hasFlags(FLAG_DYNAMIC) || hasFlags(FLAG_CHOOSER);
+ }
+
/** @hide */
public boolean isOriginallyFromManifest() {
return hasFlags(FLAG_IMMUTABLE);
@@ -1661,6 +1828,19 @@
mCategories.add(source.readString().intern());
}
}
+
+ // We put a placeholder empty array in to keep the parcelable order, but can do away with
+ // them at this point if they're empty.
+ mChooserComponentNames = source.readParcelableArray(cl, ComponentName.class);
+ if (mChooserComponentNames.length == 0) {
+ mChooserComponentNames = null;
+ }
+
+ mChooserIntentFilters = source.readParcelableArray(cl, IntentFilter.class);
+ if (mChooserIntentFilters.length == 0) {
+ mChooserIntentFilters = null;
+ }
+ mChooserExtras = source.readPersistableBundle(cl);
}
@Override
@@ -1707,6 +1887,17 @@
} else {
dest.writeInt(0);
}
+ if (mChooserComponentNames != null) {
+ dest.writeParcelableArray(mChooserComponentNames, flags);
+ } else {
+ dest.writeParcelableArray(new ComponentName[0], flags);
+ }
+ if (mChooserIntentFilters != null) {
+ dest.writeParcelableArray(mChooserIntentFilters, flags);
+ } else {
+ dest.writeParcelableArray(new IntentFilter[0], flags);
+ }
+ dest.writePersistableBundle(mChooserExtras);
}
public static final Creator<ShortcutInfo> CREATOR =
diff --git a/core/java/android/content/pm/ShortcutServiceInternal.java b/core/java/android/content/pm/ShortcutServiceInternal.java
index 87a6d4a..696fe81 100644
--- a/core/java/android/content/pm/ShortcutServiceInternal.java
+++ b/core/java/android/content/pm/ShortcutServiceInternal.java
@@ -44,8 +44,8 @@
getShortcuts(int launcherUserId,
@NonNull String callingPackage, long changedSince,
@Nullable String packageName, @Nullable List<String> shortcutIds,
- @Nullable ComponentName componentName, @ShortcutQuery.QueryFlags int flags,
- int userId);
+ @Nullable ComponentName componentName, @Nullable Intent intent,
+ @ShortcutQuery.QueryFlags int flags, int userId);
public abstract boolean
isPinnedByCaller(int launcherUserId, @NonNull String callingPackage,
diff --git a/core/java/android/content/pm/ContainerEncryptionParams.aidl b/core/java/android/content/pm/StringParceledListSlice.aidl
similarity index 86%
rename from core/java/android/content/pm/ContainerEncryptionParams.aidl
rename to core/java/android/content/pm/StringParceledListSlice.aidl
index c13d946..345f3a7 100644
--- a/core/java/android/content/pm/ContainerEncryptionParams.aidl
+++ b/core/java/android/content/pm/StringParceledListSlice.aidl
@@ -1,5 +1,5 @@
/*
- * Copyright 2012, The Android Open Source Project
+ * Copyright 2017, 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.
@@ -16,4 +16,4 @@
package android.content.pm;
-parcelable ContainerEncryptionParams;
+parcelable StringParceledListSlice;
diff --git a/core/java/android/content/pm/StringParceledListSlice.java b/core/java/android/content/pm/StringParceledListSlice.java
new file mode 100644
index 0000000..9540744
--- /dev/null
+++ b/core/java/android/content/pm/StringParceledListSlice.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.content.pm;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Transfer a large list of Parcelable objects across an IPC. Splits into
+ * multiple transactions if needed.
+ *
+ * @see BaseParceledListSlice
+ *
+ * @hide
+ */
+public class StringParceledListSlice extends BaseParceledListSlice<String> {
+ public StringParceledListSlice(List<String> list) {
+ super(list);
+ }
+
+ private StringParceledListSlice(Parcel in, ClassLoader loader) {
+ super(in, loader);
+ }
+
+ public static StringParceledListSlice emptyList() {
+ return new StringParceledListSlice(Collections.<String> emptyList());
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ protected void writeElement(String parcelable, Parcel reply, int callFlags) {
+ reply.writeString(parcelable);
+ }
+
+ @Override
+ protected void writeParcelableCreator(String parcelable, Parcel dest) {
+ return;
+ }
+
+ @Override
+ protected Parcelable.Creator<?> readParcelableCreator(Parcel from, ClassLoader loader) {
+ return Parcel.STRING_CREATOR;
+ }
+
+ @SuppressWarnings("unchecked")
+ public static final Parcelable.ClassLoaderCreator<StringParceledListSlice> CREATOR =
+ new Parcelable.ClassLoaderCreator<StringParceledListSlice>() {
+ public StringParceledListSlice createFromParcel(Parcel in) {
+ return new StringParceledListSlice(in, null);
+ }
+
+ @Override
+ public StringParceledListSlice createFromParcel(Parcel in, ClassLoader loader) {
+ return new StringParceledListSlice(in, loader);
+ }
+
+ @Override
+ public StringParceledListSlice[] newArray(int size) {
+ return new StringParceledListSlice[size];
+ }
+ };
+}
diff --git a/core/java/android/content/res/AssetManager.java b/core/java/android/content/res/AssetManager.java
index 37e32ff..4cf55ba 100644
--- a/core/java/android/content/res/AssetManager.java
+++ b/core/java/android/content/res/AssetManager.java
@@ -222,19 +222,21 @@
*/
final boolean getResourceValue(@AnyRes int resId, int densityDpi, @NonNull TypedValue outValue,
boolean resolveRefs) {
- final int block = loadResourceValue(resId, (short) densityDpi, outValue, resolveRefs);
- if (block < 0) {
- return false;
- }
+ synchronized (this) {
+ final int block = loadResourceValue(resId, (short) densityDpi, outValue, resolveRefs);
+ if (block < 0) {
+ return false;
+ }
- // Convert the changing configurations flags populated by native code.
- outValue.changingConfigurations = ActivityInfo.activityInfoConfigNativeToJava(
- outValue.changingConfigurations);
+ // Convert the changing configurations flags populated by native code.
+ outValue.changingConfigurations = ActivityInfo.activityInfoConfigNativeToJava(
+ outValue.changingConfigurations);
- if (outValue.type == TypedValue.TYPE_STRING) {
- outValue.string = mStringBlocks[block].get(outValue.data);
+ if (outValue.type == TypedValue.TYPE_STRING) {
+ outValue.string = mStringBlocks[block].get(outValue.data);
+ }
+ return true;
}
- return true;
}
/**
@@ -244,18 +246,20 @@
* @param resId the resource id of the string array
*/
final CharSequence[] getResourceTextArray(@ArrayRes int resId) {
- final int[] rawInfoArray = getArrayStringInfo(resId);
- final int rawInfoArrayLen = rawInfoArray.length;
- final int infoArrayLen = rawInfoArrayLen / 2;
- int block;
- int index;
- final CharSequence[] retArray = new CharSequence[infoArrayLen];
- for (int i = 0, j = 0; i < rawInfoArrayLen; i = i + 2, j++) {
- block = rawInfoArray[i];
- index = rawInfoArray[i + 1];
- retArray[j] = index >= 0 ? mStringBlocks[block].get(index) : null;
+ synchronized (this) {
+ final int[] rawInfoArray = getArrayStringInfo(resId);
+ final int rawInfoArrayLen = rawInfoArray.length;
+ final int infoArrayLen = rawInfoArrayLen / 2;
+ int block;
+ int index;
+ final CharSequence[] retArray = new CharSequence[infoArrayLen];
+ for (int i = 0, j = 0; i < rawInfoArrayLen; i = i + 2, j++) {
+ block = rawInfoArray[i];
+ index = rawInfoArray[i + 1];
+ retArray[j] = index >= 0 ? mStringBlocks[block].get(index) : null;
+ }
+ return retArray;
}
- return retArray;
}
/**
@@ -320,8 +324,10 @@
}
/*package*/ final CharSequence getPooledStringForCookie(int cookie, int id) {
- // Cookies map to string blocks starting at 1.
- return mStringBlocks[cookie - 1].get(id);
+ synchronized (this) {
+ // Cookies map to string blocks starting at 1.
+ return mStringBlocks[cookie - 1].get(id);
+ }
}
/**
diff --git a/core/java/android/content/res/ColorStateList.java b/core/java/android/content/res/ColorStateList.java
index 273522a..a46db06 100644
--- a/core/java/android/content/res/ColorStateList.java
+++ b/core/java/android/content/res/ColorStateList.java
@@ -508,8 +508,8 @@
}
/**
- * Indicates whether this color state list contains more than one state spec
- * and will change color based on state.
+ * Indicates whether this color state list contains at least one state spec
+ * and the first spec is not empty (e.g. match-all).
*
* @return True if this color state list changes color based on state, false
* otherwise.
@@ -517,7 +517,7 @@
*/
@Override
public boolean isStateful() {
- return mStateSpecs.length > 1;
+ return mStateSpecs.length >= 1 && mStateSpecs[0].length > 0;
}
/**
diff --git a/core/java/android/content/res/CompatResources.java b/core/java/android/content/res/CompatResources.java
new file mode 100644
index 0000000..15575fd
--- /dev/null
+++ b/core/java/android/content/res/CompatResources.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the
+ * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+package android.content.res;
+
+import android.annotation.ColorRes;
+import android.annotation.DrawableRes;
+import android.content.Context;
+import android.graphics.drawable.Drawable;
+
+import java.lang.ref.WeakReference;
+
+/**
+ * Version of resources generated for apps targeting <26.
+ * @hide
+ */
+public class CompatResources extends Resources {
+
+ private final WeakReference<Context> mContext;
+
+ public CompatResources(Resources base, Context context) {
+ super(base.getClassLoader());
+ setImpl(base.getImpl());
+ mContext = new WeakReference<>(context);
+ }
+
+ @Override
+ public Drawable getDrawable(@DrawableRes int id) throws NotFoundException {
+ return getDrawable(id, getTheme());
+ }
+
+ @Override
+ public Drawable getDrawableForDensity(@DrawableRes int id, int density)
+ throws NotFoundException {
+ return getDrawableForDensity(id, density, getTheme());
+ }
+
+ @Override
+ public int getColor(@ColorRes int id) throws NotFoundException {
+ return getColor(id, getTheme());
+ }
+
+ @Override
+ public ColorStateList getColorStateList(@ColorRes int id) throws NotFoundException {
+ return getColorStateList(id, getTheme());
+ }
+
+ private Theme getTheme() {
+ Context c = mContext.get();
+ return c != null ? c.getTheme() : null;
+ }
+}
diff --git a/core/java/android/hardware/display/DisplayManager.java b/core/java/android/hardware/display/DisplayManager.java
index 33a9f5e..a529c2f 100644
--- a/core/java/android/hardware/display/DisplayManager.java
+++ b/core/java/android/hardware/display/DisplayManager.java
@@ -339,8 +339,7 @@
private Display getOrCreateDisplayLocked(int displayId, boolean assumeValid) {
Display display = mDisplays.get(displayId);
if (display == null) {
- display = mGlobal.getCompatibleDisplay(displayId,
- mContext.getDisplayAdjustments(displayId));
+ display = mGlobal.getCompatibleDisplay(displayId, mContext.getResources());
if (display != null) {
mDisplays.put(displayId, display);
}
diff --git a/core/java/android/hardware/display/DisplayManagerGlobal.java b/core/java/android/hardware/display/DisplayManagerGlobal.java
index 826eb74..341754c 100644
--- a/core/java/android/hardware/display/DisplayManagerGlobal.java
+++ b/core/java/android/hardware/display/DisplayManagerGlobal.java
@@ -18,6 +18,7 @@
import android.content.Context;
import android.content.res.Configuration;
+import android.content.res.Resources;
import android.hardware.display.DisplayManager.DisplayListener;
import android.media.projection.MediaProjection;
import android.media.projection.IMediaProjection;
@@ -181,6 +182,24 @@
}
/**
+ * Gets information about a logical display.
+ *
+ * The display metrics may be adjusted to provide compatibility
+ * for legacy applications or limited screen areas.
+ *
+ * @param displayId The logical display id.
+ * @param resources Resources providing compatibility info.
+ * @return The display object, or null if there is no display with the given id.
+ */
+ public Display getCompatibleDisplay(int displayId, Resources resources) {
+ DisplayInfo displayInfo = getDisplayInfo(displayId);
+ if (displayInfo == null) {
+ return null;
+ }
+ return new Display(this, displayId, displayInfo, resources);
+ }
+
+ /**
* Gets information about a logical display without applying any compatibility metrics.
*
* @param displayId The logical display id.
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index e6f3021..1259de6 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -2952,15 +2952,6 @@
* @hide
*/
public void requestNetwork(NetworkRequest request, NetworkCallback networkCallback,
- int timeoutMs, int legacyType) {
- requestNetwork(request, networkCallback, timeoutMs, legacyType, getDefaultHandler());
- }
-
- /**
- * Helper function to request a network with a particular legacy type.
- * @hide
- */
- private void requestNetwork(NetworkRequest request, NetworkCallback networkCallback,
int timeoutMs, int legacyType, Handler handler) {
CallbackHandler cbHandler = new CallbackHandler(handler);
NetworkCapabilities nc = request.networkCapabilities;
@@ -3062,7 +3053,7 @@
public void requestNetwork(NetworkRequest request, NetworkCallback networkCallback,
int timeoutMs) {
int legacyType = inferLegacyTypeForNetworkCapabilities(request.networkCapabilities);
- requestNetwork(request, networkCallback, timeoutMs, legacyType);
+ requestNetwork(request, networkCallback, timeoutMs, legacyType, getDefaultHandler());
}
diff --git a/core/java/android/net/ConnectivityMetricsEvent.aidl b/core/java/android/net/ConnectivityMetricsEvent.aidl
index a027d7c..1c541dc 100644
--- a/core/java/android/net/ConnectivityMetricsEvent.aidl
+++ b/core/java/android/net/ConnectivityMetricsEvent.aidl
@@ -16,5 +16,5 @@
package android.net;
+/** {@hide} */
parcelable ConnectivityMetricsEvent;
-parcelable ConnectivityMetricsEvent.Reference;
diff --git a/core/java/android/net/ConnectivityMetricsEvent.java b/core/java/android/net/ConnectivityMetricsEvent.java
index eaaef7f..6fdc739 100644
--- a/core/java/android/net/ConnectivityMetricsEvent.java
+++ b/core/java/android/net/ConnectivityMetricsEvent.java
@@ -16,12 +16,10 @@
package android.net;
-import android.annotation.SystemApi;
import android.os.Parcel;
import android.os.Parcelable;
/** {@hide} */
-@SystemApi
public final class ConnectivityMetricsEvent implements Parcelable {
/** The time when this event was collected, as returned by System.currentTimeMillis(). */
@@ -67,7 +65,6 @@
return 0;
}
- /** Implement the Parcelable interface */
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeLong(timestamp);
@@ -80,51 +77,4 @@
return String.format("ConnectivityMetricsEvent(%tT.%tL, %d, %d): %s",
timestamp, timestamp, componentTag, eventTag, data);
}
-
- /** {@hide} */
- @SystemApi
- public final static class Reference implements Parcelable {
-
- private long mValue;
-
- public Reference(long ref) {
- this.mValue = ref;
- }
-
- /** Implement the Parcelable interface */
- public static final Parcelable.Creator<Reference> CREATOR
- = new Parcelable.Creator<Reference> (){
- public Reference createFromParcel(Parcel source) {
- return new Reference(source.readLong());
- }
-
- public Reference[] newArray(int size) {
- return new Reference[size];
- }
- };
-
- /** Implement the Parcelable interface */
- @Override
- public int describeContents() {
- return 0;
- }
-
- /** Implement the Parcelable interface */
- @Override
- public void writeToParcel(Parcel dest, int flags) {
- dest.writeLong(mValue);
- }
-
- public void readFromParcel(Parcel in) {
- mValue = in.readLong();
- }
-
- public long getValue() {
- return mValue;
- }
-
- public void setValue(long val) {
- mValue = val;
- }
- }
}
diff --git a/core/java/android/net/ConnectivityMetricsLogger.java b/core/java/android/net/ConnectivityMetricsLogger.java
deleted file mode 100644
index 67b6908..0000000
--- a/core/java/android/net/ConnectivityMetricsLogger.java
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.net;
-
-import android.annotation.SystemApi;
-import android.app.PendingIntent;
-import android.os.Bundle;
-import android.os.Parcelable;
-import android.os.RemoteException;
-import android.os.ServiceManager;
-import android.util.Log;
-
-import com.android.internal.annotations.VisibleForTesting;
-
-/** {@hide} */
-@SystemApi
-public class ConnectivityMetricsLogger {
- private static String TAG = "ConnectivityMetricsLogger";
- private static final boolean DBG = true;
-
- public static final String CONNECTIVITY_METRICS_LOGGER_SERVICE = "connectivity_metrics_logger";
-
- // Component Tags
- public static final int COMPONENT_TAG_CONNECTIVITY = 0;
- public static final int COMPONENT_TAG_BLUETOOTH = 1;
- public static final int COMPONENT_TAG_WIFI = 2;
- public static final int COMPONENT_TAG_TELECOM = 3;
- public static final int COMPONENT_TAG_TELEPHONY = 4;
- public static final int NUMBER_OF_COMPONENTS = 5;
-
- // Event Tag
- public static final int TAG_SKIPPED_EVENTS = -1;
-
- public static final String DATA_KEY_EVENTS_COUNT = "count";
-
- public ConnectivityMetricsLogger() {
- }
-
- /**
- * Log a ConnectivityMetricsEvent.
- *
- * This method keeps track of skipped events when MetricsLoggerService throttles input events.
- * It skips logging when MetricsLoggerService is active. When throttling ends, it logs a
- * meta-event containing the number of events dropped. It is not safe to call this method
- * concurrently from different threads.
- *
- * @param timestamp is the epoch timestamp of the event in ms.
- * @param componentTag is the COMPONENT_* constant the event belongs to.
- * @param eventTag is an event type constant whose meaning is specific to the component tag.
- * @param data is a Parcelable instance representing the event.
- */
- public void logEvent(long timestamp, int componentTag, int eventTag, Parcelable data) {
- }
-
- /**
- * Retrieve events
- *
- * @param reference of the last event previously returned. The function will return
- * events following it.
- * If 0 then all events will be returned.
- * After the function call it will contain reference of the
- * last returned event.
- * @return events
- */
- public ConnectivityMetricsEvent[] getEvents(ConnectivityMetricsEvent.Reference reference) {
- return new ConnectivityMetricsEvent[0];
- }
-
- /**
- * Register PendingIntent which will be sent when new events are ready to be retrieved.
- */
- public boolean register(PendingIntent newEventsIntent) {
- return false;
- }
-
- public boolean unregister(PendingIntent newEventsIntent) {
- return false;
- }
-}
diff --git a/core/java/android/net/IConnectivityMetricsLogger.aidl b/core/java/android/net/IConnectivityMetricsLogger.aidl
deleted file mode 100644
index a83a019..0000000
--- a/core/java/android/net/IConnectivityMetricsLogger.aidl
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net;
-
-import android.app.PendingIntent;
-import android.net.ConnectivityMetricsEvent;
-
-/** {@hide} */
-interface IConnectivityMetricsLogger {
-
- /**
- * @return 0 on success
- * <0 if error happened
- * >0 timestamp after which new events will be accepted
- */
- long logEvent(in ConnectivityMetricsEvent event);
- long logEvents(in ConnectivityMetricsEvent[] events);
-
- /**
- * @param reference of the last event previously returned. The function will return
- * events following it.
- * If 0 then all events will be returned.
- * After the function call it will contain reference of the last event.
- */
- ConnectivityMetricsEvent[] getEvents(inout ConnectivityMetricsEvent.Reference reference);
-
- boolean register(in PendingIntent newEventsIntent);
- void unregister(in PendingIntent newEventsIntent);
-}
diff --git a/core/java/android/net/INetworkScoreService.aidl b/core/java/android/net/INetworkScoreService.aidl
index f249daf..362ea9d 100644
--- a/core/java/android/net/INetworkScoreService.aidl
+++ b/core/java/android/net/INetworkScoreService.aidl
@@ -18,7 +18,7 @@
import android.net.INetworkScoreCache;
import android.net.NetworkKey;
-import android.net.NetworkScorerAppManager;
+import android.net.NetworkScorerAppData;
import android.net.RecommendationRequest;
import android.net.RecommendationResult;
import android.net.ScoredNetwork;
@@ -135,11 +135,11 @@
/**
* Returns metadata about the active scorer or <code>null</code> if there is no active scorer.
*/
- NetworkScorerAppManager.NetworkScorerAppData getActiveScorer();
+ NetworkScorerAppData getActiveScorer();
/**
* Returns the list of available scorer apps. The list will be empty if there are
* no valid scorers.
*/
- List<NetworkScorerAppManager.NetworkScorerAppData> getAllValidScorers();
+ List<NetworkScorerAppData> getAllValidScorers();
}
diff --git a/core/java/android/net/IpSecAlgorithm.java b/core/java/android/net/IpSecAlgorithm.java
new file mode 100644
index 0000000..da5cb37
--- /dev/null
+++ b/core/java/android/net/IpSecAlgorithm.java
@@ -0,0 +1,181 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.net;
+
+import android.annotation.StringDef;
+import android.os.Parcel;
+import android.os.Parcelable;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * IpSecAlgorithm specifies a single algorithm that can be applied to an IpSec Transform. Refer to
+ * RFC 4301.
+ */
+public final class IpSecAlgorithm implements Parcelable {
+
+ /**
+ * AES-CBC Encryption/Ciphering Algorithm.
+ *
+ * <p>Valid lengths for this key are {128, 192, 256}.
+ */
+ public static final String ALGO_CRYPT_AES_CBC = "cbc(aes)";
+
+ /**
+ * MD5 HMAC Authentication/Integrity Algorithm. This algorithm is not recommended for use in new
+ * applications and is provided for legacy compatibility with 3gpp infrastructure.
+ *
+ * <p>Valid truncation lengths are multiples of 8 bits from 96 to (default) 128.
+ */
+ public static final String ALGO_AUTH_HMAC_MD5 = "hmac(md5)";
+
+ /**
+ * SHA1 HMAC Authentication/Integrity Algorithm. This algorithm is not recommended for use in
+ * new applications and is provided for legacy compatibility with 3gpp infrastructure.
+ *
+ * <p>Valid truncation lengths are multiples of 8 bits from 96 to (default) 160.
+ */
+ public static final String ALGO_AUTH_HMAC_SHA1 = "hmac(sha1)";
+
+ /**
+ * SHA256 HMAC Authentication/Integrity Algorithm.
+ *
+ * <p>Valid truncation lengths are multiples of 8 bits from 96 to (default) 256.
+ */
+ public static final String ALGO_AUTH_HMAC_SHA256 = "hmac(sha256)";
+
+ /**
+ * SHA384 HMAC Authentication/Integrity Algorithm.
+ *
+ * <p>Valid truncation lengths are multiples of 8 bits from 192 to (default) 384.
+ */
+ public static final String ALGO_AUTH_HMAC_SHA384 = "hmac(sha384)";
+ /**
+ * SHA512 HMAC Authentication/Integrity Algorithm
+ *
+ * <p>Valid truncation lengths are multiples of 8 bits from 256 to (default) 512.
+ */
+ public static final String ALGO_AUTH_HMAC_SHA512 = "hmac(sha512)";
+
+ /** @hide */
+ @StringDef({
+ ALGO_CRYPT_AES_CBC,
+ ALGO_AUTH_HMAC_MD5,
+ ALGO_AUTH_HMAC_SHA1,
+ ALGO_AUTH_HMAC_SHA256,
+ ALGO_AUTH_HMAC_SHA512
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface AlgorithmName {}
+
+ private final String mName;
+ private final byte[] mKey;
+ private final int mTruncLenBits;
+
+ /**
+ * Specify a IpSecAlgorithm of one of the supported types including the truncation length of the
+ * algorithm
+ *
+ * @param algorithm type for IpSec.
+ * @param key non-null Key padded to a multiple of 8 bits.
+ */
+ public IpSecAlgorithm(String algorithm, byte[] key) {
+ this(algorithm, key, key.length * 8);
+ }
+
+ /**
+ * Specify a IpSecAlgorithm of one of the supported types including the truncation length of the
+ * algorithm
+ *
+ * @param algoName precise name of the algorithm to be used.
+ * @param key non-null Key padded to a multiple of 8 bits.
+ * @param truncLenBits the number of bits of output hash to use; only meaningful for
+ * Authentication.
+ */
+ public IpSecAlgorithm(@AlgorithmName String algoName, byte[] key, int truncLenBits) {
+ if (!isTruncationLengthValid(algoName, truncLenBits)) {
+ throw new IllegalArgumentException("Unknown algorithm or invalid length");
+ }
+ mName = algoName;
+ mKey = key.clone();
+ mTruncLenBits = Math.min(truncLenBits, key.length * 8);
+ }
+
+ /** Retrieve the algorithm name */
+ public String getName() {
+ return mName;
+ }
+
+ /** Retrieve the key for this algorithm */
+ public byte[] getKey() {
+ return mKey.clone();
+ }
+
+ /**
+ * Retrieve the truncation length, in bits, for the key in this algo. By default this will be
+ * the length in bits of the key.
+ */
+ public int getTruncationLengthBits() {
+ return mTruncLenBits;
+ }
+
+ /* Parcelable Implementation */
+ public int describeContents() {
+ return 0;
+ }
+
+ /** Write to parcel */
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeString(mName);
+ out.writeByteArray(mKey);
+ out.writeInt(mTruncLenBits);
+ }
+
+ /** Parcelable Creator */
+ public static final Parcelable.Creator<IpSecAlgorithm> CREATOR =
+ new Parcelable.Creator<IpSecAlgorithm>() {
+ public IpSecAlgorithm createFromParcel(Parcel in) {
+ return new IpSecAlgorithm(in);
+ }
+
+ public IpSecAlgorithm[] newArray(int size) {
+ return new IpSecAlgorithm[size];
+ }
+ };
+
+ private IpSecAlgorithm(Parcel in) {
+ mName = in.readString();
+ mKey = in.createByteArray();
+ mTruncLenBits = in.readInt();
+ }
+
+ private static boolean isTruncationLengthValid(String algo, int truncLenBits) {
+ switch (algo) {
+ case ALGO_AUTH_HMAC_MD5:
+ return (truncLenBits >= 96 && truncLenBits <= 128);
+ case ALGO_AUTH_HMAC_SHA1:
+ return (truncLenBits >= 96 && truncLenBits <= 160);
+ case ALGO_AUTH_HMAC_SHA256:
+ return (truncLenBits >= 96 && truncLenBits <= 256);
+ case ALGO_AUTH_HMAC_SHA384:
+ return (truncLenBits >= 192 && truncLenBits <= 384);
+ case ALGO_AUTH_HMAC_SHA512:
+ return (truncLenBits >= 256 && truncLenBits <= 512);
+ default:
+ return false;
+ }
+ }
+};
diff --git a/core/java/android/net/NetworkScorerAppManager.aidl b/core/java/android/net/IpSecConfig.aidl
similarity index 76%
copy from core/java/android/net/NetworkScorerAppManager.aidl
copy to core/java/android/net/IpSecConfig.aidl
index d968343..eaefca7 100644
--- a/core/java/android/net/NetworkScorerAppManager.aidl
+++ b/core/java/android/net/IpSecConfig.aidl
@@ -1,11 +1,11 @@
-/**
- * Copyright (c) 2017, The Android Open Source Project
+/*
+ * Copyright (C) 2017 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
+ * 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,
@@ -16,4 +16,5 @@
package android.net;
-parcelable NetworkScorerAppManager.NetworkScorerAppData;
+/** @hide */
+parcelable IpSecConfig;
diff --git a/core/java/android/net/IpSecConfig.java b/core/java/android/net/IpSecConfig.java
new file mode 100644
index 0000000..b58bf42
--- /dev/null
+++ b/core/java/android/net/IpSecConfig.java
@@ -0,0 +1,197 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.net;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.util.Log;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+
+/** @hide */
+public final class IpSecConfig implements Parcelable {
+ private static final String TAG = IpSecConfig.class.getSimpleName();
+
+ //MODE_TRANSPORT or MODE_TUNNEL
+ int mode;
+
+ // For tunnel mode
+ InetAddress localAddress;
+
+ InetAddress remoteAddress;
+
+ // Limit selection by network interface
+ Network network;
+
+ public static class Flow {
+ // Minimum requirements for identifying a transform
+ // SPI identifying the IPsec flow in packet processing
+ // and a remote IP address
+ int spi;
+
+ // Encryption Algorithm
+ IpSecAlgorithm encryptionAlgo;
+
+ // Authentication Algorithm
+ IpSecAlgorithm authenticationAlgo;
+ }
+
+ Flow[] flow = new Flow[2];
+
+ // For tunnel mode IPv4 UDP Encapsulation
+ // IpSecTransform#ENCAP_ESP_*, such as ENCAP_ESP_OVER_UDP_IKE
+ int encapType;
+ int encapLocalPort;
+ int encapRemotePort;
+
+ // An optional protocol to match with the selector
+ int selectorProto;
+
+ // A bitmask of FEATURE_* indicating which of the fields
+ // of this class are valid.
+ long features;
+
+ // An interval, in seconds between the NattKeepalive packets
+ int nattKeepaliveInterval;
+
+ public InetAddress getLocalIp() {
+ return localAddress;
+ }
+
+ public int getSpi(int direction) {
+ return flow[direction].spi;
+ }
+
+ public InetAddress getRemoteIp() {
+ return remoteAddress;
+ }
+
+ public IpSecAlgorithm getEncryptionAlgo(int direction) {
+ return flow[direction].encryptionAlgo;
+ }
+
+ public IpSecAlgorithm getAuthenticationAlgo(int direction) {
+ return flow[direction].authenticationAlgo;
+ }
+
+ Network getNetwork() {
+ return network;
+ }
+
+ public int getEncapType() {
+ return encapType;
+ }
+
+ public int getEncapLocalPort() {
+ return encapLocalPort;
+ }
+
+ public int getEncapRemotePort() {
+ return encapRemotePort;
+ }
+
+ public int getSelectorProto() {
+ return selectorProto;
+ }
+
+ int getNattKeepaliveInterval() {
+ return nattKeepaliveInterval;
+ }
+
+ public boolean hasProperty(int featureBits) {
+ return (features & featureBits) == featureBits;
+ }
+
+ // Parcelable Methods
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeLong(features);
+ // TODO: Use a byte array or other better method for storing IPs that can also include scope
+ out.writeString((localAddress != null) ? localAddress.getHostAddress() : null);
+ // TODO: Use a byte array or other better method for storing IPs that can also include scope
+ out.writeString((remoteAddress != null) ? remoteAddress.getHostAddress() : null);
+ out.writeParcelable(network, flags);
+ out.writeInt(flow[IpSecTransform.DIRECTION_IN].spi);
+ out.writeParcelable(flow[IpSecTransform.DIRECTION_IN].encryptionAlgo, flags);
+ out.writeParcelable(flow[IpSecTransform.DIRECTION_IN].authenticationAlgo, flags);
+ out.writeInt(flow[IpSecTransform.DIRECTION_OUT].spi);
+ out.writeParcelable(flow[IpSecTransform.DIRECTION_OUT].encryptionAlgo, flags);
+ out.writeParcelable(flow[IpSecTransform.DIRECTION_OUT].authenticationAlgo, flags);
+ out.writeInt(encapType);
+ out.writeInt(encapLocalPort);
+ out.writeInt(encapRemotePort);
+ out.writeInt(selectorProto);
+ }
+
+ // Package Private: Used by the IpSecTransform.Builder;
+ // there should be no public constructor for this object
+ IpSecConfig() {
+ flow[IpSecTransform.DIRECTION_IN].spi = 0;
+ flow[IpSecTransform.DIRECTION_OUT].spi = 0;
+ nattKeepaliveInterval = 0; //FIXME constant
+ }
+
+ private static InetAddress readInetAddressFromParcel(Parcel in) {
+ String addrString = in.readString();
+ if (addrString == null) {
+ return null;
+ }
+ try {
+ return InetAddress.getByName(addrString);
+ } catch (UnknownHostException e) {
+ Log.wtf(TAG, "Invalid IpAddress " + addrString);
+ return null;
+ }
+ }
+
+ private IpSecConfig(Parcel in) {
+ features = in.readLong();
+ localAddress = readInetAddressFromParcel(in);
+ remoteAddress = readInetAddressFromParcel(in);
+ network = (Network) in.readParcelable(Network.class.getClassLoader());
+ flow[IpSecTransform.DIRECTION_IN].spi = in.readInt();
+ flow[IpSecTransform.DIRECTION_IN].encryptionAlgo =
+ (IpSecAlgorithm) in.readParcelable(IpSecAlgorithm.class.getClassLoader());
+ flow[IpSecTransform.DIRECTION_IN].authenticationAlgo =
+ (IpSecAlgorithm) in.readParcelable(IpSecAlgorithm.class.getClassLoader());
+ flow[IpSecTransform.DIRECTION_OUT].spi = in.readInt();
+ flow[IpSecTransform.DIRECTION_OUT].encryptionAlgo =
+ (IpSecAlgorithm) in.readParcelable(IpSecAlgorithm.class.getClassLoader());
+ flow[IpSecTransform.DIRECTION_OUT].authenticationAlgo =
+ (IpSecAlgorithm) in.readParcelable(IpSecAlgorithm.class.getClassLoader());
+ encapType = in.readInt();
+ encapLocalPort = in.readInt();
+ encapRemotePort = in.readInt();
+ selectorProto = in.readInt();
+ }
+
+ public static final Parcelable.Creator<IpSecConfig> CREATOR =
+ new Parcelable.Creator<IpSecConfig>() {
+ public IpSecConfig createFromParcel(Parcel in) {
+ return new IpSecConfig(in);
+ }
+
+ public IpSecConfig[] newArray(int size) {
+ return new IpSecConfig[size];
+ }
+ };
+}
diff --git a/core/java/android/net/IpSecManager.java b/core/java/android/net/IpSecManager.java
new file mode 100644
index 0000000..2c544e9
--- /dev/null
+++ b/core/java/android/net/IpSecManager.java
@@ -0,0 +1,379 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.net;
+
+import static com.android.internal.util.Preconditions.checkNotNull;
+
+import android.annotation.SystemApi;
+import android.content.Context;
+import android.os.INetworkManagementService;
+import android.os.ParcelFileDescriptor;
+import android.util.AndroidException;
+import dalvik.system.CloseGuard;
+import java.io.FileDescriptor;
+import java.io.IOException;
+import java.net.DatagramSocket;
+import java.net.InetAddress;
+import java.net.Socket;
+
+/**
+ * This class contains methods for managing IPsec sessions, which will perform kernel-space
+ * encryption and decryption of socket or Network traffic.
+ *
+ * <p>An IpSecManager may be obtained by calling {@link
+ * android.content.Context#getSystemService(String) Context#getSystemService(String)} with {@link
+ * android.content.Context#IPSEC_SERVICE Context#IPSEC_SERVICE}
+ */
+public final class IpSecManager {
+ private static final String TAG = "IpSecManager";
+
+ /**
+ * Indicates that the combination of remote InetAddress and SPI was non-unique for a given
+ * request. If encountered, selection of a new SPI is required before a transform may be
+ * created. Note, this should happen very rarely if the SPI is chosen to be sufficiently random
+ * or reserved using reserveSecurityParameterIndex.
+ */
+ public static final class SpiUnavailableException extends AndroidException {
+ private final int mSpi;
+
+ /**
+ * Construct an exception indicating that a transform with the given SPI is already in use
+ * or otherwise unavailable.
+ *
+ * @param msg Description indicating the colliding SPI
+ * @param spi the SPI that could not be used due to a collision
+ */
+ SpiUnavailableException(String msg, int spi) {
+ super(msg + "(spi: " + spi + ")");
+ mSpi = spi;
+ }
+
+ /** Retrieve the SPI that caused a collision */
+ public int getSpi() {
+ return mSpi;
+ }
+ }
+
+ /**
+ * Indicates that the requested system resource for IPsec, such as a socket or other system
+ * resource is unavailable. If this exception is thrown, try releasing allocated objects of the
+ * type requested.
+ */
+ public static final class ResourceUnavailableException extends AndroidException {
+
+ ResourceUnavailableException(String msg) {
+ super(msg);
+ }
+ }
+
+ private final Context mContext;
+ private final INetworkManagementService mService;
+
+ public static final class SecurityParameterIndex implements AutoCloseable {
+ private final Context mContext;
+ private final InetAddress mDestinationAddress;
+ private final CloseGuard mCloseGuard = CloseGuard.get();
+ private int mSpi;
+
+ /** Return the underlying SPI held by this object */
+ public int getSpi() {
+ return mSpi;
+ }
+
+ private SecurityParameterIndex(Context context, InetAddress destinationAddress, int spi)
+ throws ResourceUnavailableException, SpiUnavailableException {
+ mContext = context;
+ mDestinationAddress = destinationAddress;
+ mSpi = spi;
+ mCloseGuard.open("open");
+ }
+
+ /**
+ * Release an SPI that was previously reserved.
+ *
+ * <p>Release an SPI for use by other users in the system. This will fail if the SPI is
+ * currently in use by an IpSecTransform.
+ *
+ * @param destinationAddress SPIs must be unique for each combination of SPI and destination
+ * address. Thus, the destinationAddress to which the SPI will communicate must be
+ * supplied.
+ * @param spi the previously reserved SPI to be freed.
+ */
+ @Override
+ public void close() {
+ mSpi = INVALID_SECURITY_PARAMETER_INDEX; // TODO: Invalid SPI
+ mCloseGuard.close();
+ }
+
+ @Override
+ protected void finalize() {
+ if (mCloseGuard != null) {
+ mCloseGuard.warnIfOpen();
+ }
+
+ close();
+ }
+ }
+
+ /**
+ * The Security Parameter Index, SPI, 0 indicates an unknown or invalid index.
+ *
+ * <p>No IPsec packet may contain an SPI of 0.
+ */
+ public static final int INVALID_SECURITY_PARAMETER_INDEX = 0;
+
+ /**
+ * Reserve an SPI for traffic bound towards the specified destination address.
+ *
+ * <p>If successful, this SPI is guaranteed available until released by a call to {@link
+ * SecurityParameterIndex#close()}.
+ *
+ * @param destinationAddress SPIs must be unique for each combination of SPI and destination
+ * address.
+ * @param requestedSpi the requested SPI, or '0' to allocate a random SPI.
+ * @return the reserved SecurityParameterIndex
+ * @throws ResourceUnavailableException indicating that too many SPIs are currently allocated
+ * for this user
+ * @throws SpiUnavailableException indicating that a particular SPI cannot be reserved
+ */
+ public SecurityParameterIndex reserveSecurityParameterIndex(
+ InetAddress destinationAddress, int requestedSpi)
+ throws SpiUnavailableException, ResourceUnavailableException {
+ return new SecurityParameterIndex(mContext, destinationAddress, requestedSpi);
+ }
+
+ /**
+ * Apply an active Transport Mode IPsec Transform to a stream socket to perform IPsec
+ * encapsulation of the traffic flowing between the socket and the remote InetAddress of that
+ * transform. For security reasons, attempts to send traffic to any IP address other than the
+ * address associated with that transform will throw an IOException. In addition, if the
+ * IpSecTransform is later deactivated, the socket will throw an IOException on any calls to
+ * send() or receive() until the transform is removed from the socket by calling {@link
+ * #removeTransportModeTransform(Socket, IpSecTransform)};
+ *
+ * @param socket a stream socket
+ * @param transform an {@link IpSecTransform}, which must be an active Transport Mode transform.
+ */
+ public void applyTransportModeTransform(Socket socket, IpSecTransform transform)
+ throws IOException {
+ applyTransportModeTransform(ParcelFileDescriptor.fromSocket(socket), transform);
+ }
+
+ /**
+ * Apply an active Transport Mode IPsec Transform to a datagram socket to perform IPsec
+ * encapsulation of the traffic flowing between the socket and the remote InetAddress of that
+ * transform. For security reasons, attempts to send traffic to any IP address other than the
+ * address associated with that transform will throw an IOException. In addition, if the
+ * IpSecTransform is later deactivated, the socket will throw an IOException on any calls to
+ * send() or receive() until the transform is removed from the socket by calling {@link
+ * #removeTransportModeTransform(DatagramSocket, IpSecTransform)};
+ *
+ * @param socket a datagram socket
+ * @param transform an {@link IpSecTransform}, which must be an active Transport Mode transform.
+ */
+ public void applyTransportModeTransform(DatagramSocket socket, IpSecTransform transform)
+ throws IOException {
+ applyTransportModeTransform(ParcelFileDescriptor.fromDatagramSocket(socket), transform);
+ }
+
+ /* Call down to activate a transform */
+ private void applyTransportModeTransform(ParcelFileDescriptor pfd, IpSecTransform transform) {}
+
+ /**
+ * Apply an active Tunnel Mode IPsec Transform to a network, which will tunnel all traffic to
+ * and from that network's interface with IPsec (applies an outer IP header and IPsec Header to
+ * all traffic, and expects an additional IP header and IPsec Header on all inbound traffic).
+ * Applications should probably not use this API directly. Instead, they should use {@link
+ * VpnService} to provide VPN capability in a more generic fashion.
+ *
+ * @param net a {@link Network} that will be tunneled via IP Sec.
+ * @param transform an {@link IpSecTransform}, which must be an active Tunnel Mode transform.
+ * @hide
+ */
+ @SystemApi
+ public void applyTunnelModeTransform(Network net, IpSecTransform transform) {}
+
+ /**
+ * Remove a transform from a given stream socket. Once removed, traffic on the socket will not
+ * be encypted. This allows sockets that have been used for IPsec to be reclaimed for
+ * communication in the clear in the event socket reuse is desired. This operation will succeed
+ * regardless of the underlying state of a transform. If a transform is removed, communication
+ * on all sockets to which that transform was applied will fail until this method is called.
+ *
+ * @param socket a socket that previously had a transform applied to it.
+ * @param transform the IPsec Transform that was previously applied to the given socket
+ */
+ public void removeTransportModeTransform(Socket socket, IpSecTransform transform) {
+ removeTransportModeTransform(ParcelFileDescriptor.fromSocket(socket), transform);
+ }
+
+ /**
+ * Remove a transform from a given datagram socket. Once removed, traffic on the socket will not
+ * be encypted. This allows sockets that have been used for IPsec to be reclaimed for
+ * communication in the clear in the event socket reuse is desired. This operation will succeed
+ * regardless of the underlying state of a transform. If a transform is removed, communication
+ * on all sockets to which that transform was applied will fail until this method is called.
+ *
+ * @param socket a socket that previously had a transform applied to it.
+ * @param transform the IPsec Transform that was previously applied to the given socket
+ */
+ public void removeTransportModeTransform(DatagramSocket socket, IpSecTransform transform) {
+ removeTransportModeTransform(ParcelFileDescriptor.fromDatagramSocket(socket), transform);
+ }
+
+ /* Call down to activate a transform */
+ private void removeTransportModeTransform(ParcelFileDescriptor pfd, IpSecTransform transform) {}
+
+ /**
+ * Remove a Tunnel Mode IPsec Transform from a {@link Network}. This must be used as part of
+ * cleanup if a tunneled Network experiences a change in default route. The Network will drop
+ * all traffic that cannot be routed to the Tunnel's outbound interface. If that interface is
+ * lost, all traffic will drop.
+ *
+ * @param net a network that currently has transform applied to it.
+ * @param transform a Tunnel Mode IPsec Transform that has been previously applied to the given
+ * network
+ * @hide
+ */
+ @SystemApi
+ public void removeTunnelModeTransform(Network net, IpSecTransform transform) {}
+
+ /**
+ * Class providing access to a system-provided UDP Encapsulation Socket, which may be used for
+ * IKE signalling as well as for inbound and outbound UDP encapsulated IPsec traffic.
+ *
+ * <p>The socket provided by this class cannot be re-bound or closed via the inner
+ * FileDescriptor. Instead, disposing of this socket requires a call to close().
+ */
+ public static final class UdpEncapsulationSocket implements AutoCloseable {
+ private final FileDescriptor mFd;
+ private final Context mContext;
+ private final CloseGuard mCloseGuard = CloseGuard.get();
+
+ private UdpEncapsulationSocket(Context context, int port)
+ throws ResourceUnavailableException {
+ mContext = context;
+ mCloseGuard.open("constructor");
+ // TODO: go down to the kernel and get a socket on the specified
+ mFd = new FileDescriptor();
+ }
+
+ private UdpEncapsulationSocket(Context context) throws ResourceUnavailableException {
+ mContext = context;
+ mCloseGuard.open("constructor");
+ // TODO: go get a random socket on a random port
+ mFd = new FileDescriptor();
+ }
+
+ /** Access the inner UDP Encapsulation Socket */
+ public FileDescriptor getSocket() {
+ return mFd;
+ }
+
+ /** Retrieve the port number of the inner encapsulation socket */
+ public int getPort() {
+ return 0; // TODO get the port number from the Socket;
+ }
+
+ @Override
+ /**
+ * Release the resources that have been reserved for this Socket.
+ *
+ * <p>This method closes the underlying socket, reducing a user's allocated sockets in the
+ * system. This must be done as part of cleanup following use of a socket. Failure to do so
+ * will cause the socket to count against a total allocation limit for IpSec and eventually
+ * fail due to resource limits.
+ *
+ * @param fd a file descriptor previously returned as a UDP Encapsulation socket.
+ */
+ public void close() {
+ // TODO: Go close the socket
+ mCloseGuard.close();
+ }
+
+ @Override
+ protected void finalize() throws Throwable {
+ if (mCloseGuard != null) {
+ mCloseGuard.warnIfOpen();
+ }
+
+ close();
+ }
+ };
+
+ /**
+ * Open a socket that is bound to a free UDP port on the system.
+ *
+ * <p>By binding in this manner and holding the FileDescriptor, the socket cannot be un-bound by
+ * the caller. This provides safe access to a socket on a port that can later be used as a UDP
+ * Encapsulation port.
+ *
+ * <p>This socket reservation works in conjunction with IpSecTransforms, which may re-use the
+ * socket port. Explicitly opening this port is only necessary if communication is desired on
+ * that port.
+ *
+ * @param port a local UDP port to be reserved for UDP Encapsulation. is provided, then this
+ * method will bind to the specified port or fail. To retrieve the port number, call {@link
+ * android.system.Os#getsockname(FileDescriptor)}.
+ * @return a {@link UdpEncapsulationSocket} that is bound to the requested port for the lifetime
+ * of the object.
+ */
+ // Returning a socket in this fashion that has been created and bound by the system
+ // is the only safe way to ensure that a socket is both accessible to the user and
+ // safely usable for Encapsulation without allowing a user to possibly unbind from/close
+ // the port, which could potentially impact the traffic of the next user who binds to that
+ // socket.
+ public UdpEncapsulationSocket openUdpEncapsulationSocket(int port)
+ throws IOException, ResourceUnavailableException {
+ // Temporary code
+ return new UdpEncapsulationSocket(mContext, port);
+ }
+
+ /**
+ * Open a socket that is bound to a port selected by the system.
+ *
+ * <p>By binding in this manner and holding the FileDescriptor, the socket cannot be un-bound by
+ * the caller. This provides safe access to a socket on a port that can later be used as a UDP
+ * Encapsulation port.
+ *
+ * <p>This socket reservation works in conjunction with IpSecTransforms, which may re-use the
+ * socket port. Explicitly opening this port is only necessary if communication is desired on
+ * that port.
+ *
+ * @return a {@link UdpEncapsulationSocket} that is bound to an arbitrarily selected port
+ */
+ // Returning a socket in this fashion that has been created and bound by the system
+ // is the only safe way to ensure that a socket is both accessible to the user and
+ // safely usable for Encapsulation without allowing a user to possibly unbind from/close
+ // the port, which could potentially impact the traffic of the next user who binds to that
+ // socket.
+ public UdpEncapsulationSocket openUdpEncapsulationSocket()
+ throws IOException, ResourceUnavailableException {
+ // Temporary code
+ return new UdpEncapsulationSocket(mContext);
+ }
+
+ /**
+ * Retrieve an instance of an IpSecManager within you application context
+ *
+ * @param context the application context for this manager
+ * @hide
+ */
+ public IpSecManager(Context context, INetworkManagementService service) {
+ mContext = checkNotNull(context, "missing context");
+ mService = checkNotNull(service, "missing service");
+ }
+}
diff --git a/core/java/android/net/IpSecTransform.java b/core/java/android/net/IpSecTransform.java
new file mode 100644
index 0000000..d6dd28be
--- /dev/null
+++ b/core/java/android/net/IpSecTransform.java
@@ -0,0 +1,471 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.net;
+
+import android.annotation.IntDef;
+import android.annotation.SystemApi;
+import android.content.Context;
+import android.system.ErrnoException;
+import android.util.Log;
+import dalvik.system.CloseGuard;
+import java.io.IOException;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.net.InetAddress;
+
+/**
+ * This class represents an IpSecTransform, which encapsulates both properties and state of IPsec.
+ *
+ * <p>IpSecTransforms must be built from an IpSecTransform.Builder, and they must persist throughout
+ * the lifetime of the underlying transform. If a transform object leaves scope, the underlying
+ * transform may be disabled automatically, with likely undesirable results.
+ *
+ * <p>An IpSecTransform may either represent a tunnel mode transform that operates on a wide array
+ * of traffic or may represent a transport mode transform operating on a Socket or Sockets.
+ */
+public final class IpSecTransform implements AutoCloseable {
+ private static final String TAG = "IpSecTransform";
+
+ /**
+ * For direction-specific attributes of an IpSecTransform, indicates that an attribute applies
+ * to traffic towards the host.
+ */
+ public static final int DIRECTION_IN = 0;
+
+ /**
+ * For direction-specific attributes of an IpSecTransform, indicates that an attribute applies
+ * to traffic from the host.
+ */
+ public static final int DIRECTION_OUT = 1;
+
+ /** @hide */
+ @IntDef(value = {DIRECTION_IN, DIRECTION_OUT})
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface TransformDirection {}
+
+ /** @hide */
+ private static final int MODE_TUNNEL = 0;
+
+ /** @hide */
+ private static final int MODE_TRANSPORT = 1;
+
+ /** @hide */
+ public static final int ENCAP_NONE = 0;
+
+ /**
+ * IpSec traffic will be encapsulated within UDP as per <a
+ * href="https://tools.ietf.org/html/rfc3948">RFC3498</a>.
+ *
+ * @hide
+ */
+ public static final int ENCAP_ESPINUDP = 1;
+
+ /**
+ * IpSec traffic will be encapsulated within a UDP header with an additional 8-byte header pad
+ * (of '0'-value bytes) that prevents traffic from being interpreted as IKE or as ESP over UDP.
+ *
+ * @hide
+ */
+ public static final int ENCAP_ESPINUDP_NONIKE = 2;
+
+ /** @hide */
+ @IntDef(value = {ENCAP_NONE, ENCAP_ESPINUDP, ENCAP_ESPINUDP_NONIKE})
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface EncapType {}
+
+ /**
+ * Sentinel for an invalid transform (means that this transform is inactive).
+ *
+ * @hide
+ */
+ public static final int INVALID_TRANSFORM_ID = -1;
+
+ private IpSecTransform(Context context, IpSecConfig config) {
+ mContext = context;
+ mConfig = config;
+ mTransformId = INVALID_TRANSFORM_ID;
+ }
+
+ private IpSecTransform activate()
+ throws IOException, IpSecManager.ResourceUnavailableException,
+ IpSecManager.SpiUnavailableException {
+ int transformId;
+ synchronized (this) {
+ //try {
+ transformId = INVALID_TRANSFORM_ID;
+ //} catch (RemoteException e) {
+ // throw e.rethrowFromSystemServer();
+ //}
+
+ if (transformId < 0) {
+ throw new ErrnoException("addTransform", -transformId).rethrowAsIOException();
+ }
+
+ startKeepalive(mContext); // Will silently fail if not required
+ mTransformId = transformId;
+ Log.d(TAG, "Added Transform with Id " + transformId);
+ }
+ mCloseGuard.open("build");
+
+ return this;
+ }
+
+ /**
+ * Deactivate an IpSecTransform and free all resources for that transform that are managed by
+ * the system for this Transform.
+ *
+ * <p>Deactivating a transform while it is still applied to any Socket will result in sockets
+ * refusing to send or receive data. This method will silently succeed if the specified
+ * transform has already been removed; thus, it is always safe to attempt cleanup when a
+ * transform is no longer needed.
+ */
+ public void close() {
+ Log.d(TAG, "Removing Transform with Id " + mTransformId);
+
+ // Always safe to attempt cleanup
+ if (mTransformId == INVALID_TRANSFORM_ID) {
+ return;
+ }
+ //try {
+ stopKeepalive();
+ //} catch (RemoteException e) {
+ // transform.setTransformId(transformId);
+ // throw e.rethrowFromSystemServer();
+ //} finally {
+ mTransformId = INVALID_TRANSFORM_ID;
+ //}
+ mCloseGuard.close();
+ }
+
+ @Override
+ protected void finalize() throws Throwable {
+ if (mCloseGuard != null) {
+ mCloseGuard.warnIfOpen();
+ }
+ close();
+ }
+
+ /* Package */
+ IpSecConfig getConfig() {
+ return mConfig;
+ }
+
+ private final IpSecConfig mConfig;
+ private int mTransformId;
+ private final Context mContext;
+ private final CloseGuard mCloseGuard = CloseGuard.get();
+ private ConnectivityManager.PacketKeepalive mKeepalive;
+ private int mKeepaliveStatus = ConnectivityManager.PacketKeepalive.NO_KEEPALIVE;
+ private Object mKeepaliveSyncLock = new Object();
+ private ConnectivityManager.PacketKeepaliveCallback mKeepaliveCallback =
+ new ConnectivityManager.PacketKeepaliveCallback() {
+
+ @Override
+ public void onStarted() {
+ synchronized (mKeepaliveSyncLock) {
+ mKeepaliveStatus = ConnectivityManager.PacketKeepalive.SUCCESS;
+ mKeepaliveSyncLock.notifyAll();
+ }
+ }
+
+ @Override
+ public void onStopped() {
+ synchronized (mKeepaliveSyncLock) {
+ mKeepaliveStatus = ConnectivityManager.PacketKeepalive.NO_KEEPALIVE;
+ mKeepaliveSyncLock.notifyAll();
+ }
+ }
+
+ @Override
+ public void onError(int error) {
+ synchronized (mKeepaliveSyncLock) {
+ mKeepaliveStatus = error;
+ mKeepaliveSyncLock.notifyAll();
+ }
+ }
+ };
+
+ /* Package */
+ void startKeepalive(Context c) {
+ if (mConfig.getNattKeepaliveInterval() == 0) {
+ return;
+ }
+
+ ConnectivityManager cm =
+ (ConnectivityManager) c.getSystemService(Context.CONNECTIVITY_SERVICE);
+
+ if (mKeepalive != null) {
+ Log.e(TAG, "Keepalive already started for this IpSecTransform.");
+ return;
+ }
+
+ synchronized (mKeepaliveSyncLock) {
+ mKeepalive =
+ cm.startNattKeepalive(
+ mConfig.getNetwork(),
+ mConfig.getNattKeepaliveInterval(),
+ mKeepaliveCallback,
+ mConfig.getLocalIp(),
+ mConfig.getEncapLocalPort(),
+ mConfig.getRemoteIp());
+ try {
+ mKeepaliveSyncLock.wait(2000);
+ } catch (InterruptedException e) {
+ }
+ }
+ if (mKeepaliveStatus != ConnectivityManager.PacketKeepalive.SUCCESS) {
+ throw new UnsupportedOperationException("Packet Keepalive cannot be started");
+ }
+ }
+
+ /* Package */
+ void stopKeepalive() {
+ if (mKeepalive == null) {
+ return;
+ }
+ mKeepalive.stop();
+ synchronized (mKeepaliveSyncLock) {
+ if (mKeepaliveStatus == ConnectivityManager.PacketKeepalive.SUCCESS) {
+ try {
+ mKeepaliveSyncLock.wait(2000);
+ } catch (InterruptedException e) {
+ }
+ }
+ }
+ }
+
+ /* Package */
+ void setTransformId(int transformId) {
+ mTransformId = transformId;
+ }
+
+ /* Package */
+ int getTransformId() {
+ return mTransformId;
+ }
+
+ /**
+ * Builder object to facilitate the creation of IpSecTransform objects.
+ *
+ * <p>Apply additional properties to the transform and then call a build() method to return an
+ * IpSecTransform object.
+ *
+ * @see Builder#buildTransportModeTransform(InetAddress)
+ */
+ public static class Builder {
+ private Context mContext;
+ private IpSecConfig mConfig;
+
+ /**
+ * Add an encryption algorithm to the transform for the given direction.
+ *
+ * <p>If encryption is set for a given direction without also providing an SPI for that
+ * direction, creation of an IpSecTransform will fail upon calling a build() method.
+ *
+ * @param direction either {@link #DIRECTION_IN or #DIRECTION_OUT}
+ * @param algo {@link IpSecAlgorithm} specifying the encryption to be applied.
+ */
+ public IpSecTransform.Builder setEncryption(
+ @TransformDirection int direction, IpSecAlgorithm algo) {
+ mConfig.flow[direction].encryptionAlgo = algo;
+ return this;
+ }
+
+ /**
+ * Add an authentication/integrity algorithm to the transform.
+ *
+ * <p>If authentication is set for a given direction without also providing an SPI for that
+ * direction, creation of an IpSecTransform will fail upon calling a build() method.
+ *
+ * @param direction either {@link #DIRECTION_IN or #DIRECTION_OUT}
+ * @param algo {@link IpSecAlgorithm} specifying the authentication to be applied.
+ */
+ public IpSecTransform.Builder setAuthentication(
+ @TransformDirection int direction, IpSecAlgorithm algo) {
+ mConfig.flow[direction].authenticationAlgo = algo;
+ return this;
+ }
+
+ /**
+ * Set the SPI, which uniquely identifies a particular IPsec session from others. Because
+ * IPsec operates at the IP layer, this 32-bit identifier uniquely identifies packets to a
+ * given destination address.
+ *
+ * <p>Care should be chosen when selecting an SPI to ensure that is is as unique as
+ * possible. Random number generation is a reasonable approach to selecting an SPI. For
+ * outbound SPIs, they must be reserved by calling {@link
+ * IpSecManager#reserveSecurityParameterIndex(InetAddress, int)}. Otherwise, Transforms will
+ * fail to build.
+ *
+ * <p>Unless an SPI is set for a given direction, traffic in that direction will be
+ * sent/received without any IPsec applied.
+ *
+ * @param direction either {@link #DIRECTION_IN or #DIRECTION_OUT}
+ * @param spi a unique 32-bit integer to identify transformed traffic
+ */
+ public IpSecTransform.Builder setSpi(@TransformDirection int direction, int spi) {
+ mConfig.flow[direction].spi = spi;
+ return this;
+ }
+
+ /**
+ * Set the SPI, which uniquely identifies a particular IPsec session from others. Because
+ * IPsec operates at the IP layer, this 32-bit identifier uniquely identifies packets to a
+ * given destination address.
+ *
+ * <p>Care should be chosen when selecting an SPI to ensure that is is as unique as
+ * possible. Random number generation is a reasonable approach to selecting an SPI. For
+ * outbound SPIs, they must be reserved by calling {@link
+ * IpSecManager#reserveSecurityParameterIndex(InetAddress, int)}. Otherwise, Transforms will
+ * fail to activate.
+ *
+ * <p>Unless an SPI is set for a given direction, traffic in that direction will be
+ * sent/received without any IPsec applied.
+ *
+ * @param direction either {@link #DIRECTION_IN or #DIRECTION_OUT}
+ * @param spi a unique {@link IpSecManager.SecurityParameterIndex} to identify transformed
+ * traffic
+ */
+ public IpSecTransform.Builder setSpi(
+ @TransformDirection int direction, IpSecManager.SecurityParameterIndex spi) {
+ mConfig.flow[direction].spi = spi.getSpi();
+ return this;
+ }
+
+ /**
+ * Specify the network on which this transform will emit its traffic; (otherwise it will
+ * emit on the default network).
+ *
+ * <p>Restricts the transformed traffic to a particular {@link Network}. This is required in
+ * tunnel mode.
+ *
+ * @hide
+ */
+ @SystemApi
+ public IpSecTransform.Builder setUnderlyingNetwork(Network net) {
+ mConfig.network = net;
+ return this;
+ }
+
+ /**
+ * Add UDP encapsulation to an IPv4 transform
+ *
+ * <p>This option allows IPsec traffic to pass through NAT. Refer to RFC 3947 and 3948 for
+ * details on how UDP should be applied to IPsec.
+ *
+ * @param localSocket a {@link IpSecManager.UdpEncapsulationSocket} for sending and
+ * receiving encapsulating traffic.
+ * @param remotePort the UDP port number of the remote that will send and receive
+ * encapsulated traffic. In the case of IKE, this is likely port 4500.
+ */
+ public IpSecTransform.Builder setIpv4Encapsulation(
+ IpSecManager.UdpEncapsulationSocket localSocket, int remotePort) {
+ // TODO: check encap type is valid.
+ mConfig.encapType = ENCAP_ESPINUDP;
+ mConfig.encapLocalPort = localSocket.getPort(); // TODO: plug in the encap socket
+ mConfig.encapRemotePort = remotePort;
+ return this;
+ }
+
+ // TODO: Decrease the minimum keepalive to maybe 10?
+ // TODO: Probably a better exception to throw for NATTKeepalive failure
+ // TODO: Specify the needed NATT keepalive permission.
+ /**
+ * Send a NATT Keepalive packet with a given maximum interval. This will create an offloaded
+ * request to do power-efficient NATT Keepalive. If NATT keepalive is requested but cannot
+ * be activated, then the transform will fail to activate and throw an IOException.
+ *
+ * @param intervalSeconds the maximum number of seconds between keepalive packets, no less
+ * than 20s and no more than 3600s.
+ * @hide
+ */
+ @SystemApi
+ public IpSecTransform.Builder setNattKeepalive(int intervalSeconds) {
+ mConfig.nattKeepaliveInterval = intervalSeconds;
+ return this;
+ }
+
+ /**
+ * Build and return an active {@link IpSecTransform} object as a Transport Mode Transform.
+ * Some parameters have interdependencies that are checked at build time. If a well-formed
+ * transform cannot be created from the supplied parameters, this method will throw an
+ * Exception.
+ *
+ * <p>Upon a successful return from this call, the provided IpSecTransform will be active
+ * and may be applied to sockets. If too many IpSecTransform objects are active for a given
+ * user this operation will fail and throw ResourceUnavailableException. To avoid these
+ * exceptions, unused Transform objects must be cleaned up by calling {@link
+ * IpSecTransform#close()} when they are no longer needed.
+ *
+ * @param remoteAddress the {@link InetAddress} that, when matched on traffic to/from this
+ * socket will cause the transform to be applied.
+ * <p>Note that an active transform will not impact any network traffic until it has
+ * been applied to one or more Sockets. Calling this method is a necessary precondition
+ * for applying it to a socket, but is not sufficient to actually apply IPsec.
+ * @throws IllegalArgumentException indicating that a particular combination of transform
+ * properties is invalid.
+ * @throws IpSecManager.ResourceUnavailableException in the event that no more Transforms
+ * may be allocated
+ * @throws SpiUnavailableException if the SPI collides with an existing transform
+ * (unlikely).
+ * @throws ResourceUnavailableException if the current user currently has exceeded the
+ * number of allowed active transforms.
+ */
+ public IpSecTransform buildTransportModeTransform(InetAddress remoteAddress)
+ throws IpSecManager.ResourceUnavailableException,
+ IpSecManager.SpiUnavailableException, IOException {
+ //FIXME: argument validation here
+ //throw new IllegalArgumentException("Natt Keepalive requires UDP Encapsulation");
+ mConfig.mode = MODE_TRANSPORT;
+ mConfig.remoteAddress = remoteAddress;
+ return new IpSecTransform(mContext, mConfig).activate();
+ }
+
+ /**
+ * Build and return an {@link IpSecTransform} object as a Tunnel Mode Transform. Some
+ * parameters have interdependencies that are checked at build time.
+ *
+ * @param localAddress the {@link InetAddress} that provides the local endpoint for this
+ * IPsec tunnel. This is almost certainly an address belonging to the {@link Network}
+ * that will originate the traffic, which is set as the {@link #setUnderlyingNetwork}.
+ * @param remoteAddress the {@link InetAddress} representing the remote endpoint of this
+ * IPsec tunnel.
+ * @throws IllegalArgumentException indicating that a particular combination of transform
+ * properties is invalid.
+ * @hide
+ */
+ @SystemApi
+ public IpSecTransform buildTunnelModeTransform(
+ InetAddress localAddress, InetAddress remoteAddress) {
+ //FIXME: argument validation here
+ //throw new IllegalArgumentException("Natt Keepalive requires UDP Encapsulation");
+ mConfig.localAddress = localAddress;
+ mConfig.remoteAddress = remoteAddress;
+ mConfig.mode = MODE_TUNNEL;
+ return new IpSecTransform(mContext, mConfig);
+ }
+
+ /**
+ * Create a new IpSecTransform.Builder to construct an IpSecTransform
+ *
+ * @param context current Context
+ */
+ public Builder(Context context) {
+ mContext = context;
+ mConfig = new IpSecConfig();
+ }
+ }
+}
diff --git a/core/java/android/net/NetworkRecommendationProvider.java b/core/java/android/net/NetworkRecommendationProvider.java
index 8395864..271b0a7 100644
--- a/core/java/android/net/NetworkRecommendationProvider.java
+++ b/core/java/android/net/NetworkRecommendationProvider.java
@@ -1,6 +1,8 @@
package android.net;
+import android.Manifest.permission;
import android.annotation.SystemApi;
+import android.content.Context;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
@@ -10,8 +12,10 @@
import android.util.Log;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.Preconditions;
import java.util.Objects;
+import java.util.concurrent.Executor;
import java.util.concurrent.atomic.AtomicBoolean;
/**
@@ -32,6 +36,7 @@
/**
* Constructs a new instance.
* @param handler indicates which thread to use when handling requests. Cannot be {@code null}.
+ * @deprecated use {@link #NetworkRecommendationProvider(Context, Executor)}
*/
public NetworkRecommendationProvider(Handler handler) {
if (handler == null) {
@@ -41,6 +46,17 @@
}
/**
+ * Constructs a new instance.
+ * @param context the current context instance. Cannot be {@code null}.
+ * @param executor used to execute the incoming requests. Cannot be {@code null}.
+ */
+ public NetworkRecommendationProvider(Context context, Executor executor) {
+ Preconditions.checkNotNull(context);
+ Preconditions.checkNotNull(executor);
+ mService = new ServiceWrapper(context, executor);
+ }
+
+ /**
* Invoked when a recommendation has been requested.
*
* @param request a {@link RecommendationRequest} instance containing additional
@@ -130,17 +146,28 @@
* A wrapper around INetworkRecommendationProvider that dispatches to the provided Handler.
*/
private final class ServiceWrapper extends INetworkRecommendationProvider.Stub {
+ private final Context mContext;
+ private final Executor mExecutor;
private final Handler mHandler;
ServiceWrapper(Handler handler) {
mHandler = handler;
+ mExecutor = null;
+ mContext = null;
+ }
+
+ ServiceWrapper(Context context, Executor executor) {
+ mContext = context;
+ mExecutor = executor;
+ mHandler = null;
}
@Override
public void requestRecommendation(final RecommendationRequest request,
final IRemoteCallback callback, final int sequence) throws RemoteException {
+ enforceCallingPermission();
if (VERBOSE) Log.v(TAG, "requestRecommendation(seq=" + sequence + ")");
- mHandler.post(new Runnable() {
+ execute(new Runnable() {
@Override
public void run() {
if (VERBOSE) {
@@ -154,8 +181,9 @@
@Override
public void requestScores(final NetworkKey[] networks) throws RemoteException {
+ enforceCallingPermission();
if (networks != null && networks.length > 0) {
- mHandler.post(new Runnable() {
+ execute(new Runnable() {
@Override
public void run() {
onRequestScores(networks);
@@ -163,5 +191,20 @@
});
}
}
+
+ private void execute(Runnable command) {
+ if (mExecutor != null) {
+ mExecutor.execute(command);
+ } else {
+ mHandler.post(command);
+ }
+ }
+
+ private void enforceCallingPermission() {
+ if (mContext != null) {
+ mContext.enforceCallingOrSelfPermission(permission.REQUEST_NETWORK_SCORES,
+ "Permission denied.");
+ }
+ }
}
}
diff --git a/core/java/android/net/NetworkScoreManager.java b/core/java/android/net/NetworkScoreManager.java
index 8f3af66..f0bea5b 100644
--- a/core/java/android/net/NetworkScoreManager.java
+++ b/core/java/android/net/NetworkScoreManager.java
@@ -18,7 +18,6 @@
import static android.net.NetworkRecommendationProvider.EXTRA_RECOMMENDATION_RESULT;
-import android.Manifest;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -26,7 +25,6 @@
import android.annotation.SdkConstant.SdkConstantType;
import android.annotation.SystemApi;
import android.content.Context;
-import android.net.NetworkScorerAppManager.NetworkScorerAppData;
import android.os.Bundle;
import android.os.Handler;
import android.os.RemoteCallback;
@@ -96,17 +94,24 @@
public static final String EXTRA_NETWORKS_TO_SCORE = "networksToScore";
/**
- * Activity action: launch a custom activity for configuring a scorer before enabling it.
- * Scorer applications may choose to specify an activity for this action, in which case the
- * framework will launch that activity which should return RESULT_OK if scoring was enabled.
- *
- * <p>If no activity is included in a scorer which implements this action, the system dialog for
- * selecting a scorer will be shown instead.
+ * Activity action: launch an activity for configuring a provider for the feature that connects
+ * and secures open wifi networks available before enabling it. Applications that enable this
+ * feature must provide an activity for this action. The framework will launch this activity
+ * which must return RESULT_OK if the feature should be enabled.
*/
@SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
public static final String ACTION_CUSTOM_ENABLE = "android.net.scoring.CUSTOM_ENABLE";
/**
+ * Meta-data specified on a {@link NetworkRecommendationProvider} that specified the package
+ * name of the application that connects and secures open wifi networks automatically. The
+ * specified package must provide an Activity for {@link #ACTION_CUSTOM_ENABLE}.
+ * @hide
+ */
+ public static final String USE_OPEN_WIFI_PACKAGE_META_DATA =
+ "android.net.wifi.use_open_wifi_package";
+
+ /**
* Broadcast action: the active scorer has been changed. Scorer apps may listen to this to
* perform initialization once selected as the active scorer, or clean up unneeded resources
* if another scorer has been selected. This is an explicit broadcast only sent to the
@@ -260,8 +265,8 @@
* the {@link #ACTION_CHANGE_ACTIVE} broadcast, or using a custom configuration activity.
*
* @return true if the operation succeeded, or false if the new package is not a valid scorer.
- * @throws SecurityException if the caller does not hold the
- * {@link android.Manifest.permission#SCORE_NETWORKS} permission.
+ * @throws SecurityException if the caller is not a system process or does not hold the
+ * {@link android.Manifest.permission#REQUEST_NETWORK_SCORES} permission
* @hide
*/
@SystemApi
diff --git a/core/java/android/net/NetworkScorerAppManager.aidl b/core/java/android/net/NetworkScorerAppData.aidl
similarity index 91%
rename from core/java/android/net/NetworkScorerAppManager.aidl
rename to core/java/android/net/NetworkScorerAppData.aidl
index d968343..ee7f1d1 100644
--- a/core/java/android/net/NetworkScorerAppManager.aidl
+++ b/core/java/android/net/NetworkScorerAppData.aidl
@@ -16,4 +16,4 @@
package android.net;
-parcelable NetworkScorerAppManager.NetworkScorerAppData;
+parcelable NetworkScorerAppData;
diff --git a/core/java/android/net/NetworkScorerAppData.java b/core/java/android/net/NetworkScorerAppData.java
new file mode 100644
index 0000000..fca0a2e
--- /dev/null
+++ b/core/java/android/net/NetworkScorerAppData.java
@@ -0,0 +1,99 @@
+package android.net;
+
+import android.annotation.Nullable;
+import android.content.ComponentName;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.Objects;
+
+/**
+ * Holds metadata about a discovered network scorer/recommendation application.
+ *
+ * @hide
+ */
+public final class NetworkScorerAppData implements Parcelable {
+ /** UID of the scorer app. */
+ public final int packageUid;
+ private final ComponentName mRecommendationService;
+ /**
+ * The {@link ComponentName} of the Activity to start before enabling the "connect to open
+ * wifi networks automatically" feature.
+ */
+ private final ComponentName mEnableUseOpenWifiActivity;
+
+ public NetworkScorerAppData(int packageUid, ComponentName recommendationServiceComp,
+ ComponentName enableUseOpenWifiActivity) {
+ this.packageUid = packageUid;
+ this.mRecommendationService = recommendationServiceComp;
+ this.mEnableUseOpenWifiActivity = enableUseOpenWifiActivity;
+ }
+
+ protected NetworkScorerAppData(Parcel in) {
+ packageUid = in.readInt();
+ mRecommendationService = ComponentName.readFromParcel(in);
+ mEnableUseOpenWifiActivity = ComponentName.readFromParcel(in);
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(packageUid);
+ ComponentName.writeToParcel(mRecommendationService, dest);
+ ComponentName.writeToParcel(mEnableUseOpenWifiActivity, dest);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ public static final Creator<NetworkScorerAppData> CREATOR =
+ new Creator<NetworkScorerAppData>() {
+ @Override
+ public NetworkScorerAppData createFromParcel(Parcel in) {
+ return new NetworkScorerAppData(in);
+ }
+
+ @Override
+ public NetworkScorerAppData[] newArray(int size) {
+ return new NetworkScorerAppData[size];
+ }
+ };
+
+ public String getRecommendationServicePackageName() {
+ return mRecommendationService.getPackageName();
+ }
+
+ public ComponentName getRecommendationServiceComponent() {
+ return mRecommendationService;
+ }
+
+ @Nullable
+ public ComponentName getEnableUseOpenWifiActivity() {
+ return mEnableUseOpenWifiActivity;
+ }
+
+ @Override
+ public String toString() {
+ return "NetworkScorerAppData{" +
+ "packageUid=" + packageUid +
+ ", mRecommendationService=" + mRecommendationService +
+ ", mEnableUseOpenWifiActivity=" + mEnableUseOpenWifiActivity +
+ '}';
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ NetworkScorerAppData that = (NetworkScorerAppData) o;
+ return packageUid == that.packageUid &&
+ Objects.equals(mRecommendationService, that.mRecommendationService) &&
+ Objects.equals(mEnableUseOpenWifiActivity, that.mEnableUseOpenWifiActivity);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(packageUid, mRecommendationService, mEnableUseOpenWifiActivity);
+ }
+}
diff --git a/core/java/android/net/NetworkScorerAppManager.java b/core/java/android/net/NetworkScorerAppManager.java
deleted file mode 100644
index a166c7f..0000000
--- a/core/java/android/net/NetworkScorerAppManager.java
+++ /dev/null
@@ -1,285 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package android.net;
-
-import android.Manifest.permission;
-import android.annotation.Nullable;
-import android.content.ComponentName;
-import android.content.ContentResolver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.pm.PackageManager;
-import android.content.pm.ResolveInfo;
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.os.UserHandle;
-import android.provider.Settings;
-import android.text.TextUtils;
-import android.util.Log;
-
-import com.android.internal.R;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-import java.util.Objects;
-
-/**
- * Internal class for discovering and managing the network scorer/recommendation application.
- *
- * @hide
- */
-public class NetworkScorerAppManager {
- private static final String TAG = "NetworkScorerAppManager";
- private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
- private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE);
- private final Context mContext;
-
- public NetworkScorerAppManager(Context context) {
- mContext = context;
- }
-
- /**
- * Holds metadata about a discovered network scorer/recommendation application.
- */
- public static final class NetworkScorerAppData implements Parcelable {
- /** UID of the scorer app. */
- public final int packageUid;
- private final ComponentName mRecommendationService;
-
- public NetworkScorerAppData(int packageUid, ComponentName recommendationServiceComp) {
- this.packageUid = packageUid;
- this.mRecommendationService = recommendationServiceComp;
- }
-
- protected NetworkScorerAppData(Parcel in) {
- packageUid = in.readInt();
- mRecommendationService = ComponentName.readFromParcel(in);
- }
-
- @Override
- public void writeToParcel(Parcel dest, int flags) {
- dest.writeInt(packageUid);
- ComponentName.writeToParcel(mRecommendationService, dest);
- }
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- public static final Creator<NetworkScorerAppData> CREATOR =
- new Creator<NetworkScorerAppData>() {
- @Override
- public NetworkScorerAppData createFromParcel(Parcel in) {
- return new NetworkScorerAppData(in);
- }
-
- @Override
- public NetworkScorerAppData[] newArray(int size) {
- return new NetworkScorerAppData[size];
- }
- };
-
- public String getRecommendationServicePackageName() {
- return mRecommendationService.getPackageName();
- }
-
- public ComponentName getRecommendationServiceComponent() {
- return mRecommendationService;
- }
-
- @Override
- public String toString() {
- return "NetworkScorerAppData{" +
- "packageUid=" + packageUid +
- ", mRecommendationService=" + mRecommendationService +
- '}';
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) return true;
- if (o == null || getClass() != o.getClass()) return false;
- NetworkScorerAppData that = (NetworkScorerAppData) o;
- return packageUid == that.packageUid &&
- Objects.equals(mRecommendationService, that.mRecommendationService);
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(packageUid, mRecommendationService);
- }
- }
-
- /**
- * Returns the list of available scorer apps. The list will be empty if there are
- * no valid scorers.
- */
- public List<NetworkScorerAppData> getAllValidScorers() {
- return Collections.emptyList();
- }
-
- /**
- * @return A {@link NetworkScorerAppData} instance containing information about the
- * best configured network recommendation provider installed or {@code null}
- * if none of the configured packages can recommend networks.
- *
- * <p>A network recommendation provider is any application which:
- * <ul>
- * <li>Is listed in the <code>config_networkRecommendationPackageNames</code> config.
- * <li>Declares the {@link android.Manifest.permission#SCORE_NETWORKS} permission.
- * <li>Includes a Service for {@link NetworkScoreManager#ACTION_RECOMMEND_NETWORKS}.
- * </ul>
- */
- public NetworkScorerAppData getNetworkRecommendationProviderData() {
- // Network recommendation apps can only run as the primary user right now.
- // http://b/23422763
- if (UserHandle.getCallingUserId() != UserHandle.USER_SYSTEM) {
- return null;
- }
-
- final List<String> potentialPkgs = getPotentialRecommendationProviderPackages();
- if (potentialPkgs.isEmpty()) {
- if (DEBUG) {
- Log.d(TAG, "No Network Recommendation Providers specified.");
- }
- return null;
- }
-
- for (int i = 0; i < potentialPkgs.size(); i++) {
- final String potentialPkg = potentialPkgs.get(i);
-
- // Look for the recommendation service class and required receiver.
- final ResolveInfo resolveServiceInfo = findRecommendationService(potentialPkg);
- if (resolveServiceInfo != null) {
- final ComponentName componentName =
- new ComponentName(potentialPkg, resolveServiceInfo.serviceInfo.name);
- return new NetworkScorerAppData(resolveServiceInfo.serviceInfo.applicationInfo.uid,
- componentName);
- } else {
- if (DEBUG) {
- Log.d(TAG, potentialPkg + " does not have the required components, skipping.");
- }
- }
- }
-
- // None of the configured packages are valid.
- return null;
- }
-
- /**
- * @return A priority order list of package names that have been granted the
- * permission needed for them to act as a network recommendation provider.
- * The packages in the returned list may not contain the other required
- * network recommendation provider components so additional checks are required
- * before making a package the network recommendation provider.
- */
- public List<String> getPotentialRecommendationProviderPackages() {
- final String[] packageArray = mContext.getResources().getStringArray(
- R.array.config_networkRecommendationPackageNames);
- if (packageArray == null || packageArray.length == 0) {
- if (DEBUG) {
- Log.d(TAG, "No Network Recommendation Providers specified.");
- }
- return Collections.emptyList();
- }
-
- if (VERBOSE) {
- Log.d(TAG, "Configured packages: " + TextUtils.join(", ", packageArray));
- }
-
- List<String> packages = new ArrayList<>();
- final PackageManager pm = mContext.getPackageManager();
- for (String potentialPkg : packageArray) {
- if (pm.checkPermission(permission.SCORE_NETWORKS, potentialPkg)
- == PackageManager.PERMISSION_GRANTED) {
- packages.add(potentialPkg);
- } else {
- if (DEBUG) {
- Log.d(TAG, potentialPkg + " has not been granted " + permission.SCORE_NETWORKS
- + ", skipping.");
- }
- }
- }
-
- return packages;
- }
-
- private ResolveInfo findRecommendationService(String packageName) {
- final PackageManager pm = mContext.getPackageManager();
- final int resolveFlags = 0;
-
- final Intent serviceIntent = new Intent(NetworkScoreManager.ACTION_RECOMMEND_NETWORKS);
- serviceIntent.setPackage(packageName);
- final ResolveInfo resolveServiceInfo =
- pm.resolveService(serviceIntent, resolveFlags);
-
- if (VERBOSE) {
- Log.d(TAG, "Resolved " + serviceIntent + " to " + resolveServiceInfo);
- }
-
- if (resolveServiceInfo != null && resolveServiceInfo.serviceInfo != null) {
- return resolveServiceInfo;
- }
-
- if (VERBOSE) {
- Log.v(TAG, packageName + " does not have a service for " + serviceIntent);
- }
- return null;
- }
-
- /**
- * Get the application to use for scoring networks.
- *
- * @return the scorer app info or null if scoring is disabled (including if no scorer was ever
- * selected) or if the previously-set scorer is no longer a valid scorer app (e.g. because
- * it was disabled or uninstalled).
- */
- @Nullable
- public NetworkScorerAppData getActiveScorer() {
- if (isNetworkRecommendationsDisabled()) {
- // If recommendations are disabled then there can't be an active scorer.
- return null;
- }
-
- // Otherwise return the recommendation provider (which may be null).
- return getNetworkRecommendationProviderData();
- }
-
- /**
- * Set the specified package as the default scorer application.
- *
- * <p>The caller must have permission to write to {@link android.provider.Settings.Global}.
- *
- * @param packageName the packageName of the new scorer to use. If null, scoring will be
- * disabled. Otherwise, the scorer will only be set if it is a valid scorer application.
- * @return true if the scorer was changed, or false if the package is not a valid scorer or
- * a valid network recommendation provider exists.
- * @deprecated Scorers are now selected from a configured list.
- */
- @Deprecated
- public boolean setActiveScorer(String packageName) {
- return false;
- }
-
- private boolean isNetworkRecommendationsDisabled() {
- final ContentResolver cr = mContext.getContentResolver();
- // A value of 1 indicates enabled.
- return Settings.Global.getInt(cr, Settings.Global.NETWORK_RECOMMENDATIONS_ENABLED, 0) != 1;
- }
-}
diff --git a/core/java/android/net/http/SslCertificate.java b/core/java/android/net/http/SslCertificate.java
index 2715af0..4c0f418 100644
--- a/core/java/android/net/http/SslCertificate.java
+++ b/core/java/android/net/http/SslCertificate.java
@@ -506,6 +506,6 @@
if (certificateDate == null) {
return "";
}
- return DateFormat.getDateFormat(context).format(certificateDate);
+ return DateFormat.getMediumDateFormat(context).format(certificateDate);
}
}
diff --git a/core/java/android/net/metrics/ApfProgramEvent.java b/core/java/android/net/metrics/ApfProgramEvent.java
index 258d8e1..c2795a2a 100644
--- a/core/java/android/net/metrics/ApfProgramEvent.java
+++ b/core/java/android/net/metrics/ApfProgramEvent.java
@@ -17,7 +17,6 @@
package android.net.metrics;
import android.annotation.IntDef;
-import android.annotation.SystemApi;
import android.os.Parcel;
import android.os.Parcelable;
import android.text.TextUtils;
@@ -36,7 +35,6 @@
* the APF program in place with a new APF program.
* {@hide}
*/
-@SystemApi
public final class ApfProgramEvent implements Parcelable {
// Bitflag constants describing what an Apf program filters.
@@ -55,7 +53,6 @@
public final int programLength; // Length of the APF program in bytes
public final int flags; // Bitfield compound of FLAG_* constants
- /** {@hide} */
public ApfProgramEvent(
long lifetime, int filteredRas, int currentRas, int programLength, @Flags int flags) {
this.lifetime = lifetime;
@@ -105,7 +102,6 @@
}
};
- /** {@hide} */
public static @Flags int flagsFor(boolean hasIPv4, boolean multicastFilterOn) {
int bitfield = 0;
if (hasIPv4) {
diff --git a/core/java/android/net/metrics/ApfStats.java b/core/java/android/net/metrics/ApfStats.java
index 8451e53..f8d7fa9 100644
--- a/core/java/android/net/metrics/ApfStats.java
+++ b/core/java/android/net/metrics/ApfStats.java
@@ -16,7 +16,6 @@
package android.net.metrics;
-import android.annotation.SystemApi;
import android.os.Parcel;
import android.os.Parcelable;
@@ -24,7 +23,6 @@
* An event logged for an interface with APF capabilities when its IpManager state machine exits.
* {@hide}
*/
-@SystemApi
public final class ApfStats implements Parcelable {
public final long durationMs; // time interval in milliseconds these stastistics covers
@@ -36,7 +34,6 @@
public final int programUpdates; // number of APF program updates
public final int maxProgramSize; // maximum APF program size advertised by hardware
- /** {@hide} */
public ApfStats(long durationMs, int receivedRas, int matchingRas, int droppedRas,
int zeroLifetimeRas, int parseErrors, int programUpdates, int maxProgramSize) {
this.durationMs = durationMs;
diff --git a/core/java/android/net/metrics/DefaultNetworkEvent.java b/core/java/android/net/metrics/DefaultNetworkEvent.java
index 9f0bad7..28cf42f 100644
--- a/core/java/android/net/metrics/DefaultNetworkEvent.java
+++ b/core/java/android/net/metrics/DefaultNetworkEvent.java
@@ -16,7 +16,6 @@
package android.net.metrics;
-import android.annotation.SystemApi;
import android.net.NetworkCapabilities;
import android.os.Parcel;
import android.os.Parcelable;
@@ -25,7 +24,6 @@
* An event recorded by ConnectivityService when there is a change in the default network.
* {@hide}
*/
-@SystemApi
public final class DefaultNetworkEvent implements Parcelable {
// The ID of the network that has become the new default or NETID_UNSET if none.
public final int netId;
@@ -38,7 +36,6 @@
public final boolean prevIPv4;
public final boolean prevIPv6;
- /** {@hide} */
public DefaultNetworkEvent(int netId, int[] transportTypes,
int prevNetId, boolean prevIPv4, boolean prevIPv6) {
this.netId = netId;
@@ -106,8 +103,4 @@
return new DefaultNetworkEvent[size];
}
};
-
- public static void logEvent(
- int netId, int[] transports, int prevNetId, boolean hadIPv4, boolean hadIPv6) {
- }
}
diff --git a/core/java/android/net/metrics/DhcpClientEvent.java b/core/java/android/net/metrics/DhcpClientEvent.java
index 4a9ff05..7e30ab5 100644
--- a/core/java/android/net/metrics/DhcpClientEvent.java
+++ b/core/java/android/net/metrics/DhcpClientEvent.java
@@ -16,7 +16,6 @@
package android.net.metrics;
-import android.annotation.SystemApi;
import android.os.Parcel;
import android.os.Parcelable;
@@ -24,7 +23,6 @@
* An event recorded when a DhcpClient state machine transitions to a new state.
* {@hide}
*/
-@SystemApi
public final class DhcpClientEvent implements Parcelable {
// Names for recording DhcpClient pseudo-state transitions.
@@ -37,7 +35,6 @@
public final String msg;
public final int durationMs;
- /** {@hide} */
public DhcpClientEvent(String ifName, String msg, int durationMs) {
this.ifName = ifName;
this.msg = msg;
@@ -77,7 +74,4 @@
return new DhcpClientEvent[size];
}
};
-
- public static void logStateEvent(String ifName, String state) {
- }
}
diff --git a/core/java/android/net/metrics/DhcpErrorEvent.java b/core/java/android/net/metrics/DhcpErrorEvent.java
index c3abcf7..f34ffdf 100644
--- a/core/java/android/net/metrics/DhcpErrorEvent.java
+++ b/core/java/android/net/metrics/DhcpErrorEvent.java
@@ -16,7 +16,6 @@
package android.net.metrics;
-import android.annotation.SystemApi;
import android.os.Parcel;
import android.os.Parcelable;
import android.util.SparseArray;
@@ -27,7 +26,6 @@
* Event class used to record error events when parsing DHCP response packets.
* {@hide}
*/
-@SystemApi
public final class DhcpErrorEvent implements Parcelable {
public static final int L2_ERROR = 1;
public static final int L3_ERROR = 2;
@@ -50,12 +48,10 @@
public static final int DHCP_INVALID_OPTION_LENGTH = makeErrorCode(DHCP_ERROR, 3);
public static final int DHCP_NO_MSG_TYPE = makeErrorCode(DHCP_ERROR, 4);
public static final int DHCP_UNKNOWN_MSG_TYPE = makeErrorCode(DHCP_ERROR, 5);
- /** {@hide} */
public static final int DHCP_NO_COOKIE = makeErrorCode(DHCP_ERROR, 6);
public static final int BUFFER_UNDERFLOW = makeErrorCode(MISC_ERROR, 1);
public static final int RECEIVE_ERROR = makeErrorCode(MISC_ERROR, 2);
- /** {@hide} */
public static final int PARSING_ERROR = makeErrorCode(MISC_ERROR, 3);
public final String ifName;
@@ -66,7 +62,6 @@
// byte 3: optional code
public final int errorCode;
- /** {@hide} */
public DhcpErrorEvent(String ifName, int errorCode) {
this.ifName = ifName;
this.errorCode = errorCode;
@@ -99,12 +94,6 @@
}
};
- public static void logParseError(String ifName, int errorCode) {
- }
-
- public static void logReceiveError(String ifName) {
- }
-
public static int errorCodeWithOption(int errorCode, int option) {
return (0xFFFF0000 & errorCode) | (0xFF & option);
}
diff --git a/core/java/android/net/metrics/DnsEvent.java b/core/java/android/net/metrics/DnsEvent.java
index 6176b2c..89ae1c2 100644
--- a/core/java/android/net/metrics/DnsEvent.java
+++ b/core/java/android/net/metrics/DnsEvent.java
@@ -16,7 +16,6 @@
package android.net.metrics;
-import android.annotation.SystemApi;
import android.os.Parcel;
import android.os.Parcelable;
@@ -24,7 +23,6 @@
* A DNS event recorded by NetdEventListenerService.
* {@hide}
*/
-@SystemApi
final public class DnsEvent implements Parcelable {
public final int netId;
@@ -38,7 +36,6 @@
// queries.
public final int[] latenciesMs;
- /** {@hide} */
public DnsEvent(int netId, byte[] eventTypes, byte[] returnCodes, int[] latenciesMs) {
this.netId = netId;
this.eventTypes = eventTypes;
@@ -82,8 +79,4 @@
return new DnsEvent[size];
}
};
-
- public static void logEvent(
- int netId, byte[] eventTypes, byte[] returnCodes, int[] latenciesMs) {
- }
}
diff --git a/core/java/android/net/metrics/IpManagerEvent.java b/core/java/android/net/metrics/IpManagerEvent.java
index e0a026e..50dda7c 100644
--- a/core/java/android/net/metrics/IpManagerEvent.java
+++ b/core/java/android/net/metrics/IpManagerEvent.java
@@ -17,7 +17,6 @@
package android.net.metrics;
import android.annotation.IntDef;
-import android.annotation.SystemApi;
import android.os.Parcel;
import android.os.Parcelable;
import android.util.SparseArray;
@@ -32,17 +31,15 @@
* when a network disconnects.
* {@hide}
*/
-@SystemApi
public final class IpManagerEvent implements Parcelable {
- public static final int PROVISIONING_OK = 1;
- public static final int PROVISIONING_FAIL = 2;
- public static final int COMPLETE_LIFECYCLE = 3;
- /** @hide */ public static final int ERROR_STARTING_IPV4 = 4;
- /** @hide */ public static final int ERROR_STARTING_IPV6 = 5;
- /** @hide */ public static final int ERROR_STARTING_IPREACHABILITYMONITOR = 6;
+ public static final int PROVISIONING_OK = 1;
+ public static final int PROVISIONING_FAIL = 2;
+ public static final int COMPLETE_LIFECYCLE = 3;
+ public static final int ERROR_STARTING_IPV4 = 4;
+ public static final int ERROR_STARTING_IPV6 = 5;
+ public static final int ERROR_STARTING_IPREACHABILITYMONITOR = 6;
- /** {@hide} */
@IntDef(value = {
PROVISIONING_OK, PROVISIONING_FAIL, COMPLETE_LIFECYCLE,
ERROR_STARTING_IPV4, ERROR_STARTING_IPV6, ERROR_STARTING_IPREACHABILITYMONITOR,
@@ -54,7 +51,6 @@
public final @EventType int eventType;
public final long durationMs;
- /** {@hide} */
public IpManagerEvent(String ifName, @EventType int eventType, long duration) {
this.ifName = ifName;
this.eventType = eventType;
@@ -90,9 +86,6 @@
}
};
- public static void logEvent(int eventType, String ifName, long durationMs) {
- }
-
@Override
public String toString() {
return String.format("IpManagerEvent(%s, %s, %dms)",
diff --git a/core/java/android/net/metrics/IpReachabilityEvent.java b/core/java/android/net/metrics/IpReachabilityEvent.java
index ee09e22..d69e806 100644
--- a/core/java/android/net/metrics/IpReachabilityEvent.java
+++ b/core/java/android/net/metrics/IpReachabilityEvent.java
@@ -16,7 +16,6 @@
package android.net.metrics;
-import android.annotation.SystemApi;
import android.os.Parcel;
import android.os.Parcelable;
import android.util.SparseArray;
@@ -28,7 +27,6 @@
* a neighbor probe result.
* {@hide}
*/
-@SystemApi
public final class IpReachabilityEvent implements Parcelable {
// Event types.
@@ -38,9 +36,9 @@
public static final int NUD_FAILED = 2 << 8;
/** Neighbor unreachable after a forced probe, IP provisioning is also lost. */
public static final int PROVISIONING_LOST = 3 << 8;
- /** {@hide} Neighbor unreachable notification from kernel. */
+ /** Neighbor unreachable notification from kernel. */
public static final int NUD_FAILED_ORGANIC = 4 << 8;
- /** {@hide} Neighbor unreachable notification from kernel, IP provisioning is also lost. */
+ /** Neighbor unreachable notification from kernel, IP provisioning is also lost. */
public static final int PROVISIONING_LOST_ORGANIC = 5 << 8;
public final String ifName;
@@ -51,7 +49,6 @@
// byte 3: when byte 2 == PROBE, errno code from RTNetlink or IpReachabilityMonitor.
public final int eventType;
- /** {@hide} */
public IpReachabilityEvent(String ifName, int eventType) {
this.ifName = ifName;
this.eventType = eventType;
@@ -84,18 +81,8 @@
}
};
- public static void logProbeEvent(String ifName, int nlErrorCode) {
- }
-
- public static void logNudFailed(String ifName) {
- }
-
- public static void logProvisioningLost(String ifName) {
- }
-
/**
* Returns the NUD failure event type code corresponding to the given conditions.
- * {@hide}
*/
public static int nudFailureEventType(boolean isFromProbe, boolean isProvisioningLost) {
if (isFromProbe) {
diff --git a/core/java/android/net/metrics/NetworkEvent.java b/core/java/android/net/metrics/NetworkEvent.java
index 0667495..4df3bf0 100644
--- a/core/java/android/net/metrics/NetworkEvent.java
+++ b/core/java/android/net/metrics/NetworkEvent.java
@@ -17,7 +17,6 @@
package android.net.metrics;
import android.annotation.IntDef;
-import android.annotation.SystemApi;
import android.os.Parcel;
import android.os.Parcelable;
import android.util.SparseArray;
@@ -30,7 +29,6 @@
/**
* {@hide}
*/
-@SystemApi
public final class NetworkEvent implements Parcelable {
public static final int NETWORK_CONNECTED = 1;
@@ -41,16 +39,11 @@
public static final int NETWORK_UNLINGER = 6;
public static final int NETWORK_DISCONNECTED = 7;
- /** {@hide} */
public static final int NETWORK_FIRST_VALIDATION_SUCCESS = 8;
- /** {@hide} */
public static final int NETWORK_REVALIDATION_SUCCESS = 9;
- /** {@hide} */
public static final int NETWORK_FIRST_VALIDATION_PORTAL_FOUND = 10;
- /** {@hide} */
public static final int NETWORK_REVALIDATION_PORTAL_FOUND = 11;
- /** {@hide} */
@IntDef(value = {
NETWORK_CONNECTED,
NETWORK_VALIDATED,
@@ -71,14 +64,12 @@
public final @EventType int eventType;
public final long durationMs;
- /** {@hide} */
public NetworkEvent(int netId, @EventType int eventType, long durationMs) {
this.netId = netId;
this.eventType = eventType;
this.durationMs = durationMs;
}
- /** {@hide} */
public NetworkEvent(int netId, @EventType int eventType) {
this(netId, eventType, 0);
}
@@ -112,15 +103,6 @@
}
};
- public static void logEvent(int netId, int eventType) {
- }
-
- public static void logValidated(int netId, long durationMs) {
- }
-
- public static void logCaptivePortalFound(int netId, long durationMs) {
- }
-
@Override
public String toString() {
return String.format("NetworkEvent(%d, %s, %dms)",
diff --git a/core/java/android/net/metrics/RaEvent.java b/core/java/android/net/metrics/RaEvent.java
index 91bd023..3249f80 100644
--- a/core/java/android/net/metrics/RaEvent.java
+++ b/core/java/android/net/metrics/RaEvent.java
@@ -16,7 +16,6 @@
package android.net.metrics;
-import android.annotation.SystemApi;
import android.os.Parcel;
import android.os.Parcelable;
@@ -24,10 +23,8 @@
* An event logged when the APF packet socket receives an RA packet.
* {@hide}
*/
-@SystemApi
public final class RaEvent implements Parcelable {
- /** {@hide} */
public static final long NO_LIFETIME = -1L;
// Lifetime in seconds of options found in a single RA packet.
@@ -39,7 +36,6 @@
public final long rdnssLifetime;
public final long dnsslLifetime;
- /** {@hide} */
public RaEvent(long routerLifetime, long prefixValidLifetime, long prefixPreferredLifetime,
long routeInfoLifetime, long rdnssLifetime, long dnsslLifetime) {
this.routerLifetime = routerLifetime;
@@ -96,7 +92,6 @@
}
};
- /** {@hide} */
public static class Builder {
long routerLifetime = NO_LIFETIME;
diff --git a/core/java/android/net/metrics/ValidationProbeEvent.java b/core/java/android/net/metrics/ValidationProbeEvent.java
index a724ec1..70c6e84 100644
--- a/core/java/android/net/metrics/ValidationProbeEvent.java
+++ b/core/java/android/net/metrics/ValidationProbeEvent.java
@@ -17,7 +17,6 @@
package android.net.metrics;
import android.annotation.IntDef;
-import android.annotation.SystemApi;
import android.os.Parcel;
import android.os.Parcelable;
import android.util.SparseArray;
@@ -31,14 +30,12 @@
* An event recorded by NetworkMonitor when sending a probe for finding captive portals.
* {@hide}
*/
-@SystemApi
public final class ValidationProbeEvent implements Parcelable {
public static final int PROBE_DNS = 0;
public static final int PROBE_HTTP = 1;
public static final int PROBE_HTTPS = 2;
public static final int PROBE_PAC = 3;
- /** {@hide} */
public static final int PROBE_FALLBACK = 4;
public static final int DNS_FAILURE = 0;
@@ -47,7 +44,6 @@
private static final int FIRST_VALIDATION = 1 << 8;
private static final int REVALIDATION = 2 << 8;
- /** {@hide} */
@IntDef(value = {DNS_FAILURE, DNS_SUCCESS})
@Retention(RetentionPolicy.SOURCE)
public @interface ReturnCode {}
@@ -62,7 +58,6 @@
public final int probeType;
public final @ReturnCode int returnCode;
- /** {@hide} */
public ValidationProbeEvent(
int netId, long durationMs, int probeType, @ReturnCode int returnCode) {
this.netId = netId;
@@ -102,24 +97,18 @@
}
};
- /** @hide */
public static int makeProbeType(int probeType, boolean firstValidation) {
return (probeType & 0xff) | (firstValidation ? FIRST_VALIDATION : REVALIDATION);
}
- /** @hide */
public static String getProbeName(int probeType) {
return Decoder.constants.get(probeType & 0xff, "PROBE_???");
}
- /** @hide */
public static String getValidationStage(int probeType) {
return Decoder.constants.get(probeType & 0xff00, "UNKNOWN");
}
- public static void logEvent(int netId, long durationMs, int probeType, int returnCode) {
- }
-
@Override
public String toString() {
return String.format("ValidationProbeEvent(%d, %s:%d %s, %dms)", netId,
diff --git a/core/java/android/os/BatteryManager.java b/core/java/android/os/BatteryManager.java
index 3a441c7..734d89e 100644
--- a/core/java/android/os/BatteryManager.java
+++ b/core/java/android/os/BatteryManager.java
@@ -118,6 +118,13 @@
*/
public static final String EXTRA_CHARGE_COUNTER = "charge_counter";
+ /**
+ * Extra for {@link android.content.Intent#ACTION_BATTERY_CHANGED}:
+ * Current int sequence number of the update.
+ * {@hide}
+ */
+ public static final String EXTRA_SEQUENCE = "seq";
+
// values for "status" field in the ACTION_BATTERY_CHANGED Intent
public static final int BATTERY_STATUS_UNKNOWN = Constants.BATTERY_STATUS_UNKNOWN;
public static final int BATTERY_STATUS_CHARGING = Constants.BATTERY_STATUS_CHARGING;
@@ -204,7 +211,7 @@
/**
* Battery charge status, from a BATTERY_STATUS_* value.
*/
- public static final int BATTERY_PROPERTY_BATTERY_STATUS = 6;
+ public static final int BATTERY_PROPERTY_STATUS = 6;
private final IBatteryStats mBatteryStats;
private final IBatteryPropertiesRegistrar mBatteryPropertiesRegistrar;
diff --git a/core/java/android/os/FileUtils.java b/core/java/android/os/FileUtils.java
index 280fa2c..af05ee7 100644
--- a/core/java/android/os/FileUtils.java
+++ b/core/java/android/os/FileUtils.java
@@ -770,4 +770,17 @@
return dir.mkdir() ? dir : null;
}
+
+ /**
+ * Round the given size of a storage device to a nice round power-of-two
+ * value, such as 256MB or 32GB. This avoids showing weird values like
+ * "29.5GB" in UI.
+ */
+ public static long roundStorageSize(long size) {
+ long res = 1;
+ while (res < size) {
+ res <<= 1;
+ }
+ return res;
+ }
}
diff --git a/core/java/android/os/Looper.java b/core/java/android/os/Looper.java
index d299672..63d3e7a 100644
--- a/core/java/android/os/Looper.java
+++ b/core/java/android/os/Looper.java
@@ -18,8 +18,10 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.os.LooperProto;
import android.util.Log;
import android.util.Printer;
+import android.util.proto.ProtoOutputStream;
/**
* Class used to run a message loop for a thread. Threads by default do
@@ -289,6 +291,16 @@
mQueue.dump(pw, prefix + " ");
}
+ /** @hide */
+ public void writeToProto(ProtoOutputStream proto, long fieldId) {
+ final long looperToken = proto.start(fieldId);
+ proto.write(LooperProto.THREAD_NAME, mThread.getName());
+ proto.write(LooperProto.THREAD_ID, mThread.getId());
+ proto.write(LooperProto.IDENTITY_HASH_CODE, System.identityHashCode(this));
+ mQueue.writeToProto(proto, LooperProto.QUEUE);
+ proto.end(looperToken);
+ }
+
@Override
public String toString() {
return "Looper (" + mThread.getName() + ", tid " + mThread.getId()
diff --git a/core/java/android/os/Message.java b/core/java/android/os/Message.java
index 8c75847..d066db1 100644
--- a/core/java/android/os/Message.java
+++ b/core/java/android/os/Message.java
@@ -16,13 +16,15 @@
package android.os;
+import android.os.MessageProto;
import android.util.TimeUtils;
+import android.util.proto.ProtoOutputStream;
/**
- *
+ *
* Defines a message containing a description and arbitrary data object that can be
* sent to a {@link Handler}. This object contains two extra int fields and an
- * extra object field that allow you to not do allocations in many cases.
+ * extra object field that allow you to not do allocations in many cases.
*
* <p class="note">While the constructor of Message is public, the best way to get
* one of these is to call {@link #obtain Message.obtain()} or one of the
@@ -31,7 +33,7 @@
*/
public final class Message implements Parcelable {
/**
- * User-defined message code so that the recipient can identify
+ * User-defined message code so that the recipient can identify
* what this message is about. Each {@link Handler} has its own name-space
* for message codes, so you do not need to worry about yours conflicting
* with other handlers.
@@ -43,7 +45,7 @@
* {@link #setData(Bundle) setData()} if you only need to store a
* few integer values.
*/
- public int arg1;
+ public int arg1;
/**
* arg1 and arg2 are lower-cost alternatives to using
@@ -58,7 +60,7 @@
* be non-null if it contains a Parcelable of a framework class (not one
* implemented by the application). For other data transfer use
* {@link #setData}.
- *
+ *
* <p>Note that Parcelable objects here are not supported prior to
* the {@link android.os.Build.VERSION_CODES#FROYO} release.
*/
@@ -97,13 +99,13 @@
/*package*/ int flags;
/*package*/ long when;
-
+
/*package*/ Bundle data;
-
+
/*package*/ Handler target;
-
+
/*package*/ Runnable callback;
-
+
// sometimes we store linked lists of these things
/*package*/ Message next;
@@ -216,9 +218,9 @@
}
/**
- * Same as {@link #obtain()}, but sets the values of the <em>target</em>, <em>what</em>,
+ * Same as {@link #obtain()}, but sets the values of the <em>target</em>, <em>what</em>,
* <em>arg1</em>, and <em>arg2</em> members.
- *
+ *
* @param h The <em>target</em> value to set.
* @param what The <em>what</em> value to set.
* @param arg1 The <em>arg1</em> value to set.
@@ -236,9 +238,9 @@
}
/**
- * Same as {@link #obtain()}, but sets the values of the <em>target</em>, <em>what</em>,
+ * Same as {@link #obtain()}, but sets the values of the <em>target</em>, <em>what</em>,
* <em>arg1</em>, <em>arg2</em>, and <em>obj</em> members.
- *
+ *
* @param h The <em>target</em> value to set.
* @param what The <em>what</em> value to set.
* @param arg1 The <em>arg1</em> value to set.
@@ -246,7 +248,7 @@
* @param obj The <em>obj</em> value to set.
* @return A Message object from the global pool.
*/
- public static Message obtain(Handler h, int what,
+ public static Message obtain(Handler h, int what,
int arg1, int arg2, Object obj) {
Message m = obtain();
m.target = h;
@@ -339,7 +341,7 @@
public long getWhen() {
return when;
}
-
+
public void setTarget(Handler target) {
this.target = target;
}
@@ -367,8 +369,8 @@
public Runnable getCallback() {
return callback;
}
-
- /**
+
+ /**
* Obtains a Bundle of arbitrary data associated with this
* event, lazily creating it if necessary. Set this value by calling
* {@link #setData(Bundle)}. Note that when transferring data across
@@ -383,11 +385,11 @@
if (data == null) {
data = new Bundle();
}
-
+
return data;
}
- /**
+ /**
* Like getData(), but does not lazily create the Bundle. A null
* is returned if the Bundle does not already exist. See
* {@link #getData} for further information on this.
@@ -401,7 +403,7 @@
/**
* Sets a Bundle of arbitrary data values. Use arg1 and arg2 members
* as a lower cost way to send a few simple integer values, if you can.
- * @see #getData()
+ * @see #getData()
* @see #peekData()
*/
public void setData(Bundle data) {
@@ -520,6 +522,37 @@
return b.toString();
}
+ void writeToProto(ProtoOutputStream proto, long fieldId) {
+ final long messageToken = proto.start(fieldId);
+ proto.write(MessageProto.WHEN, when);
+
+ if (target != null) {
+ if (callback != null) {
+ proto.write(MessageProto.CALLBACK, callback.getClass().getName());
+ } else {
+ proto.write(MessageProto.WHAT, what);
+ }
+
+ if (arg1 != 0) {
+ proto.write(MessageProto.ARG1, arg1);
+ }
+
+ if (arg2 != 0) {
+ proto.write(MessageProto.ARG2, arg2);
+ }
+
+ if (obj != null) {
+ proto.write(MessageProto.OBJ, obj.toString());
+ }
+
+ proto.write(MessageProto.TARGET, target.getClass().getName());
+ } else {
+ proto.write(MessageProto.BARRIER, arg1);
+ }
+
+ proto.end(messageToken);
+ }
+
public static final Parcelable.Creator<Message> CREATOR
= new Parcelable.Creator<Message>() {
public Message createFromParcel(Parcel source) {
@@ -527,12 +560,12 @@
msg.readFromParcel(source);
return msg;
}
-
+
public Message[] newArray(int size) {
return new Message[size];
}
};
-
+
public int describeContents() {
return 0;
}
diff --git a/core/java/android/os/MessageQueue.java b/core/java/android/os/MessageQueue.java
index 4f2e968..2a8c52e 100644
--- a/core/java/android/os/MessageQueue.java
+++ b/core/java/android/os/MessageQueue.java
@@ -18,9 +18,11 @@
import android.annotation.IntDef;
import android.annotation.NonNull;
+import android.os.MessageQueueProto;
import android.util.Log;
import android.util.Printer;
import android.util.SparseArray;
+import android.util.proto.ProtoOutputStream;
import java.io.FileDescriptor;
import java.lang.annotation.Retention;
@@ -31,7 +33,7 @@
* Low-level class holding the list of messages to be dispatched by a
* {@link Looper}. Messages are not added directly to a MessageQueue,
* but rather through {@link Handler} objects associated with the Looper.
- *
+ *
* <p>You can retrieve the MessageQueue for the current thread with
* {@link Looper#myQueue() Looper.myQueue()}.
*/
@@ -770,6 +772,18 @@
}
}
+ void writeToProto(ProtoOutputStream proto, long fieldId) {
+ final long messageQueueToken = proto.start(fieldId);
+ synchronized (this) {
+ for (Message msg = mMessages; msg != null; msg = msg.next) {
+ msg.writeToProto(proto, MessageQueueProto.MESSAGES);
+ }
+ proto.write(MessageQueueProto.IS_POLLING_LOCKED, isPollingLocked());
+ proto.write(MessageQueueProto.IS_QUITTING, mQuitting);
+ }
+ proto.end(messageQueueToken);
+ }
+
/**
* Callback interface for discovering when a thread is going to block
* waiting for more messages.
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index 21c70f9..13a495e 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -1097,40 +1097,6 @@
}
}
- /** @removed */
- @Deprecated
- public boolean isUserRunningAndLocked() {
- return isUserRunningAndLocked(Process.myUserHandle());
- }
-
- /** @removed */
- @Deprecated
- public boolean isUserRunningAndLocked(UserHandle user) {
- try {
- return ActivityManager.getService().isUserRunning(
- user.getIdentifier(), ActivityManager.FLAG_AND_LOCKED);
- } catch (RemoteException re) {
- throw re.rethrowFromSystemServer();
- }
- }
-
- /** @removed */
- @Deprecated
- public boolean isUserRunningAndUnlocked() {
- return isUserRunningAndUnlocked(Process.myUserHandle());
- }
-
- /** @removed */
- @Deprecated
- public boolean isUserRunningAndUnlocked(UserHandle user) {
- try {
- return ActivityManager.getService().isUserRunning(
- user.getIdentifier(), ActivityManager.FLAG_AND_UNLOCKED);
- } catch (RemoteException re) {
- throw re.rethrowFromSystemServer();
- }
- }
-
/**
* Return whether the calling user is running in an "unlocked" state.
* <p>
diff --git a/core/java/android/os/WorkSource.java b/core/java/android/os/WorkSource.java
index f8da87a..ecec448 100644
--- a/core/java/android/os/WorkSource.java
+++ b/core/java/android/os/WorkSource.java
@@ -1,6 +1,8 @@
package android.os;
+import android.os.WorkSourceProto;
import android.util.Log;
+import android.util.proto.ProtoOutputStream;
import java.util.Arrays;
@@ -296,7 +298,7 @@
break;
}
if (mUids[i] == uid) {
- int diff = mNames[i].compareTo(name);
+ int diff = mNames[i].compareTo(name);
if (diff > 0) {
break;
}
@@ -692,6 +694,20 @@
return result.toString();
}
+ /** @hide */
+ public void writeToProto(ProtoOutputStream proto, long fieldId) {
+ final long workSourceToken = proto.start(fieldId);
+ for (int i = 0; i < mNum; i++) {
+ final long contentProto = proto.start(WorkSourceProto.WORK_SOURCE_CONTENTS);
+ proto.write(WorkSourceProto.WorkSourceContentProto.UID, mUids[i]);
+ if (mNames != null) {
+ proto.write(WorkSourceProto.WorkSourceContentProto.NAME, mNames[i]);
+ }
+ proto.end(contentProto);
+ }
+ proto.end(workSourceToken);
+ }
+
public static final Parcelable.Creator<WorkSource> CREATOR
= new Parcelable.Creator<WorkSource>() {
public WorkSource createFromParcel(Parcel in) {
diff --git a/core/java/android/preference/PreferenceManager.java b/core/java/android/preference/PreferenceManager.java
index a2f4db6..756c3f4 100644
--- a/core/java/android/preference/PreferenceManager.java
+++ b/core/java/android/preference/PreferenceManager.java
@@ -420,12 +420,6 @@
mSharedPreferences = null;
}
- /** @removed */
- @Deprecated
- public void setStorageDeviceEncrypted() {
- setStorageDeviceProtected();
- }
-
/**
* Explicitly set the storage location used internally by this class to be
* credential-protected storage. This is the default storage area for apps
@@ -445,12 +439,6 @@
mSharedPreferences = null;
}
- /** @removed */
- @Deprecated
- public void setStorageCredentialEncrypted() {
- setStorageCredentialProtected();
- }
-
/**
* Indicates if the storage location used internally by this class is the
* default provided by the hosting {@link Context}.
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 6d5fcc0..c4a5be7 100755
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -1121,7 +1121,7 @@
public static final String ACTION_ZEN_MODE_SETTINGS = "android.settings.ZEN_MODE_SETTINGS";
/**
- * Activity Action: Show Zen Mode priority configuration settings.
+ * Activity Action: Show Zen Mode (aka Do Not Disturb) priority configuration settings.
*/
@SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
public static final String ACTION_ZEN_MODE_PRIORITY_SETTINGS
@@ -4635,7 +4635,7 @@
return setLocationModeForUser(resolver, Integer.parseInt(value), userHandle);
}
if (MOVED_TO_GLOBAL.contains(name)) {
- Log.w(TAG, "Setting " + name + " has moved from android.provider.Settings.System"
+ Log.w(TAG, "Setting " + name + " has moved from android.provider.Settings.Secure"
+ " to android.provider.Settings.Global");
return Global.putStringForUser(resolver, name, value,
tag, makeDefault, userHandle);
@@ -6905,6 +6905,12 @@
public static final String PACKAGE_VERIFIER_STATE = "package_verifier_state";
/**
+ * Specifies additional package name for broadcasting the CMAS messages.
+ * @hide
+ */
+ public static final String CMAS_ADDITIONAL_BROADCAST_PKG = "cmas_additional_broadcast_pkg";
+
+ /**
* This are the settings to be backed up.
*
* NOTE: Settings are backed up and restored in the order they appear
@@ -8258,6 +8264,15 @@
public static final String CURATE_SAVED_OPEN_NETWORKS = "curate_saved_open_networks";
/**
+ * The package name of the application that connect and secures high quality open wifi
+ * networks automatically.
+ *
+ * Type: string package name or null if the feature is either not provided or disabled.
+ * @hide
+ */
+ public static final String USE_OPEN_WIFI_PACKAGE = "use_open_wifi_package";
+
+ /**
* The number of milliseconds the {@link com.android.server.NetworkScoreService}
* will give a recommendation request to complete before returning a default response.
*
@@ -8267,6 +8282,16 @@
public static final String NETWORK_RECOMMENDATION_REQUEST_TIMEOUT_MS =
"network_recommendation_request_timeout_ms";
+ /**
+ * The expiration time in milliseconds for the {@link android.net.WifiKey} request cache in
+ * {@link com.android.server.wifi.RecommendedNetworkEvaluator}.
+ *
+ * Type: long
+ * @hide
+ */
+ public static final String RECOMMENDED_NETWORK_EVALUATOR_CACHE_EXPIRY_MS =
+ "recommended_network_evaluator_cache_expiry_ms";
+
/**
* Settings to allow BLE scans to be enabled even when Bluetooth is turned off for
* connectivity.
@@ -9679,6 +9704,7 @@
CURATE_SAVED_OPEN_NETWORKS,
WIFI_WAKEUP_ENABLED,
WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON,
+ USE_OPEN_WIFI_PACKAGE,
WIFI_WATCHDOG_POOR_NETWORK_TEST_ENABLED,
EMERGENCY_TONE,
CALL_AUTO_RETRY,
diff --git a/core/java/android/service/autofill/FillResponse.java b/core/java/android/service/autofill/FillResponse.java
index 91c668e..ba75c8b 100644
--- a/core/java/android/service/autofill/FillResponse.java
+++ b/core/java/android/service/autofill/FillResponse.java
@@ -23,7 +23,6 @@
import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
-import android.util.ArraySet;
import android.view.autofill.AutoFillId;
import android.view.autofill.AutoFillManager;
import android.widget.RemoteViews;
@@ -69,18 +68,19 @@
*
* <p>If the user does not have any data associated with this {@link android.app.Activity} but
* the service wants to offer the user the option to save the data that was entered, then the
- * service could populate the response with {@code savableIds} instead of {@link Dataset}s:
+ * service could populate the response with a {@link SaveInfo} instead of {@link Dataset}s:
*
* <pre class="prettyprint">
* new FillResponse.Builder()
- * .addSavableFields(id1, id2)
+ * .setSaveInfo(new SaveInfo.Builder(SaveInfo.SAVE_INFO_TYPE_CREDENTIALS)
+ * .addSavableFields(id1, id2))
* .build();
* </pre>
*
* <p>Similarly, there might be cases where the user data on the service is enough to populate some
* fields but not all, and the service would still be interested on saving the other fields. In this
- * scenario, the service could populate the response with both {@link Dataset}s and {@code
- * savableIds}:
+ * scenario, the service could populate the response with both {@link Dataset}s and
+ * {@link SaveInfo}:
*
* <pre class="prettyprint">
* new FillResponse.Builder()
@@ -90,7 +90,8 @@
* .setTextFieldValue(id3, "742 Evergreen Terrace") // street
* .setTextFieldValue(id4, "Springfield") // city
* .build())
- * .addSavableFields(id5, id6) // state and zipcode
+ * .setSaveInfo(new SaveInfo.Builder(SaveInfo.SAVE_INFO_TYPE_ADDRESS)
+ * .addSavableFields(id5, id6)) // state and zipcode
* .build();
*
* </pre>
@@ -140,9 +141,11 @@
* </pre>
*
* <p>The service could require user authentication at the {@link FillResponse} or the
- * {@link Dataset} level, prior to auto-filling an activity - see {@link FillResponse.Builder
- * #setAuthentication(IntentSender)} and {@link Dataset.Builder#setAuthentication(IntentSender)}.
- * It is recommended that you encrypt only the sensitive data but leave the labels unencrypted
+ * {@link Dataset} level, prior to auto-filling an activity - see
+ * {@link FillResponse.Builder#setAuthentication(IntentSender, RemoteViews)} and
+ * {@link Dataset.Builder#setAuthentication(IntentSender)}.
+ *
+ * <p>It is recommended that you encrypt only the sensitive data but leave the labels unencrypted
* which would allow you to provide a dataset presentation views with labels and if the user
* chooses one of them challenge the user to authenticate. For example, if the user has a
* home and a work address the Home and Work labels could be stored unencrypted as they don't
@@ -158,14 +161,45 @@
public final class FillResponse implements Parcelable {
private final ArrayList<Dataset> mDatasets;
- private final ArraySet<AutoFillId> mSavableIds;
+ private final SaveInfo mSaveInfo;
private final Bundle mExtras;
private final RemoteViews mPresentation;
private final IntentSender mAuthentication;
private FillResponse(@NonNull Builder builder) {
mDatasets = builder.mDatasets;
- mSavableIds = builder.mSavableIds;
+
+ if (false) {
+ // TODO(b/33197203, 35727295): this is how mSaveInfo will be set once we don't support
+ // FillResponse.setSavableIds()
+ mSaveInfo = builder.mSaveInfo;
+ if (mSaveInfo != null) {
+ mSaveInfo.addSavableIds(mDatasets);
+ if (mSaveInfo.getSavableIds() == null) {
+ throw new IllegalArgumentException(
+ "need to provide at least one savable id on SaveInfo");
+ }
+ }
+ } else {
+ // Temporary workaround to support FillResponse.setSavableIds()
+ SaveInfo saveInfo = builder.mSaveInfoBuilder != null ? builder.mSaveInfoBuilder.build()
+ : builder.mSaveInfo;
+
+ // Handle the the case where service didn't call setSavableIds() because it would
+ // contain just the ids from the datasets.
+ if (saveInfo == null && mDatasets != null) {
+ saveInfo = new SaveInfo.Builder(SaveInfo.SAVE_DATA_TYPE_GENERIC).build();
+ }
+ if (saveInfo != null) {
+ saveInfo.addSavableIds(mDatasets);
+ if (saveInfo.getSavableIds() == null) {
+ throw new IllegalArgumentException(
+ "need to provide at least one savable id on SaveInfo");
+ }
+ }
+ mSaveInfo = saveInfo;
+ }
+
mExtras = builder.mExtras;
mPresentation = builder.mPresentation;
mAuthentication = builder.mAuthentication;
@@ -182,8 +216,8 @@
}
/** @hide */
- public @Nullable ArraySet<AutoFillId> getSavableIds() {
- return mSavableIds;
+ public @Nullable SaveInfo getSaveInfo() {
+ return mSaveInfo;
}
/** @hide */
@@ -202,7 +236,10 @@
*/
public static final class Builder {
private ArrayList<Dataset> mDatasets;
- private ArraySet<AutoFillId> mSavableIds;
+ // TODO(b/33197203, 35727295): temporary builder use by deprecated addSavableIds() method,
+ // should be removed once that method is gone
+ private SaveInfo.Builder mSaveInfoBuilder;
+ private SaveInfo mSaveInfo;
private Bundle mExtras;
private RemoteViews mPresentation;
private IntentSender mAuthentication;
@@ -276,41 +313,37 @@
if (!mDatasets.add(dataset)) {
return this;
}
- if (dataset.getFieldIds() != null) {
- final int fieldCount = dataset.getFieldIds().size();
- for (int i = 0; i < fieldCount; i++) {
- final AutoFillId id = dataset.getFieldIds().get(i);
- if (mSavableIds == null) {
- mSavableIds = new ArraySet<>();
- }
- mSavableIds.add(id);
- }
+ return this;
+ }
+
+ /** @hide */
+ // TODO(b/33197203, 35727295): remove when not used by clients
+ public @NonNull Builder addSavableFields(@Nullable AutoFillId... ids) {
+ throwIfDestroyed();
+ if (mSaveInfo != null) {
+ throw new IllegalStateException("setSaveInfo() already called");
}
+ if (mSaveInfoBuilder == null) {
+ mSaveInfoBuilder = new SaveInfo.Builder(SaveInfo.SAVE_DATA_TYPE_GENERIC);
+ }
+ mSaveInfoBuilder.addSavableIds(ids);
+
return this;
}
/**
- * Adds ids of additional fields that the service would be interested to save (through
- * {@link AutoFillService#onSaveRequest(
- * android.app.assist.AssistStructure, Bundle, SaveCallback)})
- * but were not indirectly set through {@link #addDataset(Dataset)}.
+ * Sets the {@link SaveInfo} associated with this response.
*
- * @param ids The savable ids.
+ * <p>See {@link FillResponse} for more info.
+ *
* @return This builder.
- *
- * @see FillResponse
*/
- public @NonNull Builder addSavableFields(@Nullable AutoFillId... ids) {
+ public @NonNull Builder setSaveInfo(@NonNull SaveInfo saveInfo) {
throwIfDestroyed();
- if (ids == null) {
- return this;
+ if (mSaveInfoBuilder != null) {
+ throw new IllegalStateException("addSavableFields() already called");
}
- for (AutoFillId id : ids) {
- if (mSavableIds == null) {
- mSavableIds = new ArraySet<>();
- }
- mSavableIds.add(id);
- }
+ mSaveInfo = saveInfo;
return this;
}
@@ -340,9 +373,11 @@
*/
public FillResponse build() {
throwIfDestroyed();
- if (mAuthentication == null && mDatasets == null && mSavableIds == null) {
- throw new IllegalArgumentException("need to provide at least one"
- + " data set or savable ids or an authentication with a presentation");
+
+ if (mAuthentication == null && mDatasets == null && mSaveInfoBuilder == null
+ && mSaveInfo == null) {
+ throw new IllegalArgumentException("need to provide at least one DataSet or a "
+ + "SaveInfo or an authentication with a presentation");
}
mDestroyed = true;
return new FillResponse(this);
@@ -361,9 +396,10 @@
@Override
public String toString() {
if (!DEBUG) return super.toString();
+
return new StringBuilder(
"FillResponse: [datasets=").append(mDatasets)
- .append(", savableIds=").append(mSavableIds)
+ .append(", saveInfo=").append(mSaveInfo)
.append(", hasExtras=").append(mExtras != null)
.append(", hasPresentation=").append(mPresentation != null)
.append(", hasAuthentication=").append(mAuthentication != null)
@@ -382,7 +418,7 @@
@Override
public void writeToParcel(Parcel parcel, int flags) {
parcel.writeTypedArrayList(mDatasets, flags);
- parcel.writeTypedArraySet(mSavableIds, flags);
+ parcel.writeParcelable(mSaveInfo, flags);
parcel.writeParcelable(mExtras, flags);
parcel.writeParcelable(mAuthentication, flags);
parcel.writeParcelable(mPresentation, flags);
@@ -401,11 +437,7 @@
for (int i = 0; i < datasetCount; i++) {
builder.addDataset(datasets.get(i));
}
- final ArraySet<AutoFillId> fillIds = parcel.readTypedArraySet(null);
- final int fillIdCount = (fillIds != null) ? fillIds.size() : 0;
- for (int i = 0; i < fillIdCount; i++) {
- builder.addSavableFields(fillIds.valueAt(i));
- }
+ builder.setSaveInfo(parcel.readParcelable(null));
builder.setExtras(parcel.readParcelable(null));
builder.setAuthentication(parcel.readParcelable(null),
parcel.readParcelable(null));
diff --git a/core/java/android/net/NetworkScorerAppManager.aidl b/core/java/android/service/autofill/SaveInfo.aidl
similarity index 88%
copy from core/java/android/net/NetworkScorerAppManager.aidl
copy to core/java/android/service/autofill/SaveInfo.aidl
index d968343..8cda608 100644
--- a/core/java/android/net/NetworkScorerAppManager.aidl
+++ b/core/java/android/service/autofill/SaveInfo.aidl
@@ -14,6 +14,6 @@
* limitations under the License.
*/
-package android.net;
+package android.service.autofill;
-parcelable NetworkScorerAppManager.NetworkScorerAppData;
+parcelable SaveInfo;
diff --git a/core/java/android/service/autofill/SaveInfo.java b/core/java/android/service/autofill/SaveInfo.java
new file mode 100644
index 0000000..096f28b
--- /dev/null
+++ b/core/java/android/service/autofill/SaveInfo.java
@@ -0,0 +1,263 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.service.autofill;
+
+import static android.view.autofill.Helper.DEBUG;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.Bundle;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.util.ArraySet;
+import android.view.autofill.AutoFillId;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
+
+/**
+ * Information used to indicate that a service is interested on saving the user-inputed data for
+ * future use.
+ *
+ * <p>A {@link SaveInfo} is always associated with a {@link FillResponse}.
+ *
+ * <p>A {@link SaveInfo} must define the type it represents, and contain at least one
+ * {@code savableId}. A {@code savableId} is the {@link AutoFillId} of a view the service is
+ * interested to save in a {@code onSaveRequest()}; the ids of all {@link Dataset} present in the
+ * {@link FillResponse} associated with this {@link SaveInfo} are already marked as savable,
+ * but additional ids can be added through {@link Builder#addSavableIds(AutoFillId...)}.
+ *
+ * <p>See {@link AutoFillService#onSaveRequest(android.app.assist.AssistStructure, Bundle,
+ * SaveCallback)} and {@link FillResponse} for more info.
+ */
+public final class SaveInfo implements Parcelable {
+
+ /**
+ * Type used on when the service can save the contents of an activity, but cannot describe what
+ * the content is for.
+ */
+ public static final int SAVE_DATA_TYPE_GENERIC = 0;
+
+ /**
+ * Type used when the {@link FillResponse} represents user credentials that have a password.
+ */
+ public static final int SAVE_DATA_TYPE_PASSWORD = 1;
+
+
+ /**
+ * Type used on when the {@link FillResponse} represents a physical address (such as street,
+ * city, state, etc).
+ */
+ public static final int SAVE_DATA_TYPE_ADDRESS = 2;
+
+ /**
+ * Type used when the {@link FillResponse} represents a credit card.
+ */
+ public static final int SAVE_DATA_TYPE_CREDIT_CARD = 3;
+
+ private final @SaveDataType int mType;
+ private ArraySet<AutoFillId> mSavableIds;
+ private final CharSequence mDescription;
+
+ /** @hide */
+ @IntDef({
+ SAVE_DATA_TYPE_GENERIC,
+ SAVE_DATA_TYPE_PASSWORD,
+ SAVE_DATA_TYPE_ADDRESS,
+ SAVE_DATA_TYPE_CREDIT_CARD
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface SaveDataType {
+ }
+
+ private SaveInfo(Builder builder) {
+ mType = builder.mType;
+ mSavableIds = builder.mSavableIds;
+ mDescription = builder.mDescription;
+ }
+
+ /** @hide */
+ public @Nullable ArraySet<AutoFillId> getSavableIds() {
+ return mSavableIds;
+ }
+
+ /** @hide */
+ public int getType() {
+ return mType;
+ }
+
+ /** @hide */
+ public CharSequence getDescription() {
+ return mDescription;
+ }
+
+ /** @hide */
+ public void addSavableIds(@Nullable ArrayList<Dataset> datasets) {
+ if (datasets != null) {
+ for (Dataset dataset : datasets) {
+ final ArrayList<AutoFillId> ids = dataset.getFieldIds();
+ if (ids != null) {
+ final int fieldCount = ids.size();
+ for (int i = 0; i < fieldCount; i++) {
+ final AutoFillId id = ids.get(i);
+ if (mSavableIds == null) {
+ mSavableIds = new ArraySet<>();
+ }
+ mSavableIds.add(id);
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * A builder for {@link SaveInfo} objects.
+ */
+ public static final class Builder {
+
+ private final @SaveDataType int mType;
+ private ArraySet<AutoFillId> mSavableIds;
+ private CharSequence mDescription;
+ private boolean mDestroyed;
+
+ /**
+ * Creates a new builder.
+ *
+ * @param type the type of information the associated {@link FillResponse} represents. Must
+ * be {@link SaveInfo#SAVE_DATA_TYPE_GENERIC}, {@link SaveInfo#SAVE_DATA_TYPE_PASSWORD},
+ * {@link SaveInfo#SAVE_DATA_TYPE_ADDRESS}, or {@link SaveInfo#SAVE_DATA_TYPE_CREDIT_CARD};
+ * otherwise it will assume {@link SaveInfo#SAVE_DATA_TYPE_GENERIC}.
+ */
+ public Builder(@SaveDataType int type) {
+ switch (type) {
+ case SAVE_DATA_TYPE_PASSWORD:
+ case SAVE_DATA_TYPE_ADDRESS:
+ case SAVE_DATA_TYPE_CREDIT_CARD:
+ mType = type;
+ break;
+ default:
+ mType = SAVE_DATA_TYPE_GENERIC;
+ }
+ }
+
+ /**
+ * Adds ids of additional views the service would be interested to save, but were not
+ * indirectly set through {@link FillResponse.Builder#addDataset(Dataset)}.
+ *
+ * @param ids The savable ids.
+ * @return This builder.
+ *
+ * @see FillResponse
+ */
+ public @NonNull Builder addSavableIds(@Nullable AutoFillId... ids) {
+ throwIfDestroyed();
+
+ if (ids == null) {
+ return this;
+ }
+ for (AutoFillId id : ids) {
+ if (mSavableIds == null) {
+ mSavableIds = new ArraySet<>();
+ }
+ mSavableIds.add(id);
+ }
+ return this;
+ }
+
+ /**
+ * Sets an optional description to be shown in the UI when the user is asked to save.
+ *
+ * <p>Typically, it describes how the data will be stored by the service, so it can help
+ * users to decide whether they can trust the service to save their data.
+ *
+ * @param description a succint description.
+ * @return This Builder.
+ */
+ public @NonNull Builder setDescription(@Nullable CharSequence description) {
+ mDescription = description;
+ return this;
+ }
+
+ /**
+ * Builds a new {@link SaveInfo} instance.
+ */
+ public SaveInfo build() {
+ throwIfDestroyed();
+ mDestroyed = true;
+ return new SaveInfo(this);
+ }
+
+ private void throwIfDestroyed() {
+ if (mDestroyed) {
+ throw new IllegalStateException("Already called #build()");
+ }
+ }
+
+ }
+
+ /////////////////////////////////////
+ // Object "contract" methods. //
+ /////////////////////////////////////
+ @Override
+ public String toString() {
+ if (!DEBUG) return super.toString();
+
+ return new StringBuilder("SaveInfo: [type=").append(mType)
+ .append(", savableIds=").append(mSavableIds)
+ .append("]").toString();
+ }
+
+ /////////////////////////////////////
+ // Parcelable "contract" methods. //
+ /////////////////////////////////////
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel parcel, int flags) {
+ parcel.writeInt(mType);
+ parcel.writeTypedArraySet(mSavableIds, flags);
+ parcel.writeCharSequence(mDescription);
+ }
+
+ public static final Parcelable.Creator<SaveInfo> CREATOR = new Parcelable.Creator<SaveInfo>() {
+ @Override
+ public SaveInfo createFromParcel(Parcel parcel) {
+ // Always go through the builder to ensure the data ingested by
+ // the system obeys the contract of the builder to avoid attacks
+ // using specially crafted parcels.
+ final Builder builder = new Builder(parcel.readInt());
+ final ArraySet<AutoFillId> savableIds = parcel.readTypedArraySet(null);
+ final int savableIdsCount = (savableIds != null) ? savableIds.size() : 0;
+ for (int i = 0; i < savableIdsCount; i++) {
+ builder.addSavableIds(savableIds.valueAt(i));
+ }
+ builder.setDescription(parcel.readCharSequence());
+ return builder.build();
+ }
+
+ @Override
+ public SaveInfo[] newArray(int size) {
+ return new SaveInfo[size];
+ }
+ };
+}
diff --git a/core/java/android/service/notification/ConditionProviderService.java b/core/java/android/service/notification/ConditionProviderService.java
index c8358a6..3e992ec 100644
--- a/core/java/android/service/notification/ConditionProviderService.java
+++ b/core/java/android/service/notification/ConditionProviderService.java
@@ -127,7 +127,7 @@
}
/**
- * Request that the provider be rebound, after a previous call to (@link requestUnbind).
+ * Request that the provider be rebound, after a previous call to (@link #requestUnbind).
*
* <p>This method will fail for providers that have not been granted the permission by the user.
*/
diff --git a/core/java/android/service/notification/NotificationListenerService.java b/core/java/android/service/notification/NotificationListenerService.java
index 5f7ff67..70e0461 100644
--- a/core/java/android/service/notification/NotificationListenerService.java
+++ b/core/java/android/service/notification/NotificationListenerService.java
@@ -148,7 +148,7 @@
// Notification cancellation reasons
- /** Notification was canceled by the status bar reporting a click. */
+ /** Notification was canceled by the status bar reporting a notification click. */
public static final int REASON_DELEGATE_CLICK = 1;
/** Notification was canceled by the status bar reporting a user dismissal. */
public static final int REASON_DELEGATE_CANCEL = 2;
@@ -547,20 +547,20 @@
* Inform the notification manager about snoozing a specific notification.
* <p>
* Use this if your listener has a user interface that allows the user to snooze a notification
- * until a given time. It should be called after the user snoozes a single notification using
+ * for a time. It should be called after the user snoozes a single notification using
* your UI; upon being informed, the notification manager will actually remove the notification
* and you will get an {@link #onNotificationRemoved(StatusBarNotification)} callback. When the
* snoozing period expires, you will get a
* {@link #onNotificationPosted(StatusBarNotification, RankingMap)} callback for the
* notification.
* @param key The key of the notification to snooze
- * @param snoozeUntil A time in the future, in milliseconds.
+ * @param durationMs A duration to snooze the notification for, in milliseconds.
*/
- public final void snoozeNotification(String key, long snoozeUntil) {
+ public final void snoozeNotification(String key, long durationMs) {
if (!isBound()) return;
try {
getNotificationInterface().snoozeNotificationUntilFromListener(
- mWrapper, key, snoozeUntil);
+ mWrapper, key, durationMs);
} catch (android.os.RemoteException ex) {
Log.v(TAG, "Unable to contact notification manager", ex);
}
@@ -636,7 +636,7 @@
* <p>The service should wait for the {@link #onListenerConnected()} event
* before performing this operation.
*
- * @return An array of active notifications, sorted in natural order.
+ * @return An array of snoozed notifications, sorted in natural order.
*/
public final StatusBarNotification[] getSnoozedNotifications() {
try {
diff --git a/core/java/android/service/notification/StatusBarNotification.java b/core/java/android/service/notification/StatusBarNotification.java
index 85bccf7..6a24aa4 100644
--- a/core/java/android/service/notification/StatusBarNotification.java
+++ b/core/java/android/service/notification/StatusBarNotification.java
@@ -67,6 +67,9 @@
this.groupKey = groupKey();
}
+ /**
+ * @deprecated Non-system apps should not need to create StatusBarNotifications.
+ */
@Deprecated
public StatusBarNotification(String pkg, String opPkg, int id, String tag, int uid,
int initialPid, int score, Notification notification, UserHandle user,
diff --git a/core/java/android/text/Hyphenator.java b/core/java/android/text/Hyphenator.java
index 356804e..80ec03e 100644
--- a/core/java/android/text/Hyphenator.java
+++ b/core/java/android/text/Hyphenator.java
@@ -189,7 +189,9 @@
// TODO: replace this with a discovery-based method that looks into /system/usr/hyphen-data
String[] availableLanguages = {
"as",
+ "bg",
"bn",
+ "cu",
"cy",
"da",
"de-1901", "de-1996", "de-CH-1901",
diff --git a/core/java/android/transition/Fade.java b/core/java/android/transition/Fade.java
index b0de711..38b89dc 100644
--- a/core/java/android/transition/Fade.java
+++ b/core/java/android/transition/Fade.java
@@ -103,6 +103,7 @@
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.Fade);
int fadingMode = a.getInt(R.styleable.Fade_fadingMode, getMode());
setMode(fadingMode);
+ a.recycle();
}
@Override
diff --git a/core/java/android/transition/TransitionInflater.java b/core/java/android/transition/TransitionInflater.java
index 4c5a717..0cc981e 100644
--- a/core/java/android/transition/TransitionInflater.java
+++ b/core/java/android/transition/TransitionInflater.java
@@ -276,9 +276,11 @@
transition.addTarget(clazz);
}
} catch (ClassNotFoundException e) {
+ a.recycle();
throw new RuntimeException("Could not create " + className, e);
}
}
+ a.recycle();
} else {
throw new RuntimeException("Unknown scene name: " + parser.getName());
}
diff --git a/core/java/android/util/Half.java b/core/java/android/util/Half.java
index e4f8dd1..84c2e83 100644
--- a/core/java/android/util/Half.java
+++ b/core/java/android/util/Half.java
@@ -17,9 +17,13 @@
package android.util;
import android.annotation.HalfFloat;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+
+import sun.misc.FloatingDecimal;
/**
- * <p>Half is a utility class to manipulate half-precision 16-bit
+ * <p>The {@code Half} class is a wrapper and a utility class to manipulate half-precision 16-bit
* <a href="https://en.wikipedia.org/wiki/Half-precision_floating-point_format">IEEE 754</a>
* floating point data types (also called fp16 or binary16). A half-precision float can be
* created from or converted to single-precision floats, and is stored in a short data type.
@@ -88,7 +92,7 @@
* <p>This table shows that numbers higher than 1024 lose all fractional precision.</p>
*/
@SuppressWarnings("SimplifiableIfStatement")
-public final class Half {
+public final class Half extends Number implements Comparable<Half> {
/**
* The number of bits used to represent a half-precision float value.
*/
@@ -164,7 +168,332 @@
private static final int FP32_DENORMAL_MAGIC = 126 << 23;
private static final float FP32_DENORMAL_FLOAT = Float.intBitsToFloat(FP32_DENORMAL_MAGIC);
- private Half() {
+ private final @HalfFloat short mValue;
+
+ /**
+ * Constructs a newly allocated {@code Half} object that represents the
+ * half-precision float type argument.
+ *
+ * @param value The value to be represented by the {@code Half}
+ */
+ public Half(@HalfFloat short value) {
+ mValue = value;
+ }
+
+ /**
+ * Constructs a newly allocated {@code Half} object that represents the
+ * argument converted to a half-precision float.
+ *
+ * @param value The value to be represented by the {@code Half}
+ *
+ * @see #toHalf(float)
+ */
+ public Half(float value) {
+ mValue = toHalf(value);
+ }
+
+ /**
+ * Constructs a newly allocated {@code Half} object that
+ * represents the argument converted to a half-precision float.
+ *
+ * @param value The value to be represented by the {@code Half}
+ *
+ * @see #toHalf(float)
+ */
+ public Half(double value) {
+ mValue = toHalf((float) value);
+ }
+
+ /**
+ * <p>Constructs a newly allocated {@code Half} object that represents the
+ * half-precision float value represented by the string.
+ * The string is converted to a half-precision float value as if by the
+ * {@link #valueOf(String)} method.</p>
+ *
+ * <p>Calling this constructor is equivalent to calling:</p>
+ * <pre>
+ * new Half(Float.parseFloat(value))
+ * </pre>
+ *
+ * @param value A string to be converted to a {@code Half}
+ * @throws NumberFormatException if the string does not contain a parsable number
+ *
+ * @see Float#valueOf(java.lang.String)
+ * @see #toHalf(float)
+ */
+ public Half(@NonNull String value) throws NumberFormatException {
+ mValue = toHalf(Float.parseFloat(value));
+ }
+
+ /**
+ * Returns the half-precision value of this {@code Half} as a {@code short}
+ * containing the bit representation described in {@link Half}.
+ *
+ * @return The half-precision float value represented by this object
+ */
+ public @HalfFloat short halfValue() {
+ return mValue;
+ }
+
+ /**
+ * Returns the value of this {@code Half} as a {@code byte} after
+ * a narrowing primitive conversion.
+ *
+ * @return The half-precision float value represented by this object
+ * converted to type {@code byte}
+ */
+ @Override
+ public byte byteValue() {
+ return (byte) toFloat(mValue);
+ }
+
+ /**
+ * Returns the value of this {@code Half} as a {@code short} after
+ * a narrowing primitive conversion.
+ *
+ * @return The half-precision float value represented by this object
+ * converted to type {@code short}
+ */
+ @Override
+ public short shortValue() {
+ return (short) toFloat(mValue);
+ }
+
+ /**
+ * Returns the value of this {@code Half} as a {@code int} after
+ * a narrowing primitive conversion.
+ *
+ * @return The half-precision float value represented by this object
+ * converted to type {@code int}
+ */
+ @Override
+ public int intValue() {
+ return (int) toFloat(mValue);
+ }
+
+ /**
+ * Returns the value of this {@code Half} as a {@code long} after
+ * a narrowing primitive conversion.
+ *
+ * @return The half-precision float value represented by this object
+ * converted to type {@code long}
+ */
+ @Override
+ public long longValue() {
+ return (long) toFloat(mValue);
+ }
+
+ /**
+ * Returns the value of this {@code Half} as a {@code float} after
+ * a widening primitive conversion.
+ *
+ * @return The half-precision float value represented by this object
+ * converted to type {@code float}
+ */
+ @Override
+ public float floatValue() {
+ return toFloat(mValue);
+ }
+
+ /**
+ * Returns the value of this {@code Half} as a {@code double} after
+ * a widening primitive conversion.
+ *
+ * @return The half-precision float value represented by this object
+ * converted to type {@code double}
+ */
+ @Override
+ public double doubleValue() {
+ return toFloat(mValue);
+ }
+
+ /**
+ * Returns true if this {@code Half} value represents a Not-a-Number,
+ * false otherwise.
+ *
+ * @return True if the value is a NaN, false otherwise
+ */
+ public boolean isNaN() {
+ return isNaN(mValue);
+ }
+
+ /**
+ * Compares this object against the specified object. The result is {@code true}
+ * if and only if the argument is not {@code null} and is a {@code Half} object
+ * that represents the same half-precision value as the this object. Two
+ * half-precision values are considered to be the same if and only if the method
+ * {@link #halfToIntBits(short)} returns an identical {@code int} value for both.
+ *
+ * @param o The object to compare
+ * @return True if the objects are the same, false otherwise
+ *
+ * @see #halfToIntBits(short)
+ */
+ @Override
+ public boolean equals(@Nullable Object o) {
+ return (o instanceof Half) &&
+ (halfToIntBits(((Half) o).mValue) == halfToIntBits(mValue));
+ }
+
+ /**
+ * Returns a hash code for this {@code Half} object. The result is the
+ * integer bit representation, exactly as produced by the method
+ * {@link #halfToIntBits(short)}, of the primitive half-precision float
+ * value represented by this {@code Half} object.
+ *
+ * @return A hash code value for this object
+ */
+ @Override
+ public int hashCode() {
+ return hashCode(mValue);
+ }
+
+ /**
+ * Returns a string representation of the specified half-precision
+ * float value. See {@link #toString(short)} for more information.
+ *
+ * @return A string representation of this {@code Half} object
+ */
+ @NonNull
+ @Override
+ public String toString() {
+ return toString(mValue);
+ }
+
+ /**
+ * <p>Compares the two specified half-precision float values. The following
+ * conditions apply during the comparison:</p>
+ *
+ * <ul>
+ * <li>{@link #NaN} is considered by this method to be equal to itself and greater
+ * than all other half-precision float values (including {@code #POSITIVE_INFINITY})</li>
+ * <li>{@link #POSITIVE_ZERO} is considered by this method to be greater than
+ * {@link #NEGATIVE_ZERO}.</li>
+ * </ul>
+ *
+ * @param h The half-precision float value to compare to the half-precision value
+ * represented by this {@code Half} object
+ *
+ * @return The value {@code 0} if {@code x} is numerically equal to {@code y}; a
+ * value less than {@code 0} if {@code x} is numerically less than {@code y};
+ * and a value greater than {@code 0} if {@code x} is numerically greater
+ * than {@code y}
+ */
+ @Override
+ public int compareTo(@NonNull Half h) {
+ return compare(mValue, h.mValue);
+ }
+
+ /**
+ * Returns a hash code for a half-precision float value.
+ *
+ * @param h The value to hash
+ *
+ * @return A hash code value for a half-precision float value
+ */
+ public static int hashCode(@HalfFloat short h) {
+ return halfToIntBits(h);
+ }
+
+ /**
+ * <p>Compares the two specified half-precision float values. The following
+ * conditions apply during the comparison:</p>
+ *
+ * <ul>
+ * <li>{@link #NaN} is considered by this method to be equal to itself and greater
+ * than all other half-precision float values (including {@code #POSITIVE_INFINITY})</li>
+ * <li>{@link #POSITIVE_ZERO} is considered by this method to be greater than
+ * {@link #NEGATIVE_ZERO}.</li>
+ * </ul>
+ *
+ * @param x The first half-precision float value to compare.
+ * @param y The second half-precision float value to compare
+ *
+ * @return The value {@code 0} if {@code x} is numerically equal to {@code y}, a
+ * value less than {@code 0} if {@code x} is numerically less than {@code y},
+ * and a value greater than {@code 0} if {@code x} is numerically greater
+ * than {@code y}
+ */
+ public static int compare(@HalfFloat short x, @HalfFloat short y) {
+ if (less(x, y)) return -1;
+ if (greater(x, y)) return 1;
+
+ // Collapse NaNs, akin to halfToIntBits(), but we want to keep
+ // (signed) short value types to preserve the ordering of -0.0
+ // and +0.0
+ short xBits = (x & FP16_COMBINED) > FP16_EXPONENT_MAX ? NaN : x;
+ short yBits = (y & FP16_COMBINED) > FP16_EXPONENT_MAX ? NaN : y;
+
+ return (xBits == yBits ? 0 : (xBits < yBits ? -1 : 1));
+ }
+
+ /**
+ * <p>Returns a representation of the specified half-precision float value
+ * according to the bit layout described in {@link Half}.</p>
+ *
+ * <p>Similar to {@link #halfToIntBits(short)}, this method collapses all
+ * possible Not-a-Number values to a single canonical Not-a-Number value
+ * defined by {@link #NaN}.</p>
+ *
+ * @param h A half-precision float value
+ * @return The bits that represent the half-precision float value
+ *
+ * @see #halfToIntBits(short)
+ */
+ public static @HalfFloat short halfToShortBits(@HalfFloat short h) {
+ return (h & FP16_COMBINED) > FP16_EXPONENT_MAX ? NaN : h;
+ }
+
+ /**
+ * <p>Returns a representation of the specified half-precision float value
+ * according to the bit layout described in {@link Half}.</p>
+ *
+ * <p>Unlike {@link #halfToRawIntBits(short)}, this method collapses all
+ * possible Not-a-Number values to a single canonical Not-a-Number value
+ * defined by {@link #NaN}.</p>
+ *
+ * @param h A half-precision float value
+ * @return The bits that represent the half-precision float value
+ *
+ * @see #halfToRawIntBits(short)
+ * @see #halfToShortBits(short)
+ * @see #intBitsToHalf(int)
+ */
+ public static int halfToIntBits(@HalfFloat short h) {
+ return (h & FP16_COMBINED) > FP16_EXPONENT_MAX ? NaN : h & 0xffff;
+ }
+
+ /**
+ * <p>Returns a representation of the specified half-precision float value
+ * according to the bit layout described in {@link Half}.</p>
+ *
+ * <p>The argument is considered to be a representation of a half-precision
+ * float value according to the bit layout described in {@link Half}. The 16
+ * most significant bits of the returned value are set to 0.</p>
+ *
+ * @param h A half-precision float value
+ * @return The bits that represent the half-precision float value
+ *
+ * @see #halfToIntBits(short)
+ * @see #intBitsToHalf(int)
+ */
+ public static int halfToRawIntBits(@HalfFloat short h) {
+ return h & 0xffff;
+ }
+
+ /**
+ * <p>Returns the half-precision float value corresponding to a given
+ * bit representation.</p>
+ *
+ * <p>The argument is considered to be a representation of a half-precision
+ * float value according to the bit layout described in {@link Half}. The 16
+ * most significant bits of the argument are ignored.</p>
+ *
+ * @param bits An integer
+ * @return The half-precision float value with the same bit pattern
+ */
+ public static @HalfFloat short intBitsToHalf(int bits) {
+ return (short) (bits & 0xffff);
}
/**
@@ -509,7 +838,7 @@
* infinity, false otherwise.
*
* @param h A half-precision float value
- * @return true if the value is positive infinity or negative infinity,
+ * @return True if the value is positive infinity or negative infinity,
* false otherwise
*/
public static boolean isInfinite(@HalfFloat short h) {
@@ -521,7 +850,7 @@
* a Not-a-Number, false otherwise.
*
* @param h A half-precision float value
- * @return true if the value is a NaN, false otherwise
+ * @return True if the value is a NaN, false otherwise
*/
public static boolean isNaN(@HalfFloat short h) {
return (h & FP16_COMBINED) > FP16_EXPONENT_MAX;
@@ -535,7 +864,7 @@
* number, this method returns false.
*
* @param h A half-precision float value
- * @return true if the value is normalized, false otherwise
+ * @return True if the value is normalized, false otherwise
*/
public static boolean isNormalized(@HalfFloat short h) {
return (h & FP16_EXPONENT_MAX) != 0 && (h & FP16_EXPONENT_MAX) != FP16_EXPONENT_MAX;
@@ -608,7 +937,7 @@
* @return A half-precision float value
*/
@SuppressWarnings("StatementWithEmptyBody")
- public static @HalfFloat short valueOf(float f) {
+ public static @HalfFloat short toHalf(float f) {
int bits = Float.floatToRawIntBits(f);
int s = (bits >>> FP32_SIGN_SHIFT );
int e = (bits >>> FP32_EXPONENT_SHIFT) & FP32_EXPONENT_MASK;
@@ -650,6 +979,57 @@
}
/**
+ * Returns a {@code Half} instance representing the specified
+ * half-precision float value.
+ *
+ * @param h A half-precision float value
+ * @return a {@code Half} instance representing {@code h}
+ */
+ public static @NonNull Half valueOf(@HalfFloat short h) {
+ return new Half(h);
+ }
+
+ /**
+ * Returns a {@code Half} instance representing the specified float value.
+ *
+ * @param f A float value
+ * @return a {@code Half} instance representing {@code f}
+ */
+ public static @NonNull Half valueOf(float f) {
+ return new Half(f);
+ }
+
+ /**
+ * Returns a {@code Half} instance representing the specified string value.
+ * Calling this method is equivalent to calling
+ * <code>toHalf(Float.parseString(h))</code>. See {@link Float#valueOf(String)}
+ * for more information on the format of the string representation.
+ *
+ * @param s The string to be parsed
+ * @return a {@code Half} instance representing {@code h}
+ * @throws NumberFormatException if the string does not contain a parsable
+ * half-precision float value
+ */
+ public static @NonNull Half valueOf(@NonNull String s) {
+ return new Half(s);
+ }
+
+ /**
+ * Returns the half-precision float value represented by the specified string.
+ * Calling this method is equivalent to calling
+ * <code>toHalf(Float.parseString(h))</code>. See {@link Float#valueOf(String)}
+ * for more information on the format of the string representation.
+ *
+ * @param s The string to be parsed
+ * @return A half-precision float value represented by the string
+ * @throws NumberFormatException if the string does not contain a parsable
+ * half-precision float value
+ */
+ public static @HalfFloat short parseHalf(@NonNull String s) throws NumberFormatException {
+ return toHalf(FloatingDecimal.parseFloat(s));
+ }
+
+ /**
* Returns a string representation of the specified half-precision
* float value. Calling this method is equivalent to calling
* <code>Float.toString(toFloat(h))</code>. See {@link Float#toString(float)}
@@ -658,6 +1038,7 @@
* @param h A half-precision float value
* @return A string representation of the specified value
*/
+ @NonNull
public static String toString(@HalfFloat short h) {
return Float.toString(toFloat(h));
}
@@ -688,6 +1069,7 @@
* @param h A half-precision float value
* @return A hexadecimal string representation of the specified value
*/
+ @NonNull
public static String toHexString(@HalfFloat short h) {
StringBuilder o = new StringBuilder();
diff --git a/core/java/android/view/Display.java b/core/java/android/view/Display.java
index 83b6a52..7ec7ba7 100644
--- a/core/java/android/view/Display.java
+++ b/core/java/android/view/Display.java
@@ -21,6 +21,7 @@
import android.annotation.IntDef;
import android.annotation.RequiresPermission;
import android.content.res.CompatibilityInfo;
+import android.content.res.Resources;
import android.graphics.PixelFormat;
import android.graphics.Point;
import android.graphics.Rect;
@@ -71,7 +72,8 @@
private final String mAddress;
private final int mOwnerUid;
private final String mOwnerPackageName;
- private final DisplayAdjustments mDisplayAdjustments;
+ private final Resources mResources;
+ private DisplayAdjustments mDisplayAdjustments;
private DisplayInfo mDisplayInfo; // never null
private boolean mIsValid;
@@ -355,19 +357,39 @@
/**
* Internal method to create a display.
+ * The display created with this method will have a static {@link DisplayAdjustments} applied.
* Applications should use {@link android.view.WindowManager#getDefaultDisplay()}
* or {@link android.hardware.display.DisplayManager#getDisplay}
* to get a display object.
*
* @hide
*/
- public Display(DisplayManagerGlobal global,
- int displayId, DisplayInfo displayInfo /*not null*/,
+ public Display(DisplayManagerGlobal global, int displayId, /*@NotNull*/ DisplayInfo displayInfo,
DisplayAdjustments daj) {
+ this(global, displayId, displayInfo, daj, null /*res*/);
+ }
+
+ /**
+ * Internal method to create a display.
+ * The display created with this method will be adjusted based on the adjustments in the
+ * supplied {@link Resources}.
+ *
+ * @hide
+ */
+ public Display(DisplayManagerGlobal global, int displayId, /*@NotNull*/ DisplayInfo displayInfo,
+ Resources res) {
+ this(global, displayId, displayInfo, null /*daj*/, res);
+ }
+
+ private Display(DisplayManagerGlobal global, int displayId,
+ /*@NotNull*/ DisplayInfo displayInfo, DisplayAdjustments daj, Resources res) {
mGlobal = global;
mDisplayId = displayId;
mDisplayInfo = displayInfo;
- mDisplayAdjustments = new DisplayAdjustments(daj);
+ mResources = res;
+ mDisplayAdjustments = mResources != null
+ ? new DisplayAdjustments(mResources.getConfiguration())
+ : daj != null ? new DisplayAdjustments(daj) : null;
mIsValid = true;
// Cache properties that cannot change as long as the display is valid.
@@ -512,6 +534,13 @@
* @hide
*/
public DisplayAdjustments getDisplayAdjustments() {
+ if (mResources != null) {
+ final DisplayAdjustments currentAdjustements = mResources.getDisplayAdjustments();
+ if (!mDisplayAdjustments.equals(currentAdjustements)) {
+ mDisplayAdjustments = new DisplayAdjustments(currentAdjustements);
+ }
+ }
+
return mDisplayAdjustments;
}
@@ -562,7 +591,7 @@
public void getSize(Point outSize) {
synchronized (this) {
updateDisplayInfoLocked();
- mDisplayInfo.getAppMetrics(mTempMetrics, mDisplayAdjustments);
+ mDisplayInfo.getAppMetrics(mTempMetrics, getDisplayAdjustments());
outSize.x = mTempMetrics.widthPixels;
outSize.y = mTempMetrics.heightPixels;
}
@@ -577,7 +606,7 @@
public void getRectSize(Rect outSize) {
synchronized (this) {
updateDisplayInfoLocked();
- mDisplayInfo.getAppMetrics(mTempMetrics, mDisplayAdjustments);
+ mDisplayInfo.getAppMetrics(mTempMetrics, getDisplayAdjustments());
outSize.set(0, 0, mTempMetrics.widthPixels, mTempMetrics.heightPixels);
}
}
@@ -908,7 +937,7 @@
public void getMetrics(DisplayMetrics outMetrics) {
synchronized (this) {
updateDisplayInfoLocked();
- mDisplayInfo.getAppMetrics(outMetrics, mDisplayAdjustments);
+ mDisplayInfo.getAppMetrics(outMetrics, getDisplayAdjustments());
}
}
@@ -1017,7 +1046,7 @@
long now = SystemClock.uptimeMillis();
if (now > mLastCachedAppSizeUpdate + CACHED_APP_SIZE_DURATION_MILLIS) {
updateDisplayInfoLocked();
- mDisplayInfo.getAppMetrics(mTempMetrics, mDisplayAdjustments);
+ mDisplayInfo.getAppMetrics(mTempMetrics, getDisplayAdjustments());
mCachedAppWidthCompat = mTempMetrics.widthPixels;
mCachedAppHeightCompat = mTempMetrics.heightPixels;
mLastCachedAppSizeUpdate = now;
@@ -1029,7 +1058,7 @@
public String toString() {
synchronized (this) {
updateDisplayInfoLocked();
- mDisplayInfo.getAppMetrics(mTempMetrics, mDisplayAdjustments);
+ mDisplayInfo.getAppMetrics(mTempMetrics, getDisplayAdjustments());
return "Display id " + mDisplayId + ": " + mDisplayInfo
+ ", " + mTempMetrics + ", isValid=" + mIsValid;
}
diff --git a/core/java/android/view/FocusFinder.java b/core/java/android/view/FocusFinder.java
index 7fde8a6..ad06141 100644
--- a/core/java/android/view/FocusFinder.java
+++ b/core/java/android/view/FocusFinder.java
@@ -117,7 +117,7 @@
public View findNextKeyboardNavigationCluster(
@NonNull View root,
@Nullable View currentCluster,
- int direction) {
+ @View.FocusDirection int direction) {
View next = null;
final ArrayList<View> clusters = mTempList;
@@ -206,7 +206,7 @@
View root,
View currentCluster,
List<View> clusters,
- int direction) {
+ @View.FocusDirection int direction) {
final int count = clusters.size();
switch (direction) {
@@ -732,27 +732,17 @@
getRect(first, mFirstRect);
getRect(second, mSecondRect);
- if (mFirstRect.top < mSecondRect.top) {
- return -1;
- } else if (mFirstRect.top > mSecondRect.top) {
- return 1;
- } else if (mFirstRect.left < mSecondRect.left) {
- return mIsLayoutRtl ? 1 : -1;
- } else if (mFirstRect.left > mSecondRect.left) {
- return mIsLayoutRtl ? -1 : 1;
- } else if (mFirstRect.bottom < mSecondRect.bottom) {
- return -1;
- } else if (mFirstRect.bottom > mSecondRect.bottom) {
- return 1;
- } else if (mFirstRect.right < mSecondRect.right) {
- return mIsLayoutRtl ? 1 : -1;
- } else if (mFirstRect.right > mSecondRect.right) {
- return mIsLayoutRtl ? -1 : 1;
+ boolean overlapsVertically = (mFirstRect.top < mSecondRect.top
+ && mFirstRect.bottom > mSecondRect.top)
+ || (mFirstRect.top > mSecondRect.top
+ && mFirstRect.top < mSecondRect.bottom);
+ boolean alignedVertically = (mFirstRect.left > mSecondRect.left)
+ == (mFirstRect.right < mSecondRect.right);
+ if (overlapsVertically && !alignedVertically) {
+ int rtl = mIsLayoutRtl ? -1 : 1;
+ return rtl * (mFirstRect.left - mSecondRect.left);
} else {
- // The view are distinct but completely coincident so we consider
- // them equal for our purposes. Since the sort is stable, this
- // means that the views will retain their layout order relative to one another.
- return 0;
+ return mFirstRect.top - mSecondRect.top;
}
}
diff --git a/core/java/android/view/FrameMetrics.java b/core/java/android/view/FrameMetrics.java
index 92f0e8f..358a2d1 100644
--- a/core/java/android/view/FrameMetrics.java
+++ b/core/java/android/view/FrameMetrics.java
@@ -132,6 +132,26 @@
*/
public static final int FIRST_DRAW_FRAME = 9;
+ /**
+ * Metric identifier for the timestamp of the intended vsync for this frame.
+ * <p>
+ * The intended start point for the frame. If this value is different from
+ * {@link #VSYNC_TIMESTAMP}, there was work occurring on the UI thread that
+ * prevented it from responding to the vsync signal in a timely fashion.
+ * </p>
+ */
+ public static final int INTENDED_VSYNC_TIMESTAMP = 10;
+
+ /**
+ * Metric identifier for the timestamp of the actual vsync for this frame.
+ * <p>
+ * The time value that was used in all the vsync listeners and drawing for
+ * the frame (Choreographer frame callbacks, animations,
+ * {@link View#getDrawingTime()}, etc…)
+ * </p>
+ */
+ public static final int VSYNC_TIMESTAMP = 11;
+
private static final int FRAME_INFO_FLAG_FIRST_DRAW = 1 << 0;
/**
@@ -151,6 +171,8 @@
SWAP_BUFFERS_DURATION,
TOTAL_DURATION,
FIRST_DRAW_FRAME,
+ INTENDED_VSYNC_TIMESTAMP,
+ VSYNC_TIMESTAMP,
})
@Retention(RetentionPolicy.SOURCE)
public @interface Metric {}
@@ -261,7 +283,7 @@
* @return the value of the metric or -1 if it is not available.
*/
public long getMetric(@Metric int id) {
- if (id < UNKNOWN_DELAY_DURATION || id > FIRST_DRAW_FRAME) {
+ if (id < UNKNOWN_DELAY_DURATION || id > VSYNC_TIMESTAMP) {
return -1;
}
@@ -271,6 +293,10 @@
if (id == FIRST_DRAW_FRAME) {
return (mTimingData[Index.FLAGS] & FRAME_INFO_FLAG_FIRST_DRAW) != 0 ? 1 : 0;
+ } else if (id == INTENDED_VSYNC_TIMESTAMP) {
+ return mTimingData[Index.INTENDED_VSYNC];
+ } else if (id == VSYNC_TIMESTAMP) {
+ return mTimingData[Index.VSYNC];
}
int durationsIdx = 2 * id;
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index cf8da17..0ac16c1 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -95,6 +95,11 @@
IBinder displayToken, int mode);
private static native void nativeDeferTransactionUntil(long nativeObject,
IBinder handle, long frame);
+ private static native void nativeDeferTransactionUntilSurface(long nativeObject,
+ long surfaceObject, long frame);
+ private static native void nativeReparentChildren(long nativeObject,
+ IBinder handle);
+ private static native void nativeSeverChildren(long nativeObject);
private static native void nativeSetOverrideScalingMode(long nativeObject,
int scalingMode);
private static native IBinder nativeGetHandle(long nativeObject);
@@ -421,6 +426,18 @@
nativeDeferTransactionUntil(mNativeObject, handle, frame);
}
+ public void deferTransactionUntil(Surface barrier, long frame) {
+ nativeDeferTransactionUntilSurface(mNativeObject, barrier.mNativeObject, frame);
+ }
+
+ public void reparentChildren(IBinder newParentHandle) {
+ nativeReparentChildren(mNativeObject, newParentHandle);
+ }
+
+ public void detachChildren() {
+ nativeSeverChildren(mNativeObject);
+ }
+
public void setOverrideScalingMode(int scalingMode) {
checkNotReleased();
nativeSetOverrideScalingMode(mNativeObject, scalingMode);
@@ -508,9 +525,9 @@
nativeSetAlpha(mNativeObject, alpha);
}
- public void setMatrix(float dsdx, float dtdx, float dsdy, float dtdy) {
+ public void setMatrix(float dsdx, float dtdx, float dtdy, float dsdy) {
checkNotReleased();
- nativeSetMatrix(mNativeObject, dsdx, dtdx, dsdy, dtdy);
+ nativeSetMatrix(mNativeObject, dsdx, dtdx, dtdy, dsdy);
}
public void setWindowCrop(Rect crop) {
diff --git a/core/java/android/view/SurfaceSession.java b/core/java/android/view/SurfaceSession.java
index 3cf5af4..b5912bc 100644
--- a/core/java/android/view/SurfaceSession.java
+++ b/core/java/android/view/SurfaceSession.java
@@ -27,6 +27,7 @@
private long mNativeClient; // SurfaceComposerClient*
private static native long nativeCreate();
+ private static native long nativeCreateScoped(long surfacePtr);
private static native void nativeDestroy(long ptr);
private static native void nativeKill(long ptr);
@@ -35,6 +36,10 @@
mNativeClient = nativeCreate();
}
+ public SurfaceSession(Surface root) {
+ mNativeClient = nativeCreateScoped(root.mNativeObject);
+ }
+
/* no user serviceable parts here ... */
@Override
protected void finalize() throws Throwable {
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index d2577d4..6430633 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -16,6 +16,10 @@
package android.view;
+import static android.view.WindowManagerPolicy.APPLICATION_MEDIA_SUBLAYER;
+import static android.view.WindowManagerPolicy.APPLICATION_MEDIA_OVERLAY_SUBLAYER;
+import static android.view.WindowManagerPolicy.APPLICATION_PANEL_SUBLAYER;
+
import android.content.Context;
import android.content.res.CompatibilityInfo.Translator;
import android.content.res.Configuration;
@@ -26,16 +30,12 @@
import android.graphics.Region;
import android.os.Handler;
import android.os.Message;
-import android.os.ParcelFileDescriptor;
-import android.os.RemoteException;
import android.os.SystemClock;
import android.util.AttributeSet;
import android.util.Log;
-import com.android.internal.view.BaseIWindow;
import com.android.internal.view.SurfaceCallbackHelper;
-import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.concurrent.locks.ReentrantLock;
@@ -92,8 +92,8 @@
* positioned asynchronously.</p>
*/
public class SurfaceView extends View {
- static private final String TAG = "SurfaceView";
- static private final boolean DEBUG = false;
+ private static final String TAG = "SurfaceView";
+ private static final boolean DEBUG = false;
final ArrayList<SurfaceHolder.Callback> mCallbacks
= new ArrayList<SurfaceHolder.Callback>();
@@ -102,28 +102,23 @@
final ReentrantLock mSurfaceLock = new ReentrantLock();
final Surface mSurface = new Surface(); // Current surface in use
- final Surface mNewSurface = new Surface(); // New surface we are switching to
boolean mDrawingStopped = true;
+ // We use this to track if the application has produced a frame
+ // in to the Surface. Up until that point, we should be careful not to punch
+ // holes.
+ boolean mDrawFinished = false;
- final WindowManager.LayoutParams mLayout
- = new WindowManager.LayoutParams();
- IWindowSession mSession;
- MyWindow mWindow;
- final Rect mVisibleInsets = new Rect();
- final Rect mWinFrame = new Rect();
- final Rect mOverscanInsets = new Rect();
- final Rect mContentInsets = new Rect();
- final Rect mStableInsets = new Rect();
- final Rect mOutsets = new Rect();
- final Rect mBackdropFrame = new Rect();
+ final Rect mScreenRect = new Rect();
+ SurfaceSession mSurfaceSession;
+
+ SurfaceControl mSurfaceControl;
final Rect mTmpRect = new Rect();
final Configuration mConfiguration = new Configuration();
static final int KEEP_SCREEN_ON_MSG = 1;
- static final int GET_NEW_SURFACE_MSG = 2;
- static final int UPDATE_WINDOW_MSG = 3;
+ static final int DRAW_FINISHED_MSG = 2;
- int mWindowType = WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA;
+ int mSubLayer = APPLICATION_MEDIA_SUBLAYER;
boolean mIsCreating = false;
private volatile boolean mRtHandlingPositionUpdates = false;
@@ -135,11 +130,9 @@
case KEEP_SCREEN_ON_MSG: {
setKeepScreenOn(msg.arg1 != 0);
} break;
- case GET_NEW_SURFACE_MSG: {
- handleGetNewSurface();
- } break;
- case UPDATE_WINDOW_MSG: {
- updateWindow();
+ case DRAW_FINISHED_MSG: {
+ mDrawFinished = true;
+ invalidate();
} break;
}
}
@@ -149,7 +142,7 @@
= new ViewTreeObserver.OnScrollChangedListener() {
@Override
public void onScrollChanged() {
- updateWindow();
+ updateSurface();
}
};
@@ -159,13 +152,14 @@
public boolean onPreDraw() {
// reposition ourselves where the surface is
mHaveFrame = getWidth() > 0 && getHeight() > 0;
- updateWindow();
+ updateSurface();
return true;
}
};
boolean mRequestedVisible = false;
boolean mWindowVisibility = false;
+ boolean mLastWindowVisibility = false;
boolean mViewVisibility = false;
int mRequestedWidth = -1;
int mRequestedHeight = -1;
@@ -181,19 +175,17 @@
boolean mVisible = false;
int mWindowSpaceLeft = -1;
int mWindowSpaceTop = -1;
- int mWindowSpaceWidth = -1;
- int mWindowSpaceHeight = -1;
+ int mSurfaceWidth = -1;
+ int mSurfaceHeight = -1;
int mFormat = -1;
final Rect mSurfaceFrame = new Rect();
int mLastSurfaceWidth = -1, mLastSurfaceHeight = -1;
- boolean mUpdateWindowNeeded;
- boolean mReportDrawNeeded;
private Translator mTranslator;
- private int mWindowInsetLeft;
- private int mWindowInsetTop;
private boolean mGlobalListenersAdded;
+ private int mSurfaceFlags = SurfaceControl.HIDDEN;
+
public SurfaceView(Context context) {
this(context, null);
}
@@ -227,11 +219,8 @@
protected void onAttachedToWindow() {
super.onAttachedToWindow();
mParent.requestTransparentRegion(this);
- mSession = getWindowSession();
- mLayout.token = getWindowToken();
- mLayout.setTitle("SurfaceView - " + getViewRootImpl().getTitle());
- mLayout.packageName = mContext.getOpPackageName();
mViewVisibility = getVisibility() == VISIBLE;
+ mRequestedVisible = mViewVisibility && mWindowVisibility;
if (!mGlobalListenersAdded) {
ViewTreeObserver observer = getViewTreeObserver();
@@ -246,7 +235,7 @@
super.onWindowVisibilityChanged(visibility);
mWindowVisibility = visibility == VISIBLE;
mRequestedVisible = mWindowVisibility && mViewVisibility;
- updateWindow();
+ updateSurface();
}
@Override
@@ -264,7 +253,7 @@
requestLayout();
}
mRequestedVisible = newRequestedVisible;
- updateWindow();
+ updateSurface();
}
@Override
@@ -277,19 +266,14 @@
}
mRequestedVisible = false;
- updateWindow();
- mHaveFrame = false;
- if (mWindow != null) {
- try {
- mSession.remove(mWindow);
- } catch (RemoteException ex) {
- // Not much we can do here...
- }
- mWindow = null;
- }
- mSession = null;
- mLayout.token = null;
+ updateSurface();
+ if (mSurfaceControl != null) {
+ mSurfaceControl.destroy();
+ }
+ mSurfaceControl = null;
+
+ mHaveFrame = false;
super.onDetachedFromWindow();
}
@@ -308,13 +292,13 @@
@Override
protected boolean setFrame(int left, int top, int right, int bottom) {
boolean result = super.setFrame(left, top, right, bottom);
- updateWindow();
+ updateSurface();
return result;
}
@Override
public boolean gatherTransparentRegion(Region region) {
- if (mWindowType == WindowManager.LayoutParams.TYPE_APPLICATION_PANEL) {
+ if (isAboveParent()) {
return super.gatherTransparentRegion(region);
}
@@ -341,7 +325,7 @@
@Override
public void draw(Canvas canvas) {
- if (mWindowType != WindowManager.LayoutParams.TYPE_APPLICATION_PANEL) {
+ if (mDrawFinished && !isAboveParent()) {
// draw() is not called when SKIP_DRAW is set
if ((mPrivateFlags & PFLAG_SKIP_DRAW) == 0) {
// punch a whole in the view-hierarchy below us
@@ -353,8 +337,8 @@
@Override
protected void dispatchDraw(Canvas canvas) {
- if (mWindowType != WindowManager.LayoutParams.TYPE_APPLICATION_PANEL) {
- // if SKIP_DRAW is cleared, draw() has already punched a hole
+ if (mDrawFinished && !isAboveParent()) {
+ // draw() is not called when SKIP_DRAW is set
if ((mPrivateFlags & PFLAG_SKIP_DRAW) == PFLAG_SKIP_DRAW) {
// punch a whole in the view-hierarchy below us
canvas.drawColor(0, PorterDuff.Mode.CLEAR);
@@ -375,9 +359,8 @@
* <p>Calling this overrides any previous call to {@link #setZOrderOnTop}.
*/
public void setZOrderMediaOverlay(boolean isMediaOverlay) {
- mWindowType = isMediaOverlay
- ? WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA_OVERLAY
- : WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA;
+ mSubLayer = isMediaOverlay
+ ? APPLICATION_MEDIA_OVERLAY_SUBLAYER : APPLICATION_MEDIA_SUBLAYER;
}
/**
@@ -395,12 +378,9 @@
*/
public void setZOrderOnTop(boolean onTop) {
if (onTop) {
- mWindowType = WindowManager.LayoutParams.TYPE_APPLICATION_PANEL;
- // ensures the surface is placed below the IME
- mLayout.flags |= WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
+ mSubLayer = APPLICATION_PANEL_SUBLAYER;
} else {
- mWindowType = WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA;
- mLayout.flags &= ~WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
+ mSubLayer = APPLICATION_MEDIA_SUBLAYER;
}
}
@@ -418,31 +398,23 @@
*/
public void setSecure(boolean isSecure) {
if (isSecure) {
- mLayout.flags |= WindowManager.LayoutParams.FLAG_SECURE;
+ mSurfaceFlags |= SurfaceControl.SECURE;
} else {
- mLayout.flags &= ~WindowManager.LayoutParams.FLAG_SECURE;
+ mSurfaceFlags &= ~SurfaceControl.SECURE;
}
}
- /**
- * Hack to allow special layering of windows. The type is one of the
- * types in WindowManager.LayoutParams. This is a hack so:
- * @hide
- */
- public void setWindowType(int type) {
- mWindowType = type;
- }
-
/** @hide */
- protected void updateWindow() {
+ protected void updateSurface() {
if (!mHaveFrame) {
return;
}
ViewRootImpl viewRoot = getViewRootImpl();
- if (viewRoot != null) {
- mTranslator = viewRoot.mTranslator;
+ if (viewRoot == null || viewRoot.mSurface == null || !viewRoot.mSurface.isValid()) {
+ return;
}
+ mTranslator = viewRoot.mTranslator;
if (mTranslator != null) {
mSurface.setCompatibilityTranslator(mTranslator);
}
@@ -452,17 +424,15 @@
int myHeight = mRequestedHeight;
if (myHeight <= 0) myHeight = getHeight();
- final boolean creating = mWindow == null;
final boolean formatChanged = mFormat != mRequestedFormat;
- final boolean sizeChanged = mWindowSpaceWidth != myWidth || mWindowSpaceHeight != myHeight;
+ final boolean creating = (mSurfaceControl == null || formatChanged)
+ && mRequestedVisible;
+ final boolean sizeChanged = mSurfaceWidth != myWidth || mSurfaceHeight != myHeight;
final boolean visibleChanged = mVisible != mRequestedVisible;
- final boolean layoutSizeChanged = getWidth() != mLayout.width
- || getHeight() != mLayout.height;
-
+ final boolean windowVisibleChanged = mWindowVisibility != mLastWindowVisibility;
boolean redrawNeeded = false;
- if (creating || formatChanged || sizeChanged || visibleChanged
- || mUpdateWindowNeeded || mReportDrawNeeded) {
+ if (creating || formatChanged || sizeChanged || visibleChanged || windowVisibleChanged) {
getLocationInWindow(mLocation);
if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " "
@@ -476,93 +446,74 @@
final boolean visible = mVisible = mRequestedVisible;
mWindowSpaceLeft = mLocation[0];
mWindowSpaceTop = mLocation[1];
- mWindowSpaceWidth = myWidth;
- mWindowSpaceHeight = myHeight;
+ mSurfaceWidth = myWidth;
+ mSurfaceHeight = myHeight;
mFormat = mRequestedFormat;
+ mLastWindowVisibility = mWindowVisibility;
- // Scaling/Translate window's layout here because mLayout is not used elsewhere.
-
- // Places the window relative
- mLayout.x = mWindowSpaceLeft;
- mLayout.y = mWindowSpaceTop;
- mLayout.width = getWidth();
- mLayout.height = getHeight();
+ mScreenRect.left = mWindowSpaceLeft;
+ mScreenRect.top = mWindowSpaceTop;
+ mScreenRect.right = mWindowSpaceLeft + getWidth();
+ mScreenRect.bottom = mWindowSpaceTop + getHeight();
if (mTranslator != null) {
- mTranslator.translateLayoutParamsInAppWindowToScreen(mLayout);
+ mTranslator.translateRectInAppWindowToScreen(mScreenRect);
}
- mLayout.format = mRequestedFormat;
- mLayout.flags |=WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
- | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
- | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS
- | WindowManager.LayoutParams.FLAG_SCALED
- | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
- | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
- ;
- if (!creating && !sizeChanged) {
- mLayout.privateFlags |=
- WindowManager.LayoutParams.PRIVATE_FLAG_PRESERVE_GEOMETRY;
- } else {
- mLayout.privateFlags &=
- ~WindowManager.LayoutParams.PRIVATE_FLAG_PRESERVE_GEOMETRY;
+ if (creating) {
+ mSurfaceSession = new SurfaceSession(viewRoot.mSurface);
+ mSurfaceControl = new SurfaceControl(mSurfaceSession,
+ "SurfaceView - " + viewRoot.getTitle().toString(),
+ mSurfaceWidth, mSurfaceHeight, mFormat,
+ mSurfaceFlags);
}
- if (!getContext().getResources().getCompatibilityInfo().supportsScreen()) {
- mLayout.privateFlags |=
- WindowManager.LayoutParams.PRIVATE_FLAG_COMPATIBLE_WINDOW;
- }
- mLayout.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_NO_MOVE_ANIMATION
- | WindowManager.LayoutParams.PRIVATE_FLAG_LAYOUT_CHILD_WINDOW_IN_PARENT_FRAME;
-
- if (mWindow == null) {
- Display display = getDisplay();
- mWindow = new MyWindow(this);
- mLayout.type = mWindowType;
- mLayout.gravity = Gravity.START|Gravity.TOP;
- mSession.addToDisplayWithoutInputChannel(mWindow, mWindow.mSeq, mLayout,
- mVisible ? VISIBLE : GONE, display.getDisplayId(), mContentInsets,
- mStableInsets);
- }
-
- boolean realSizeChanged;
- boolean reportDrawNeeded;
-
- int relayoutResult;
+ boolean realSizeChanged = false;
mSurfaceLock.lock();
try {
- mUpdateWindowNeeded = false;
- reportDrawNeeded = mReportDrawNeeded;
- mReportDrawNeeded = false;
mDrawingStopped = !visible;
if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " "
+ "Cur surface: " + mSurface);
- relayoutResult = mSession.relayout(
- mWindow, mWindow.mSeq, mLayout, mWindowSpaceWidth, mWindowSpaceHeight,
- visible ? VISIBLE : GONE,
- WindowManagerGlobal.RELAYOUT_DEFER_SURFACE_DESTROY,
- mWinFrame, mOverscanInsets, mContentInsets,
- mVisibleInsets, mStableInsets, mOutsets, mBackdropFrame,
- mConfiguration, mNewSurface);
- if ((relayoutResult & WindowManagerGlobal.RELAYOUT_RES_FIRST_TIME) != 0) {
- reportDrawNeeded = true;
+ SurfaceControl.openTransaction();
+ try {
+ mSurfaceControl.setLayer(mSubLayer);
+ if (mViewVisibility) {
+ mSurfaceControl.show();
+ } else {
+ mSurfaceControl.hide();
+ }
+
+ // While creating the surface, we will set it's initial
+ // geometry. Outside of that though, we should generally
+ // leave it to the RenderThread.
+ if (creating || !mRtHandlingPositionUpdates) {
+ mSurfaceControl.setPosition(mScreenRect.left, mScreenRect.top);
+ mSurfaceControl.setMatrix(mScreenRect.width() / (float) mSurfaceWidth,
+ 0.0f, 0.0f,
+ mScreenRect.height() / (float) mSurfaceHeight);
+ }
+ if (sizeChanged) {
+ mSurfaceControl.setSize(mSurfaceWidth, mSurfaceHeight);
+ }
+ } finally {
+ SurfaceControl.closeTransaction();
}
- if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " "
- + "New surface: " + mNewSurface
- + ", vis=" + visible + ", frame=" + mWinFrame);
+ if (sizeChanged || creating) {
+ redrawNeeded = true;
+ }
mSurfaceFrame.left = 0;
mSurfaceFrame.top = 0;
if (mTranslator == null) {
- mSurfaceFrame.right = mWinFrame.width();
- mSurfaceFrame.bottom = mWinFrame.height();
+ mSurfaceFrame.right = mSurfaceWidth;
+ mSurfaceFrame.bottom = mSurfaceHeight;
} else {
float appInvertedScale = mTranslator.applicationInvertedScale;
- mSurfaceFrame.right = (int) (mWinFrame.width() * appInvertedScale + 0.5f);
- mSurfaceFrame.bottom = (int) (mWinFrame.height() * appInvertedScale + 0.5f);
+ mSurfaceFrame.right = (int) (mSurfaceWidth * appInvertedScale + 0.5f);
+ mSurfaceFrame.bottom = (int) (mSurfaceHeight * appInvertedScale + 0.5f);
}
final int surfaceWidth = mSurfaceFrame.right;
@@ -576,12 +527,11 @@
}
try {
- redrawNeeded |= creating | reportDrawNeeded;
+ redrawNeeded |= visible && !mDrawFinished;
SurfaceHolder.Callback callbacks[] = null;
- final boolean surfaceChanged = (relayoutResult
- & WindowManagerGlobal.RELAYOUT_RES_SURFACE_CHANGED) != 0;
+ final boolean surfaceChanged = creating;
if (mSurfaceCreated && (surfaceChanged || (!visible && visibleChanged))) {
mSurfaceCreated = false;
if (mSurface.isValid()) {
@@ -608,7 +558,10 @@
}
}
- mSurface.transferFrom(mNewSurface);
+ if (creating) {
+ mSurface.copyFrom(mSurfaceControl);
+ }
+
if (visible && mSurface.isValid()) {
if (!mSurfaceCreated && (surfaceChanged || visibleChanged)) {
mSurfaceCreated = true;
@@ -641,53 +594,57 @@
callbacks = getSurfaceCallbacks();
}
SurfaceCallbackHelper sch =
- new SurfaceCallbackHelper(mSession, mWindow);
+ new SurfaceCallbackHelper(this::onDrawFinished);
sch.dispatchSurfaceRedrawNeededAsync(mSurfaceHolder, callbacks);
}
}
} finally {
mIsCreating = false;
- mSession.performDeferredDestroy(mWindow);
+ if (mSurfaceControl != null && !mSurfaceCreated) {
+ mSurfaceControl.destroy();
+ mSurfaceControl = null;
+ }
}
- } catch (RemoteException ex) {
+ } catch (Exception ex) {
Log.e(TAG, "Exception from relayout", ex);
}
if (DEBUG) Log.v(
- TAG, "Layout: x=" + mLayout.x + " y=" + mLayout.y +
- " w=" + mLayout.width + " h=" + mLayout.height +
- ", frame=" + mSurfaceFrame);
+ TAG, "Layout: x=" + mScreenRect.left + " y=" + mScreenRect.top
+ + " w=" + mScreenRect.width() + " h=" + mScreenRect.height()
+ + ", frame=" + mSurfaceFrame);
} else {
// Calculate the window position in case RT loses the window
// and we need to fallback to a UI-thread driven position update
getLocationInWindow(mLocation);
final boolean positionChanged = mWindowSpaceLeft != mLocation[0]
|| mWindowSpaceTop != mLocation[1];
+ final boolean layoutSizeChanged = getWidth() != mScreenRect.width()
+ || getHeight() != mScreenRect.height();
if (positionChanged || layoutSizeChanged) { // Only the position has changed
mWindowSpaceLeft = mLocation[0];
mWindowSpaceTop = mLocation[1];
- // For our size changed check, we keep mLayout.width and mLayout.height
+ // For our size changed check, we keep mScreenRect.width() and mScreenRect.height()
// in view local space.
- mLocation[0] = mLayout.width = getWidth();
- mLocation[1] = mLayout.height = getHeight();
+ mLocation[0] = getWidth();
+ mLocation[1] = getHeight();
transformFromViewToWindowSpace(mLocation);
- mTmpRect.set(mWindowSpaceLeft, mWindowSpaceTop,
+ mScreenRect.set(mWindowSpaceLeft, mWindowSpaceTop,
mLocation[0], mLocation[1]);
if (mTranslator != null) {
- mTranslator.translateRectInAppWindowToScreen(mTmpRect);
+ mTranslator.translateRectInAppWindowToScreen(mScreenRect);
}
if (!isHardwareAccelerated() || !mRtHandlingPositionUpdates) {
try {
- if (DEBUG) Log.d(TAG, String.format("%d updateWindowPosition UI, " +
+ if (DEBUG) Log.d(TAG, String.format("%d updateSurfacePosition UI, " +
"postion = [%d, %d, %d, %d]", System.identityHashCode(this),
- mTmpRect.left, mTmpRect.top,
- mTmpRect.right, mTmpRect.bottom));
- mSession.repositionChild(mWindow, mTmpRect.left, mTmpRect.top,
- mTmpRect.right, mTmpRect.bottom, -1, mTmpRect);
- } catch (RemoteException ex) {
+ mScreenRect.left, mScreenRect.top,
+ mScreenRect.right, mScreenRect.bottom));
+ setParentSpaceRectangle(mScreenRect, -1);
+ } catch (Exception ex) {
Log.e(TAG, "Exception from relayout", ex);
}
}
@@ -695,18 +652,40 @@
}
}
+ private void onDrawFinished() {
+ if (DEBUG) {
+ Log.i(TAG, System.identityHashCode(this) + " "
+ + "finishedDrawing");
+ }
+ mHandler.sendEmptyMessage(DRAW_FINISHED_MSG);
+ }
+
+ private void setParentSpaceRectangle(Rect position, long frameNumber) {
+ ViewRootImpl viewRoot = getViewRootImpl();
+
+ SurfaceControl.openTransaction();
+ try {
+ if (frameNumber > 0) {
+ mSurfaceControl.deferTransactionUntil(viewRoot.mSurface, frameNumber);
+ }
+ mSurfaceControl.setPosition(position.left, position.top);
+ mSurfaceControl.setMatrix(position.width() / (float) mSurfaceWidth,
+ 0.0f, 0.0f,
+ position.height() / (float) mSurfaceHeight);
+ } finally {
+ SurfaceControl.closeTransaction();
+ }
+ }
+
private Rect mRTLastReportedPosition = new Rect();
/**
* Called by native by a Rendering Worker thread to update the window position
* @hide
*/
- public final void updateWindowPosition_renderWorker(long frameNumber,
+ public final void updateSurfacePosition_renderWorker(long frameNumber,
int left, int top, int right, int bottom) {
- IWindowSession session = mSession;
- MyWindow window = mWindow;
- if (session == null || window == null) {
- // Guess we got detached, that sucks
+ if (mSurfaceControl == null) {
return;
}
// TODO: This is teensy bit racey in that a brand new SurfaceView moving on
@@ -726,35 +705,29 @@
}
try {
if (DEBUG) {
- Log.d(TAG, String.format("%d updateWindowPosition RenderWorker, frameNr = %d, " +
+ Log.d(TAG, String.format("%d updateSurfacePosition RenderWorker, frameNr = %d, " +
"postion = [%d, %d, %d, %d]", System.identityHashCode(this),
frameNumber, left, top, right, bottom));
}
- // Just using mRTLastReportedPosition as a dummy rect here
- session.repositionChild(window, left, top, right, bottom,
- frameNumber,
- mRTLastReportedPosition);
- // Now overwrite mRTLastReportedPosition with our values
mRTLastReportedPosition.set(left, top, right, bottom);
- } catch (RemoteException ex) {
+ setParentSpaceRectangle(mRTLastReportedPosition, frameNumber);
+ // Now overwrite mRTLastReportedPosition with our values
+ } catch (Exception ex) {
Log.e(TAG, "Exception from repositionChild", ex);
}
}
/**
- * Called by native on RenderThread to notify that the window is no longer in the
+ * Called by native on RenderThread to notify that the view is no longer in the
* draw tree. UI thread is blocked at this point.
* @hide
*/
- public final void windowPositionLost_uiRtSync(long frameNumber) {
+ public final void surfacePositionLost_uiRtSync(long frameNumber) {
if (DEBUG) {
Log.d(TAG, String.format("%d windowPositionLost, frameNr = %d",
System.identityHashCode(this), frameNumber));
}
- IWindowSession session = mSession;
- MyWindow window = mWindow;
- if (session == null || window == null) {
- // We got detached prior to receiving this, abort
+ if (mSurfaceControl == null) {
return;
}
if (mRtHandlingPositionUpdates) {
@@ -763,19 +736,14 @@
// safely access other member variables at this time.
// So do what the UI thread would have done if RT wasn't handling position
// updates.
- mTmpRect.set(mLayout.x, mLayout.y,
- mLayout.x + mLayout.width,
- mLayout.y + mLayout.height);
-
- if (!mTmpRect.isEmpty() && !mTmpRect.equals(mRTLastReportedPosition)) {
+ if (!mScreenRect.isEmpty() && !mScreenRect.equals(mRTLastReportedPosition)) {
try {
- if (DEBUG) Log.d(TAG, String.format("%d updateWindowPosition, " +
+ if (DEBUG) Log.d(TAG, String.format("%d updateSurfacePosition, " +
"postion = [%d, %d, %d, %d]", System.identityHashCode(this),
- mTmpRect.left, mTmpRect.top,
- mTmpRect.right, mTmpRect.bottom));
- session.repositionChild(window, mTmpRect.left, mTmpRect.top,
- mTmpRect.right, mTmpRect.bottom, frameNumber, mWinFrame);
- } catch (RemoteException ex) {
+ mScreenRect.left, mScreenRect.top,
+ mScreenRect.right, mScreenRect.bottom));
+ setParentSpaceRectangle(mScreenRect, frameNumber);
+ } catch (Exception ex) {
Log.e(TAG, "Exception from relayout", ex);
}
}
@@ -792,10 +760,6 @@
return callbacks;
}
- void handleGetNewSurface() {
- updateWindow();
- }
-
/**
* Check to see if the surface has fixed size dimensions or if the surface's
* dimensions are dimensions are dependent on its current layout.
@@ -807,65 +771,8 @@
return (mRequestedWidth != -1 || mRequestedHeight != -1);
}
- private static class MyWindow extends BaseIWindow {
- private final WeakReference<SurfaceView> mSurfaceView;
-
- public MyWindow(SurfaceView surfaceView) {
- mSurfaceView = new WeakReference<SurfaceView>(surfaceView);
- }
-
- @Override
- public void resized(Rect frame, Rect overscanInsets, Rect contentInsets,
- Rect visibleInsets, Rect stableInsets, Rect outsets, boolean reportDraw,
- Configuration newConfig, Rect backDropRect, boolean forceLayout,
- boolean alwaysConsumeNavBar, int displayId) {
- SurfaceView surfaceView = mSurfaceView.get();
- if (surfaceView != null) {
- if (DEBUG) Log.v(TAG, surfaceView + " got resized: w=" + frame.width()
- + " h=" + frame.height() + ", cur w=" + mCurWidth + " h=" + mCurHeight);
- surfaceView.mSurfaceLock.lock();
- try {
- if (reportDraw) {
- surfaceView.mUpdateWindowNeeded = true;
- surfaceView.mReportDrawNeeded = true;
- surfaceView.mHandler.sendEmptyMessage(UPDATE_WINDOW_MSG);
- } else if (surfaceView.mWinFrame.width() != frame.width()
- || surfaceView.mWinFrame.height() != frame.height()
- || forceLayout) {
- surfaceView.mUpdateWindowNeeded = true;
- surfaceView.mHandler.sendEmptyMessage(UPDATE_WINDOW_MSG);
- }
- } finally {
- surfaceView.mSurfaceLock.unlock();
- }
- }
- }
-
- @Override
- public void dispatchAppVisibility(boolean visible) {
- // The point of SurfaceView is to let the app control the surface.
- }
-
- @Override
- public void dispatchGetNewSurface() {
- SurfaceView surfaceView = mSurfaceView.get();
- if (surfaceView != null) {
- Message msg = surfaceView.mHandler.obtainMessage(GET_NEW_SURFACE_MSG);
- surfaceView.mHandler.sendMessage(msg);
- }
- }
-
- @Override
- public void windowFocusChanged(boolean hasFocus, boolean touchEnabled) {
- Log.w("SurfaceView", "Unexpected focus in surface: focus=" + hasFocus + ", touchEnabled=" + touchEnabled);
- }
-
- @Override
- public void executeCommand(String command, String parameters, ParcelFileDescriptor out) {
- }
-
- int mCurWidth = -1;
- int mCurHeight = -1;
+ private boolean isAboveParent() {
+ return mSubLayer >= 0;
}
private final SurfaceHolder mSurfaceHolder = new SurfaceHolder() {
@@ -913,15 +820,14 @@
@Override
public void setFormat(int format) {
-
// for backward compatibility reason, OPAQUE always
// means 565 for SurfaceView
if (format == PixelFormat.OPAQUE)
format = PixelFormat.RGB_565;
mRequestedFormat = format;
- if (mWindow != null) {
- updateWindow();
+ if (mSurfaceControl != null) {
+ updateSurface();
}
}
@@ -982,10 +888,10 @@
mSurfaceLock.lock();
if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " " + "Locking canvas... stopped="
- + mDrawingStopped + ", win=" + mWindow);
+ + mDrawingStopped + ", surfaceControl=" + mSurfaceControl);
Canvas c = null;
- if (!mDrawingStopped && mWindow != null) {
+ if (!mDrawingStopped && mSurfaceControl != null) {
try {
if (hardware) {
c = mSurface.lockHardwareCanvas();
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index aa85a98..e349170 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -4500,6 +4500,8 @@
break;
case com.android.internal.R.styleable.View_focusableInTouchMode:
if (a.getBoolean(attr, false)) {
+ // unset auto focus since focusableInTouchMode implies explicit focusable
+ viewFlagValues &= ~FOCUSABLE_AUTO;
viewFlagValues |= FOCUSABLE_IN_TOUCH_MODE | FOCUSABLE;
viewFlagMasks |= FOCUSABLE_IN_TOUCH_MODE | FOCUSABLE_MASK;
}
@@ -6471,12 +6473,18 @@
}
}
}
+
+ // Invisible and gone views are never focusable.
if ((mViewFlags & VISIBILITY_MASK) != VISIBLE) {
return false;
}
- return (allowAutoFocus
- ? getFocusable() != NOT_FOCUSABLE
- : getFocusable() == FOCUSABLE) && isFocusable();
+
+ // Only use effective focusable value when allowed.
+ if ((allowAutoFocus || getFocusable() != FOCUSABLE_AUTO) && isFocusable()) {
+ return true;
+ }
+
+ return false;
}
/**
@@ -6984,8 +6992,12 @@
* Called when assist structure is being retrieved from a view as part of an auto-fill request.
*
* <p>This method already provides most of what's needed for auto-fill, but should be overridden
- * when the view contents does not include PII (Personally Identifiable Information) (so it
- * can call {@link ViewStructure#setSanitized(boolean) ViewStructure#setSanitized(true)}).
+ * <ol>
+ * <li>The view contents does not include PII (Personally Identifiable Information), so it
+ * can call {@link ViewStructure#setSanitized(boolean)} passing {@code true}.
+ * <li>It must set fields such {@link ViewStructure#setText(CharSequence)},
+ * {@link ViewStructure#setAutoFillOptions(String[])}, or {@link ViewStructure#setUrl(String)}.
+ * </ol>
*
* @param structure Fill in with structured view data. The default implementation
* fills in all data that can be inferred from the view itself.
@@ -8662,7 +8674,10 @@
// which, in touch mode, will not successfully request focus on this view
// because the focusable in touch mode flag is not set
setFlags(focusableInTouchMode ? FOCUSABLE_IN_TOUCH_MODE : 0, FOCUSABLE_IN_TOUCH_MODE);
+
+ // Clear FOCUSABLE_AUTO if set.
if (focusableInTouchMode) {
+ // Clears FOCUSABLE_AUTO if set.
setFlags(FOCUSABLE, FOCUSABLE_MASK);
}
}
@@ -9429,7 +9444,8 @@
* @return The nearest keyboard navigation cluster in the specified direction, or null if none
* can be found
*/
- public View keyboardNavigationClusterSearch(View currentCluster, int direction) {
+ public View keyboardNavigationClusterSearch(View currentCluster,
+ @FocusDirection int direction) {
if (isKeyboardNavigationCluster()) {
currentCluster = this;
}
@@ -11725,7 +11741,10 @@
&& isOnScrollbar(event.getX(), event.getY())) {
awakenScrollBars();
}
- if (isHoverable()) {
+
+ // If we consider ourself hoverable, or if we we're already hovered,
+ // handle changing state in response to ENTER and EXIT events.
+ if (isHoverable() || isHovered()) {
switch (action) {
case MotionEvent.ACTION_HOVER_ENTER:
setHovered(true);
@@ -12256,12 +12275,13 @@
// If focusable is auto, update the FOCUSABLE bit.
int focusableChangedByAuto = 0;
if (((mViewFlags & FOCUSABLE_AUTO) != 0)
- && (changed & (FOCUSABLE_MASK | CLICKABLE | FOCUSABLE_IN_TOUCH_MODE)) != 0) {
- int newFocus = NOT_FOCUSABLE;
- if ((mViewFlags & (CLICKABLE | FOCUSABLE_IN_TOUCH_MODE)) != 0) {
+ && (changed & (FOCUSABLE_MASK | CLICKABLE)) != 0) {
+ // Heuristic only takes into account whether view is clickable.
+ final int newFocus;
+ if ((mViewFlags & CLICKABLE) != 0) {
newFocus = FOCUSABLE;
} else {
- mViewFlags = (mViewFlags & ~FOCUSABLE_IN_TOUCH_MODE);
+ newFocus = NOT_FOCUSABLE;
}
mViewFlags = (mViewFlags & ~FOCUSABLE) | newFocus;
focusableChangedByAuto = (old & FOCUSABLE) ^ (newFocus & FOCUSABLE);
@@ -20255,9 +20275,9 @@
* @return the view of the specified id, null if cannot be found
* @hide
*/
- protected View findViewTraversal(@IdRes int id) {
+ protected <T extends View> T findViewTraversal(@IdRes int id) {
if (id == mID) {
- return this;
+ return (T) this;
}
return null;
}
@@ -20267,9 +20287,9 @@
* @return the view of specified tag, null if cannot be found
* @hide
*/
- protected View findViewWithTagTraversal(Object tag) {
+ protected <T extends View> T findViewWithTagTraversal(Object tag) {
if (tag != null && tag.equals(mTag)) {
- return this;
+ return (T) this;
}
return null;
}
@@ -20280,9 +20300,10 @@
* @return The first view that matches the predicate or null.
* @hide
*/
- protected View findViewByPredicateTraversal(Predicate<View> predicate, View childToSkip) {
+ protected <T extends View> T findViewByPredicateTraversal(Predicate<View> predicate,
+ View childToSkip) {
if (predicate.test(this)) {
- return this;
+ return (T) this;
}
return null;
}
@@ -20295,7 +20316,7 @@
* @return The view that has the given id in the hierarchy or null
*/
@Nullable
- public final View findViewById(@IdRes int id) {
+ public final <T extends View> T findViewById(@IdRes int id) {
if (id < 0) {
return null;
}
@@ -20308,11 +20329,11 @@
* @param accessibilityId The searched accessibility id.
* @return The found view.
*/
- final View findViewByAccessibilityId(int accessibilityId) {
+ final <T extends View> T findViewByAccessibilityId(int accessibilityId) {
if (accessibilityId < 0) {
return null;
}
- View view = findViewByAccessibilityIdTraversal(accessibilityId);
+ T view = findViewByAccessibilityIdTraversal(accessibilityId);
if (view != null) {
return view.includeForAccessibility() ? view : null;
}
@@ -20331,12 +20352,11 @@
*
* @param accessibilityId The accessibility id.
* @return The found view.
- *
* @hide
*/
- public View findViewByAccessibilityIdTraversal(int accessibilityId) {
+ public <T extends View> T findViewByAccessibilityIdTraversal(int accessibilityId) {
if (getAccessibilityViewId() == accessibilityId) {
- return this;
+ return (T) this;
}
return null;
}
@@ -20348,7 +20368,7 @@
* @param tag The tag to search for, using "tag.equals(getTag())".
* @return The View that has the given tag in the hierarchy or null
*/
- public final View findViewWithTag(Object tag) {
+ public final <T extends View> T findViewWithTag(Object tag) {
if (tag == null) {
return null;
}
@@ -20363,7 +20383,7 @@
* @return The first view that matches the predicate or null.
* @hide
*/
- public final View findViewByPredicate(Predicate<View> predicate) {
+ public final <T extends View> T findViewByPredicate(Predicate<View> predicate) {
return findViewByPredicateTraversal(predicate, null);
}
@@ -20383,10 +20403,11 @@
* @return The first view that matches the predicate or null.
* @hide
*/
- public final View findViewByPredicateInsideOut(View start, Predicate<View> predicate) {
+ public final <T extends View> T findViewByPredicateInsideOut(
+ View start, Predicate<View> predicate) {
View childToSkip = null;
for (;;) {
- View view = start.findViewByPredicateTraversal(predicate, childToSkip);
+ T view = start.findViewByPredicateTraversal(predicate, childToSkip);
if (view != null || start == this) {
return view;
}
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index 7aa2168..3dd3ba8 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -1148,18 +1148,21 @@
@Override
boolean hasFocusable(boolean allowAutoFocus, boolean dispatchExplicit) {
+ // This should probably be super.hasFocusable, but that would change
+ // behavior. Historically, we have not checked the ancestor views for
+ // shouldBlockFocusForTouchscreen() in ViewGroup.hasFocusable.
+
+ // Invisible and gone views are never focusable.
if ((mViewFlags & VISIBILITY_MASK) != VISIBLE) {
return false;
}
- // TODO This should probably be super.hasFocusable, but that would change behavior.
- // The below is a much simpler check than we do in the superclass implementation,
- // but it's been this way for a long time and other code likely relies on it.
- if ((allowAutoFocus ? getFocusable() != NOT_FOCUSABLE : getFocusable() == FOCUSABLE)
- && isFocusable()) {
+ // Only use effective focusable value when allowed.
+ if ((allowAutoFocus || getFocusable() != FOCUSABLE_AUTO) && isFocusable()) {
return true;
}
+ // Determine whether we have a focused descendant.
final int descendantFocusability = getDescendantFocusability();
if (descendantFocusability != FOCUS_BLOCK_DESCENDANTS) {
final int count = mChildrenCount;
@@ -4324,9 +4327,9 @@
* {@hide}
*/
@Override
- protected View findViewTraversal(@IdRes int id) {
+ protected <T extends View> T findViewTraversal(@IdRes int id) {
if (id == mID) {
- return this;
+ return (T) this;
}
final View[] where = mChildren;
@@ -4339,7 +4342,7 @@
v = v.findViewById(id);
if (v != null) {
- return v;
+ return (T) v;
}
}
}
@@ -4351,9 +4354,9 @@
* {@hide}
*/
@Override
- protected View findViewWithTagTraversal(Object tag) {
+ protected <T extends View> T findViewWithTagTraversal(Object tag) {
if (tag != null && tag.equals(mTag)) {
- return this;
+ return (T) this;
}
final View[] where = mChildren;
@@ -4366,7 +4369,7 @@
v = v.findViewWithTag(tag);
if (v != null) {
- return v;
+ return (T) v;
}
}
}
@@ -4378,9 +4381,10 @@
* {@hide}
*/
@Override
- protected View findViewByPredicateTraversal(Predicate<View> predicate, View childToSkip) {
+ protected <T extends View> T findViewByPredicateTraversal(Predicate<View> predicate,
+ View childToSkip) {
if (predicate.test(this)) {
- return this;
+ return (T) this;
}
final View[] where = mChildren;
@@ -4393,7 +4397,7 @@
v = v.findViewByPredicate(predicate);
if (v != null) {
- return v;
+ return (T) v;
}
}
}
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index c81e938..f9863b0 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -72,6 +72,7 @@
import android.util.TypedValue;
import android.view.Surface.OutOfResourcesException;
import android.view.View.AttachInfo;
+import android.view.View.FocusDirection;
import android.view.View.MeasureSpec;
import android.view.WindowManager.LayoutParams.SoftInputModeFlags;
import android.view.accessibility.AccessibilityEvent;
@@ -1047,8 +1048,8 @@
// Get new instance of display based on current display adjustments. It may be updated later
// if moving between the displays also involved a configuration change.
- final DisplayAdjustments displayAdjustments = mView.getResources().getDisplayAdjustments();
- mDisplay = ResourcesManager.getInstance().getAdjustedDisplay(displayId, displayAdjustments);
+ mDisplay = ResourcesManager.getInstance().getAdjustedDisplay(displayId,
+ mView.getResources());
mAttachInfo.mDisplayState = mDisplay.getState();
// Internal state updated, now notify the view hierarchy.
mView.dispatchMovedToDisplay(mDisplay);
@@ -2631,6 +2632,14 @@
}
}
+ private void onDrawFinished() {
+ try {
+ mWindowSession.finishDrawing(mWindow);
+ } catch (RemoteException e) {
+ // Have fun!
+ }
+ }
+
private void performDraw() {
if (mAttachInfo.mDisplayState == Display.STATE_OFF && !mReportNextDraw) {
return;
@@ -2681,7 +2690,7 @@
}
if (mSurfaceHolder != null && mSurface.isValid()) {
- SurfaceCallbackHelper sch = new SurfaceCallbackHelper(mWindowSession, mWindow);
+ SurfaceCallbackHelper sch = new SurfaceCallbackHelper(this::onDrawFinished);
SurfaceHolder.Callback callbacks[] = mSurfaceHolder.getCallbacks();
sch.dispatchSurfaceRedrawNeededAsync(mSurfaceHolder, callbacks);
@@ -3384,7 +3393,7 @@
if (force || mLastConfiguration.diff(config) != 0) {
// Update the display with new DisplayAdjustments.
mDisplay = ResourcesManager.getInstance().getAdjustedDisplay(
- mDisplay.getDisplayId(), localResources.getDisplayAdjustments());
+ mDisplay.getDisplayId(), localResources);
final int lastLayoutDirection = mLastConfiguration.getLayoutDirection();
final int currentLayoutDirection = config.getLayoutDirection();
@@ -4304,11 +4313,11 @@
mTranslator.translateEventInScreenToAppWindow(event);
}
- // Enter touch mode on down or scroll.
+ // Enter touch mode on down or scroll, if it is coming from a touch screen device,
+ // exit otherwise.
final int action = event.getAction();
- if (event.isFromSource(InputDevice.SOURCE_TOUCHSCREEN)
- && (action == MotionEvent.ACTION_DOWN || action == MotionEvent.ACTION_SCROLL)) {
- ensureTouchMode(true);
+ if (action == MotionEvent.ACTION_DOWN || action == MotionEvent.ACTION_SCROLL) {
+ ensureTouchMode(event.isFromSource(InputDevice.SOURCE_TOUCHSCREEN));
}
if (action == MotionEvent.ACTION_DOWN && mAttachInfo.mTooltipHost != null) {
@@ -5975,7 +5984,8 @@
* {@inheritDoc}
*/
@Override
- public View keyboardNavigationClusterSearch(View currentCluster, int direction) {
+ public View keyboardNavigationClusterSearch(View currentCluster,
+ @FocusDirection int direction) {
checkThread();
return FocusFinder.getInstance().findNextKeyboardNavigationCluster(
mView, currentCluster, direction);
diff --git a/core/java/android/view/ViewStructure.java b/core/java/android/view/ViewStructure.java
index bc2725f..84c2c84 100644
--- a/core/java/android/view/ViewStructure.java
+++ b/core/java/android/view/ViewStructure.java
@@ -307,6 +307,15 @@
public abstract void setAutoFillValue(AutoFillValue value);
/**
+ * Sets the options that can be used to auto-fill this node.
+ *
+ * <p>Typically used by nodes whose {@link AutoFillType} is a list to indicate the meaning of
+ * each possible value in the list.
+ */
+ // TODO(b/33197203, b/33802548): add CTS/unit test
+ public abstract void setAutoFillOptions(String[] options);
+
+ /**
* Marks this node as sanitized so its content are sent on {@link
* android.service.autofill.AutoFillService#onFillRequest(android.app.assist.AssistStructure,
* Bundle, android.os.CancellationSignal, android.service.autofill.FillCallback)}.
diff --git a/core/java/android/view/accessibility/AccessibilityNodeInfo.java b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
index d866927..8094fa6 100644
--- a/core/java/android/view/accessibility/AccessibilityNodeInfo.java
+++ b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
@@ -3591,6 +3591,7 @@
* <li><strong>Standard actions</strong> - These are actions that are reported and
* handled by the standard UI widgets in the platform. For each standard action
* there is a static constant defined in this class, e.g. {@link #ACTION_FOCUS}.
+ * These actions will have {@code null} labels.
* </li>
* <li><strong>Custom actions action</strong> - These are actions that are reported
* and handled by custom widgets. i.e. ones that are not part of the UI toolkit. For
diff --git a/core/java/android/view/autofill/AutoFillManager.java b/core/java/android/view/autofill/AutoFillManager.java
index baba389..b44bbbe 100644
--- a/core/java/android/view/autofill/AutoFillManager.java
+++ b/core/java/android/view/autofill/AutoFillManager.java
@@ -17,12 +17,14 @@
package android.view.autofill;
import static android.view.autofill.Helper.DEBUG;
+import static android.view.autofill.Helper.VERBOSE;
import android.content.Context;
import android.content.Intent;
import android.content.IntentSender;
import android.graphics.Rect;
import android.os.Bundle;
+import android.os.IBinder;
import android.os.Parcelable;
import android.os.RemoteException;
import android.util.Log;
@@ -131,7 +133,7 @@
if (!mHasSession) {
if (gainFocus) {
// Starts new session.
- startSession(id, bounds, value);
+ startSession(id, view.getWindowToken(), bounds, value);
}
} else {
// Update focus on existing session.
@@ -159,7 +161,7 @@
if (!mHasSession) {
if (gainFocus) {
// Starts new session.
- startSession(id, bounds, null);
+ startSession(id, parent.getWindowToken(), bounds, null);
}
} else {
// Update focus on existing session.
@@ -251,13 +253,14 @@
return new AutoFillId(parent.getAccessibilityViewId(), childId);
}
- private void startSession(AutoFillId id, Rect bounds, AutoFillValue value) {
+ private void startSession(AutoFillId id, IBinder windowToken,
+ Rect bounds, AutoFillValue value) {
if (DEBUG) {
- Log.v(TAG, "startSession(): id=" + id + ", bounds=" + bounds + ", value=" + value);
+ Log.d(TAG, "startSession(): id=" + id + ", bounds=" + bounds + ", value=" + value);
}
try {
- mService.startSession(mContext.getActivityToken(), mServiceClient.asBinder(),
- id, bounds, value, mContext.getUserId());
+ mService.startSession(mContext.getActivityToken(), windowToken,
+ mServiceClient.asBinder(), id, bounds, value, mContext.getUserId());
AutoFillClient client = getClient();
if (client != null) {
client.resetableStateAvailable();
@@ -270,7 +273,7 @@
private void finishSession() {
if (DEBUG) {
- Log.v(TAG, "finishSession()");
+ Log.d(TAG, "finishSession()");
}
mHasSession = false;
try {
@@ -282,9 +285,12 @@
private void updateSession(AutoFillId id, Rect bounds, AutoFillValue value, int flags) {
if (DEBUG) {
- Log.v(TAG, "updateSession(): id=" + id + ", bounds=" + bounds + ", value=" + value
+ if (VERBOSE || (flags & FLAG_FOCUS_LOST) != 0) {
+ Log.d(TAG, "updateSession(): id=" + id + ", bounds=" + bounds + ", value=" + value
+ ", flags=" + flags);
+ }
}
+
try {
mService.updateSession(mContext.getActivityToken(), id, bounds, value, flags,
mContext.getUserId());
diff --git a/core/java/android/view/autofill/AutoFillType.java b/core/java/android/view/autofill/AutoFillType.java
index 017f7f8..5d85bfd 100644
--- a/core/java/android/view/autofill/AutoFillType.java
+++ b/core/java/android/view/autofill/AutoFillType.java
@@ -44,8 +44,6 @@
private static final int TYPE_TEXT = 1;
private static final int TYPE_TOGGLE = 2;
- // TODO(b/33197203): make sure it works with Spinners and/or add a new type for them
- // (since they're often used for credit card selection)
private static final int TYPE_LIST = 3;
// TODO(b/33197203): add others, like date picker? That would be trick, because they're set as:
diff --git a/core/java/android/view/autofill/IAutoFillManager.aidl b/core/java/android/view/autofill/IAutoFillManager.aidl
index 0433a8f..d054e97 100644
--- a/core/java/android/view/autofill/IAutoFillManager.aidl
+++ b/core/java/android/view/autofill/IAutoFillManager.aidl
@@ -30,7 +30,7 @@
*/
interface IAutoFillManager {
boolean addClient(in IAutoFillManagerClient client, int userId);
- oneway void startSession(in IBinder activityToken, in IBinder appCallback,
+ oneway void startSession(in IBinder activityToken, IBinder windowToken, in IBinder appCallback,
in AutoFillId autoFillId, in Rect bounds, in AutoFillValue value, int userId);
oneway void updateSession(in IBinder activityToken, in AutoFillId id, in Rect bounds,
in AutoFillValue value, int flags, int userId);
diff --git a/core/java/android/webkit/WebViewZygote.java b/core/java/android/webkit/WebViewZygote.java
index 2d6f443..f9d7332 100644
--- a/core/java/android/webkit/WebViewZygote.java
+++ b/core/java/android/webkit/WebViewZygote.java
@@ -176,7 +176,7 @@
// paths and pass them to the zygote as strings.
final List<String> zipPaths = new ArrayList<>(10);
final List<String> libPaths = new ArrayList<>(10);
- LoadedApk.makePaths(null, sPackage.applicationInfo, zipPaths, libPaths);
+ LoadedApk.makePaths(null, false, sPackage.applicationInfo, zipPaths, libPaths);
final String librarySearchPath = TextUtils.join(File.pathSeparator, libPaths);
final String zip = (zipPaths.size() == 1) ? zipPaths.get(0) :
TextUtils.join(File.pathSeparator, zipPaths);
diff --git a/core/java/android/widget/ActivityChooserView.java b/core/java/android/widget/ActivityChooserView.java
index 51587a7..9a39a17 100644
--- a/core/java/android/widget/ActivityChooserView.java
+++ b/core/java/android/widget/ActivityChooserView.java
@@ -250,7 +250,7 @@
mDefaultActivityButton = (FrameLayout) findViewById(R.id.default_activity_button);
mDefaultActivityButton.setOnClickListener(mCallbacks);
mDefaultActivityButton.setOnLongClickListener(mCallbacks);
- mDefaultActivityButtonImage = (ImageView) mDefaultActivityButton.findViewById(R.id.image);
+ mDefaultActivityButtonImage = mDefaultActivityButton.findViewById(R.id.image);
final FrameLayout expandButton = (FrameLayout) findViewById(R.id.expand_activities_button);
expandButton.setOnClickListener(mCallbacks);
@@ -282,7 +282,7 @@
mExpandActivityOverflowButton = expandButton;
mExpandActivityOverflowButtonImage =
- (ImageView) expandButton.findViewById(R.id.image);
+ expandButton.findViewById(R.id.image);
mExpandActivityOverflowButtonImage.setImageDrawable(expandActivityOverflowButtonDrawable);
mAdapter = new ActivityChooserViewAdapter();
@@ -760,7 +760,7 @@
convertView = LayoutInflater.from(getContext()).inflate(
R.layout.activity_chooser_view_list_item, parent, false);
convertView.setId(ITEM_VIEW_TYPE_FOOTER);
- TextView titleView = (TextView) convertView.findViewById(R.id.title);
+ TextView titleView = convertView.findViewById(R.id.title);
titleView.setText(mContext.getString(
R.string.activity_chooser_view_see_all));
}
@@ -772,11 +772,11 @@
}
PackageManager packageManager = mContext.getPackageManager();
// Set the icon
- ImageView iconView = (ImageView) convertView.findViewById(R.id.icon);
+ ImageView iconView = convertView.findViewById(R.id.icon);
ResolveInfo activity = (ResolveInfo) getItem(position);
iconView.setImageDrawable(activity.loadIcon(packageManager));
// Set the title.
- TextView titleView = (TextView) convertView.findViewById(R.id.title);
+ TextView titleView = convertView.findViewById(R.id.title);
titleView.setText(activity.loadLabel(packageManager));
// Highlight the default.
if (mShowDefaultActivity && position == 0 && mHighlightDefaultActivity) {
diff --git a/core/java/android/widget/AdapterView.java b/core/java/android/widget/AdapterView.java
index 2cfefba..0b3cff1 100644
--- a/core/java/android/widget/AdapterView.java
+++ b/core/java/android/widget/AdapterView.java
@@ -34,6 +34,7 @@
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityManager;
import android.view.accessibility.AccessibilityNodeInfo;
+import android.view.autofill.AutoFillManager;
/**
* An AdapterView is a view whose children are determined by an {@link Adapter}.
@@ -914,6 +915,11 @@
dispatchOnItemSelected();
}
}
+ // Always notify AutoFillManager - it will return right away if auto-fill is disabled.
+ final AutoFillManager afm = mContext.getSystemService(AutoFillManager.class);
+ if (afm != null) {
+ afm.valueChanged(this);
+ }
}
private void dispatchOnItemSelected() {
diff --git a/core/java/android/widget/AppSecurityPermissions.java b/core/java/android/widget/AppSecurityPermissions.java
index 68e6809..06d4868 100644
--- a/core/java/android/widget/AppSecurityPermissions.java
+++ b/core/java/android/widget/AppSecurityPermissions.java
@@ -451,7 +451,7 @@
private View getPermissionsView(int which, boolean showRevokeUI) {
LinearLayout permsView = (LinearLayout) mInflater.inflate(R.layout.app_perms_summary, null);
- LinearLayout displayList = (LinearLayout) permsView.findViewById(R.id.perms_list);
+ LinearLayout displayList = permsView.findViewById(R.id.perms_list);
View noPermsView = permsView.findViewById(R.id.no_permissions);
displayPermissions(mPermGroupsList, displayList, which, showRevokeUI);
@@ -517,8 +517,8 @@
CharSequence grpName, CharSequence permList, boolean dangerous, Drawable icon) {
View permView = inflater.inflate(R.layout.app_permission_item_old, null);
- TextView permGrpView = (TextView) permView.findViewById(R.id.permission_group);
- TextView permDescView = (TextView) permView.findViewById(R.id.permission_list);
+ TextView permGrpView = permView.findViewById(R.id.permission_group);
+ TextView permDescView = permView.findViewById(R.id.permission_list);
ImageView imgView = (ImageView)permView.findViewById(R.id.perm_icon);
imgView.setImageDrawable(icon);
diff --git a/core/java/android/widget/ArrayAdapter.java b/core/java/android/widget/ArrayAdapter.java
index bbc50da..81f0d3d 100644
--- a/core/java/android/widget/ArrayAdapter.java
+++ b/core/java/android/widget/ArrayAdapter.java
@@ -388,7 +388,7 @@
text = (TextView) view;
} else {
// Otherwise, find the TextView field within the layout
- text = (TextView) view.findViewById(mFieldId);
+ text = view.findViewById(mFieldId);
if (text == null) {
throw new RuntimeException("Failed to find view with ID "
diff --git a/core/java/android/widget/CalendarViewLegacyDelegate.java b/core/java/android/widget/CalendarViewLegacyDelegate.java
index 557d411..1b899db 100644
--- a/core/java/android/widget/CalendarViewLegacyDelegate.java
+++ b/core/java/android/widget/CalendarViewLegacyDelegate.java
@@ -316,9 +316,9 @@
View content = layoutInflater.inflate(R.layout.calendar_view, null, false);
mDelegator.addView(content);
- mListView = (ListView) mDelegator.findViewById(R.id.list);
- mDayNamesHeader = (ViewGroup) content.findViewById(R.id.day_names);
- mMonthName = (TextView) content.findViewById(R.id.month_name);
+ mListView = mDelegator.findViewById(R.id.list);
+ mDayNamesHeader = content.findViewById(R.id.day_names);
+ mMonthName = content.findViewById(R.id.month_name);
setUpHeader();
setUpListView();
diff --git a/core/java/android/widget/CompoundButton.java b/core/java/android/widget/CompoundButton.java
index f2c2af5..887c59a 100644
--- a/core/java/android/widget/CompoundButton.java
+++ b/core/java/android/widget/CompoundButton.java
@@ -32,6 +32,7 @@
import android.view.SoundEffectConstants;
import android.view.ViewDebug;
import android.view.ViewHierarchyEncoder;
+import android.view.ViewStructure;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityNodeInfo;
import android.view.autofill.AutoFillManager;
@@ -68,6 +69,10 @@
private OnCheckedChangeListener mOnCheckedChangeListener;
private OnCheckedChangeListener mOnCheckedChangeWidgetListener;
+ // Indicates whether the toggle state was set from resources or dynamically, so it can be used
+ // to sanitize auto-fill requests.
+ private boolean mCheckedFromResource = false;
+
private static final int[] CHECKED_STATE_SET = {
R.attr.state_checked
};
@@ -109,6 +114,7 @@
final boolean checked = a.getBoolean(
com.android.internal.R.styleable.CompoundButton_checked, false);
setChecked(checked);
+ mCheckedFromResource = true;
a.recycle();
@@ -148,6 +154,7 @@
@Override
public void setChecked(boolean checked) {
if (mChecked != checked) {
+ mCheckedFromResource = false;
mChecked = checked;
refreshDrawableState();
notifyViewAccessibilityStateChangedIfNeeded(
@@ -569,6 +576,13 @@
// TODO(b/33197203): add unit/CTS tests for auto-fill methods (and make sure they handle enable)
@Override
+ public void onProvideAutoFillStructure(ViewStructure structure, int flags) {
+ super.onProvideAutoFillStructure(structure, flags);
+
+ structure.setSanitized(mCheckedFromResource);
+ }
+
+ @Override
public void autoFill(AutoFillValue value) {
if (!isEnabled()) return;
diff --git a/core/java/android/widget/DatePickerCalendarDelegate.java b/core/java/android/widget/DatePickerCalendarDelegate.java
index f712685..907250a 100755
--- a/core/java/android/widget/DatePickerCalendarDelegate.java
+++ b/core/java/android/widget/DatePickerCalendarDelegate.java
@@ -115,10 +115,10 @@
mDelegator.addView(mContainer);
// Set up header views.
- final ViewGroup header = (ViewGroup) mContainer.findViewById(R.id.date_picker_header);
- mHeaderYear = (TextView) header.findViewById(R.id.date_picker_header_year);
+ final ViewGroup header = mContainer.findViewById(R.id.date_picker_header);
+ mHeaderYear = header.findViewById(R.id.date_picker_header_year);
mHeaderYear.setOnClickListener(mOnHeaderClickListener);
- mHeaderMonthDay = (TextView) header.findViewById(R.id.date_picker_header_date);
+ mHeaderMonthDay = header.findViewById(R.id.date_picker_header_date);
mHeaderMonthDay.setOnClickListener(mOnHeaderClickListener);
// For the sake of backwards compatibility, attempt to extract the text
@@ -154,10 +154,10 @@
a.recycle();
// Set up picker container.
- mAnimator = (ViewAnimator) mContainer.findViewById(R.id.animator);
+ mAnimator = mContainer.findViewById(R.id.animator);
// Set up day picker view.
- mDayPickerView = (DayPickerView) mAnimator.findViewById(R.id.date_picker_day_picker);
+ mDayPickerView = mAnimator.findViewById(R.id.date_picker_day_picker);
mDayPickerView.setFirstDayOfWeek(mFirstDayOfWeek);
mDayPickerView.setMinDate(mMinDate.getTimeInMillis());
mDayPickerView.setMaxDate(mMaxDate.getTimeInMillis());
@@ -165,7 +165,7 @@
mDayPickerView.setOnDaySelectedListener(mOnDaySelectedListener);
// Set up year picker view.
- mYearPickerView = (YearPickerView) mAnimator.findViewById(R.id.date_picker_year_picker);
+ mYearPickerView = mAnimator.findViewById(R.id.date_picker_year_picker);
mYearPickerView.setRange(mMinDate, mMaxDate);
mYearPickerView.setYear(mCurrentDate.get(Calendar.YEAR));
mYearPickerView.setOnYearSelectedListener(mOnYearSelectedListener);
diff --git a/core/java/android/widget/DayPickerPagerAdapter.java b/core/java/android/widget/DayPickerPagerAdapter.java
index 8d5bf8f..63621e1 100644
--- a/core/java/android/widget/DayPickerPagerAdapter.java
+++ b/core/java/android/widget/DayPickerPagerAdapter.java
@@ -225,7 +225,7 @@
public Object instantiateItem(ViewGroup container, int position) {
final View itemView = mInflater.inflate(mLayoutResId, container, false);
- final SimpleMonthView v = (SimpleMonthView) itemView.findViewById(mCalendarViewId);
+ final SimpleMonthView v = itemView.findViewById(mCalendarViewId);
v.setOnDayClickListener(mOnDayClickListener);
v.setMonthTextAppearance(mMonthTextAppearance);
v.setDayOfWeekTextAppearance(mDayOfWeekTextAppearance);
diff --git a/core/java/android/widget/DayPickerViewPager.java b/core/java/android/widget/DayPickerViewPager.java
index a27e022..1704ed7 100644
--- a/core/java/android/widget/DayPickerViewPager.java
+++ b/core/java/android/widget/DayPickerViewPager.java
@@ -137,9 +137,10 @@
}
@Override
- protected View findViewByPredicateTraversal(Predicate<View> predicate, View childToSkip) {
+ protected <T extends View> T findViewByPredicateTraversal(Predicate<View> predicate,
+ View childToSkip) {
if (predicate.test(this)) {
- return this;
+ return (T) this;
}
// Always try the selected view first.
@@ -148,7 +149,7 @@
if (current != childToSkip && current != null) {
final View v = current.findViewByPredicate(predicate);
if (v != null) {
- return v;
+ return (T) v;
}
}
@@ -160,7 +161,7 @@
final View v = child.findViewByPredicate(predicate);
if (v != null) {
- return v;
+ return (T) v;
}
}
}
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index dd3b054..ade03e1 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -2183,6 +2183,11 @@
}
void onTouchUpEvent(MotionEvent event) {
+ if (getSelectionActionModeHelper().resetOriginalSelection(
+ getTextView().getOffsetForPosition(event.getX(), event.getY()))) {
+ return;
+ }
+
boolean selectAllGotFocus = mSelectAllOnFocus && mTextView.didTouchFocusSelect();
hideCursorAndSpanControllers();
stopTextActionMode();
@@ -3916,7 +3921,7 @@
@Override
public void onDestroyActionMode(ActionMode mode) {
// Clear mTextActionMode not to recursively destroy action mode by clearing selection.
- getSelectionActionModeHelper().cancelAsyncTask();
+ getSelectionActionModeHelper().onDestroyActionMode();
mTextActionMode = null;
Callback customCallback = getCustomCallback();
if (customCallback != null) {
diff --git a/core/java/android/widget/ListView.java b/core/java/android/widget/ListView.java
index 46e998a..1c0c4ef 100644
--- a/core/java/android/widget/ListView.java
+++ b/core/java/android/widget/ListView.java
@@ -3740,20 +3740,21 @@
* @removed For internal use only. This should have been hidden.
*/
@Override
- protected View findViewTraversal(@IdRes int id) {
- View v;
- v = super.findViewTraversal(id);
+ protected <T extends View> T findViewTraversal(@IdRes int id) {
+ // First look in our children, then in any header and footer views that
+ // may be scrolled off.
+ View v = super.findViewTraversal(id);
if (v == null) {
v = findViewInHeadersOrFooters(mHeaderViewInfos, id);
if (v != null) {
- return v;
+ return (T) v;
}
v = findViewInHeadersOrFooters(mFooterViewInfos, id);
if (v != null) {
- return v;
+ return (T) v;
}
}
- return v;
+ return (T) v;
}
View findViewInHeadersOrFooters(ArrayList<FixedViewInfo> where, int id) {
@@ -3782,21 +3783,22 @@
* @removed For internal use only. This should have been hidden.
*/
@Override
- protected View findViewWithTagTraversal(Object tag) {
- View v;
- v = super.findViewWithTagTraversal(tag);
+ protected <T extends View> T findViewWithTagTraversal(Object tag) {
+ // First look in our children, then in any header and footer views that
+ // may be scrolled off.
+ View v = super.findViewWithTagTraversal(tag);
if (v == null) {
v = findViewWithTagInHeadersOrFooters(mHeaderViewInfos, tag);
if (v != null) {
- return v;
+ return (T) v;
}
v = findViewWithTagInHeadersOrFooters(mFooterViewInfos, tag);
if (v != null) {
- return v;
+ return (T) v;
}
}
- return v;
+ return (T) v;
}
View findViewWithTagInHeadersOrFooters(ArrayList<FixedViewInfo> where, Object tag) {
@@ -3829,21 +3831,21 @@
* @hide
*/
@Override
- protected View findViewByPredicateTraversal(Predicate<View> predicate, View childToSkip) {
- View v;
- v = super.findViewByPredicateTraversal(predicate, childToSkip);
+ protected <T extends View> T findViewByPredicateTraversal(
+ Predicate<View> predicate, View childToSkip) {
+ View v = super.findViewByPredicateTraversal(predicate, childToSkip);
if (v == null) {
v = findViewByPredicateInHeadersOrFooters(mHeaderViewInfos, predicate, childToSkip);
if (v != null) {
- return v;
+ return (T) v;
}
v = findViewByPredicateInHeadersOrFooters(mFooterViewInfos, predicate, childToSkip);
if (v != null) {
- return v;
+ return (T) v;
}
}
- return v;
+ return (T) v;
}
/**
diff --git a/core/java/android/widget/MediaController.java b/core/java/android/widget/MediaController.java
index 8008637..8e04f1c 100644
--- a/core/java/android/widget/MediaController.java
+++ b/core/java/android/widget/MediaController.java
@@ -257,13 +257,13 @@
.getText(com.android.internal.R.string.lockscreen_transport_play_description);
mPauseDescription = res
.getText(com.android.internal.R.string.lockscreen_transport_pause_description);
- mPauseButton = (ImageButton) v.findViewById(com.android.internal.R.id.pause);
+ mPauseButton = v.findViewById(com.android.internal.R.id.pause);
if (mPauseButton != null) {
mPauseButton.requestFocus();
mPauseButton.setOnClickListener(mPauseListener);
}
- mFfwdButton = (ImageButton) v.findViewById(com.android.internal.R.id.ffwd);
+ mFfwdButton = v.findViewById(com.android.internal.R.id.ffwd);
if (mFfwdButton != null) {
mFfwdButton.setOnClickListener(mFfwdListener);
if (!mFromXml) {
@@ -271,7 +271,7 @@
}
}
- mRewButton = (ImageButton) v.findViewById(com.android.internal.R.id.rew);
+ mRewButton = v.findViewById(com.android.internal.R.id.rew);
if (mRewButton != null) {
mRewButton.setOnClickListener(mRewListener);
if (!mFromXml) {
@@ -280,16 +280,16 @@
}
// By default these are hidden. They will be enabled when setPrevNextListeners() is called
- mNextButton = (ImageButton) v.findViewById(com.android.internal.R.id.next);
+ mNextButton = v.findViewById(com.android.internal.R.id.next);
if (mNextButton != null && !mFromXml && !mListenersSet) {
mNextButton.setVisibility(View.GONE);
}
- mPrevButton = (ImageButton) v.findViewById(com.android.internal.R.id.prev);
+ mPrevButton = v.findViewById(com.android.internal.R.id.prev);
if (mPrevButton != null && !mFromXml && !mListenersSet) {
mPrevButton.setVisibility(View.GONE);
}
- mProgress = (ProgressBar) v.findViewById(com.android.internal.R.id.mediacontroller_progress);
+ mProgress = v.findViewById(com.android.internal.R.id.mediacontroller_progress);
if (mProgress != null) {
if (mProgress instanceof SeekBar) {
SeekBar seeker = (SeekBar) mProgress;
@@ -298,8 +298,8 @@
mProgress.setMax(1000);
}
- mEndTime = (TextView) v.findViewById(com.android.internal.R.id.time);
- mCurrentTime = (TextView) v.findViewById(com.android.internal.R.id.time_current);
+ mEndTime = v.findViewById(com.android.internal.R.id.time);
+ mCurrentTime = v.findViewById(com.android.internal.R.id.time_current);
mFormatBuilder = new StringBuilder();
mFormatter = new Formatter(mFormatBuilder, Locale.getDefault());
diff --git a/core/java/android/widget/RadioGroup.java b/core/java/android/widget/RadioGroup.java
index 76b3813..bba3a11 100644
--- a/core/java/android/widget/RadioGroup.java
+++ b/core/java/android/widget/RadioGroup.java
@@ -24,6 +24,7 @@
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
+import android.view.ViewStructure;
import android.view.autofill.AutoFillManager;
import android.view.autofill.AutoFillType;
import android.view.autofill.AutoFillValue;
@@ -66,6 +67,10 @@
private OnCheckedChangeListener mOnCheckedChangeListener;
private PassThroughHierarchyChangeListener mPassThroughListener;
+ // Indicates whether the child was set from resources or dynamically, so it can be used
+ // to sanitize auto-fill requests.
+ private int mInitialCheckedId = View.NO_ID;
+
/**
* {@inheritDoc}
*/
@@ -89,8 +94,8 @@
int value = attributes.getResourceId(R.styleable.RadioGroup_checkedButton, View.NO_ID);
if (value != View.NO_ID) {
mCheckedId = value;
+ mInitialCheckedId = value;
}
-
final int index = attributes.getInt(com.android.internal.R.styleable.RadioGroup_orientation, VERTICAL);
setOrientation(index);
@@ -411,6 +416,12 @@
// TODO(b/33197203): add unit/CTS tests for auto-fill methods (and make sure they handle enable)
@Override
+ public void onProvideAutoFillStructure(ViewStructure structure, int flags) {
+ super.onProvideAutoFillStructure(structure, flags);
+ structure.setSanitized(mCheckedId == mInitialCheckedId);
+ }
+
+ @Override
public void autoFill(AutoFillValue value) {
if (!isEnabled()) return;
@@ -430,6 +441,15 @@
@Override
public AutoFillValue getAutoFillValue() {
- return isEnabled() ? AutoFillValue.forList(getCheckedRadioButtonId()) : null;
+ if (!isEnabled()) return null;
+
+ final int count = getChildCount();
+ for (int i = 0; i < count; i++) {
+ final View child = getChildAt(i);
+ if (child.getId() == mCheckedId) {
+ return AutoFillValue.forList(i);
+ }
+ }
+ return null;
}
}
diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java
index 359d04e..5505f2f 100644
--- a/core/java/android/widget/RemoteViews.java
+++ b/core/java/android/widget/RemoteViews.java
@@ -1578,7 +1578,7 @@
@Override
public void apply(View root, ViewGroup rootParent, OnClickHandler handler) {
final Context context = root.getContext();
- final ViewGroup target = (ViewGroup) root.findViewById(viewId);
+ final ViewGroup target = root.findViewById(viewId);
if (target == null) return;
if (nestedViews != null) {
// Inflate nested views and add as children
@@ -1757,7 +1757,7 @@
@Override
public void apply(View root, ViewGroup rootParent, OnClickHandler handler) {
- final TextView target = (TextView) root.findViewById(viewId);
+ final TextView target = root.findViewById(viewId);
if (target == null) return;
if (drawablesLoaded) {
if (isRelative) {
@@ -1857,7 +1857,7 @@
@Override
public void apply(View root, ViewGroup rootParent, OnClickHandler handler) {
- final TextView target = (TextView) root.findViewById(viewId);
+ final TextView target = root.findViewById(viewId);
if (target == null) return;
target.setTextSize(units, size);
}
@@ -2045,7 +2045,7 @@
@Override
public void apply(View root, ViewGroup rootParent, OnClickHandler handler) {
- final TextView target = (TextView) root.findViewById(viewId);
+ final TextView target = root.findViewById(viewId);
if (target == null) return;
Drawable[] drawables = isRelative
? target.getCompoundDrawablesRelative()
diff --git a/core/java/android/widget/SelectionActionModeHelper.java b/core/java/android/widget/SelectionActionModeHelper.java
index 770d9ee..6790532 100644
--- a/core/java/android/widget/SelectionActionModeHelper.java
+++ b/core/java/android/widget/SelectionActionModeHelper.java
@@ -54,6 +54,8 @@
private TextClassificationResult mTextClassificationResult;
private AsyncTask mTextClassificationAsyncTask;
+ private final SelectionInfo mSelectionInfo = new SelectionInfo();
+
SelectionActionModeHelper(@NonNull Editor editor) {
mEditor = Preconditions.checkNotNull(editor);
final TextView textView = mEditor.getTextView();
@@ -94,12 +96,12 @@
}
}
- public void cancelAsyncTask() {
- if (mTextClassificationAsyncTask != null) {
- mTextClassificationAsyncTask.cancel(true);
- mTextClassificationAsyncTask = null;
+ public boolean resetOriginalSelection(int textIndex) {
+ if (mSelectionInfo.resetOriginalSelection(textIndex, mEditor.getTextView().getText())) {
+ invalidateActionModeAsync();
+ return true;
}
- mTextClassificationResult = null;
+ return false;
}
@Nullable
@@ -107,12 +109,28 @@
return mTextClassificationResult;
}
+ public void onDestroyActionMode() {
+ mSelectionInfo.onSelectionDestroyed();
+ cancelAsyncTask();
+ }
+
+ private void cancelAsyncTask() {
+ if (mTextClassificationAsyncTask != null) {
+ mTextClassificationAsyncTask.cancel(true);
+ mTextClassificationAsyncTask = null;
+ }
+ mTextClassificationResult = null;
+ }
+
private boolean isNoOpTextClassifier() {
return mEditor.getTextView().getTextClassifier() == TextClassifier.NO_OP;
}
private void startActionMode(@Nullable SelectionResult result) {
- final CharSequence text = mEditor.getTextView().getText();
+ final TextView textView = mEditor.getTextView();
+ final CharSequence text = textView.getText();
+ mSelectionInfo.setOriginalSelection(
+ textView.getSelectionStart(), textView.getSelectionEnd());
if (result != null && text instanceof Spannable) {
Selection.setSelection((Spannable) text, result.mStart, result.mEnd);
mTextClassificationResult = result.mResult;
@@ -124,6 +142,9 @@
if (controller != null) {
controller.show();
}
+ if (result != null) {
+ mSelectionInfo.onSelectionStarted(result.mStart, result.mEnd);
+ }
}
mEditor.setRestartActionModeOnNextRefresh(false);
mTextClassificationAsyncTask = null;
@@ -135,6 +156,8 @@
if (actionMode != null) {
actionMode.invalidate();
}
+ final TextView textView = mEditor.getTextView();
+ mSelectionInfo.onSelectionUpdated(textView.getSelectionStart(), textView.getSelectionEnd());
mTextClassificationAsyncTask = null;
}
@@ -145,6 +168,56 @@
}
/**
+ * Holds information about the selection and uses it to decide on whether or not to update
+ * the selection when resetOriginalSelection is called.
+ * The expected UX here is to allow the user to re-snap the selection back to the original word
+ * that was selected with one tap on that word.
+ */
+ private static final class SelectionInfo {
+
+ private int mOriginalStart;
+ private int mOriginalEnd;
+ private int mSelectionStart;
+ private int mSelectionEnd;
+
+ private boolean mResetOriginal;
+
+ public void setOriginalSelection(int selectionStart, int selectionEnd) {
+ mOriginalStart = selectionStart;
+ mOriginalEnd = selectionEnd;
+ mResetOriginal = false;
+ }
+
+ public void onSelectionStarted(int selectionStart, int selectionEnd) {
+ // Set the reset flag to true if the selection changed.
+ mSelectionStart = selectionStart;
+ mSelectionEnd = selectionEnd;
+ mResetOriginal = mSelectionStart != mOriginalStart || mSelectionEnd != mOriginalEnd;
+ }
+
+ public void onSelectionUpdated(int selectionStart, int selectionEnd) {
+ // If the selection did not change, maintain the reset state. Otherwise, disable reset.
+ mResetOriginal &= selectionStart == mSelectionStart && selectionEnd == mSelectionEnd;
+ }
+
+ public void onSelectionDestroyed() {
+ mResetOriginal = false;
+ }
+
+ public boolean resetOriginalSelection(int textIndex, CharSequence text) {
+ if (mResetOriginal
+ && textIndex >= mOriginalStart && textIndex <= mOriginalEnd
+ && text instanceof Spannable) {
+ Selection.setSelection((Spannable) text, mOriginalStart, mOriginalEnd);
+ // Only allow a reset once.
+ mResetOriginal = false;
+ return true;
+ }
+ return false;
+ }
+ }
+
+ /**
* AsyncTask for running a query on a background thread and returning the result on the
* UiThread. The AsyncTask times out after a specified time, returning a null result if the
* query has not yet returned.
diff --git a/core/java/android/widget/Spinner.java b/core/java/android/widget/Spinner.java
index 28cc693..50c016b 100644
--- a/core/java/android/widget/Spinner.java
+++ b/core/java/android/widget/Spinner.java
@@ -41,9 +41,12 @@
import android.view.PointerIcon;
import android.view.View;
import android.view.ViewGroup;
+import android.view.ViewStructure;
import android.view.ViewTreeObserver;
import android.view.ViewTreeObserver.OnGlobalLayoutListener;
import android.view.accessibility.AccessibilityNodeInfo;
+import android.view.autofill.AutoFillType;
+import android.view.autofill.AutoFillValue;
import android.widget.PopupWindow.OnDismissListener;
import com.android.internal.R;
@@ -784,6 +787,7 @@
return handled;
}
+ @Override
public void onClick(DialogInterface dialog, int which) {
setSelection(which);
dialog.dismiss();
@@ -912,6 +916,42 @@
return super.onResolvePointerIcon(event, pointerIndex);
}
+ // TODO(b/33197203): add unit/CTS tests for auto-fill methods (and make sure they handle enable)
+
+ @Override
+ public void onProvideAutoFillStructure(ViewStructure structure, int flags) {
+ super.onProvideAutoFillStructure(structure, flags);
+ // TODO(b/33197203): implement sanitization so initial value is only sanitized when coming
+ // from resources.
+
+ final int count = getAdapter().getCount();
+ if (count > 0) {
+ final String[] options = new String[count];
+ for (int i = 0; i < count; i++) {
+ options[i] = getAdapter().getItem(i).toString();
+ }
+ structure.setAutoFillOptions(options);
+ }
+ }
+
+ @Override
+ public void autoFill(AutoFillValue value) {
+ if (!isEnabled()) return;
+
+ final int position = value.getListValue();
+ setSelection(position);
+ }
+
+ @Override
+ public AutoFillType getAutoFillType() {
+ return AutoFillType.forList();
+ }
+
+ @Override
+ public AutoFillValue getAutoFillValue() {
+ return isEnabled() ? AutoFillValue.forList(getSelectedItemPosition()) : null;
+ }
+
static class SavedState extends AbsSpinner.SavedState {
boolean showDropdown;
diff --git a/core/java/android/widget/SuggestionsAdapter.java b/core/java/android/widget/SuggestionsAdapter.java
index f833d1b..fbb8993 100644
--- a/core/java/android/widget/SuggestionsAdapter.java
+++ b/core/java/android/widget/SuggestionsAdapter.java
@@ -286,7 +286,7 @@
v.setTag(new ChildViewCache(v));
// Set up icon.
- final ImageView iconRefine = (ImageView) v.findViewById(R.id.edit_query);
+ final ImageView iconRefine = v.findViewById(R.id.edit_query);
iconRefine.setImageResource(mCommitIconResId);
return v;
@@ -304,11 +304,11 @@
public final ImageView mIconRefine;
public ChildViewCache(View v) {
- mText1 = (TextView) v.findViewById(com.android.internal.R.id.text1);
- mText2 = (TextView) v.findViewById(com.android.internal.R.id.text2);
- mIcon1 = (ImageView) v.findViewById(com.android.internal.R.id.icon1);
- mIcon2 = (ImageView) v.findViewById(com.android.internal.R.id.icon2);
- mIconRefine = (ImageView) v.findViewById(com.android.internal.R.id.edit_query);
+ mText1 = v.findViewById(com.android.internal.R.id.text1);
+ mText2 = v.findViewById(com.android.internal.R.id.text2);
+ mIcon1 = v.findViewById(com.android.internal.R.id.icon1);
+ mIcon2 = v.findViewById(com.android.internal.R.id.icon2);
+ mIconRefine = v.findViewById(com.android.internal.R.id.edit_query);
}
}
diff --git a/core/java/android/widget/TabHost.java b/core/java/android/widget/TabHost.java
index 32418cd..7e2cadf 100644
--- a/core/java/android/widget/TabHost.java
+++ b/core/java/android/widget/TabHost.java
@@ -619,7 +619,7 @@
mTabWidget, // tab widget is the parent
false); // no inflate params
- final TextView tv = (TextView) tabIndicator.findViewById(R.id.title);
+ final TextView tv = tabIndicator.findViewById(R.id.title);
tv.setText(mLabel);
if (context.getApplicationInfo().targetSdkVersion <= Build.VERSION_CODES.DONUT) {
@@ -653,8 +653,8 @@
mTabWidget, // tab widget is the parent
false); // no inflate params
- final TextView tv = (TextView) tabIndicator.findViewById(R.id.title);
- final ImageView iconView = (ImageView) tabIndicator.findViewById(R.id.icon);
+ final TextView tv = tabIndicator.findViewById(R.id.title);
+ final ImageView iconView = tabIndicator.findViewById(R.id.icon);
// when icon is gone by default, we're in exclusive mode
final boolean exclusive = iconView.getVisibility() == View.GONE;
diff --git a/core/java/android/widget/TextInputTimePickerView.java b/core/java/android/widget/TextInputTimePickerView.java
index ef91576..0183343 100644
--- a/core/java/android/widget/TextInputTimePickerView.java
+++ b/core/java/android/widget/TextInputTimePickerView.java
@@ -177,15 +177,15 @@
mAmPmSpinner.setVisibility(is24Hour ? View.INVISIBLE : View.VISIBLE);
- mHourEditText.setText(String.format(format, localizedHour));
- mMinuteEditText.setText(String.format(format, minute));
-
if (amOrPm == AM) {
mAmPmSpinner.setSelection(0);
} else {
mAmPmSpinner.setSelection(1);
}
+ mHourEditText.setText(String.format(format, localizedHour));
+ mMinuteEditText.setText(String.format(format, minute));
+
if (mErrorShowing) {
validateInput();
}
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index bf8de38..4937740 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -266,7 +266,7 @@
* @attr ref android.R.styleable#TextView_fontFeatureSettings
* @attr ref android.R.styleable#TextView_breakStrategy
* @attr ref android.R.styleable#TextView_hyphenationFrequency
- * @attr ref android.R.styleable#TextView_autoSizeText
+ * @attr ref android.R.styleable#TextView_autoSizeTextType
* @attr ref android.R.styleable#TextView_autoSizeMinTextSize
* @attr ref android.R.styleable#TextView_autoSizeMaxTextSize
* @attr ref android.R.styleable#TextView_autoSizeStepGranularity
@@ -691,18 +691,24 @@
*/
private int mDeviceProvisionedState = DEVICE_PROVISIONED_UNKNOWN;
- // The TextView does not auto-size text (default).
+ /**
+ * The TextView does not auto-size text (default).
+ */
public static final int AUTO_SIZE_TEXT_TYPE_NONE = 0;
- // The TextView performs uniform horizontal and vertical text size scaling to fit within the
- // container.
+
+ /**
+ * The TextView scales text size both horizontally and vertically to fit within the
+ * container.
+ */
public static final int AUTO_SIZE_TEXT_TYPE_UNIFORM = 1;
+
/** @hide */
@IntDef({AUTO_SIZE_TEXT_TYPE_NONE, AUTO_SIZE_TEXT_TYPE_UNIFORM})
@Retention(RetentionPolicy.SOURCE)
public @interface AutoSizeTextType {}
- // Default minimum size for auto-sizing text in scaled pixels. {@see #setAutoSizeMinTextSize}.
+ // Default minimum size for auto-sizing text in scaled pixels.
private static final int DEFAULT_AUTO_SIZE_MIN_TEXT_SIZE_IN_SP = 12;
- // Default maximum size for auto-sizing text in scaled pixels. {@see #setAutoSizeMaxTextSize}.
+ // Default maximum size for auto-sizing text in scaled pixels.
private static final int DEFAULT_AUTO_SIZE_MAX_TEXT_SIZE_IN_SP = 112;
// Default value for the step size in pixels.
private static final int DEFAULT_AUTO_SIZE_GRANULARITY_IN_PX = 1;
@@ -727,7 +733,7 @@
private boolean mHasPresetAutoSizeValues = false;
// Indicates whether the text was set from resources or dynamically, so it can be used to
- // sanitize auto-fill request.
+ // sanitize auto-fill requests.
private boolean mTextFromResource = false;
/**
@@ -1308,7 +1314,7 @@
mHyphenationFrequency = a.getInt(attr, Layout.HYPHENATION_FREQUENCY_NONE);
break;
- case com.android.internal.R.styleable.TextView_autoSizeText:
+ case com.android.internal.R.styleable.TextView_autoSizeTextType:
mAutoSizeTextType = a.getInt(attr, AUTO_SIZE_TEXT_TYPE_NONE);
break;
@@ -1660,7 +1666,7 @@
* {@link TextView#AUTO_SIZE_TEXT_TYPE_NONE} or
* {@link TextView#AUTO_SIZE_TEXT_TYPE_UNIFORM}
*
- * @attr ref android.R.styleable#TextView_autoSizeText
+ * @attr ref android.R.styleable#TextView_autoSizeTextType
*
* @see #getAutoSizeTextType()
*/
@@ -1709,7 +1715,7 @@
*
* @throws IllegalArgumentException if any of the configuration params are invalid.
*
- * @attr ref android.R.styleable#TextView_autoSizeText
+ * @attr ref android.R.styleable#TextView_autoSizeTextType
* @attr ref android.R.styleable#TextView_autoSizeMinTextSize
* @attr ref android.R.styleable#TextView_autoSizeMaxTextSize
* @attr ref android.R.styleable#TextView_autoSizeStepGranularity
@@ -1753,7 +1759,7 @@
*
* @throws IllegalArgumentException if all of the <code>presetSizes</code> are invalid.
*
- * @attr ref android.R.styleable#TextView_autoSizeText
+ * @attr ref android.R.styleable#TextView_autoSizeTextType
* @attr ref android.R.styleable#TextView_autoSizePresetSizes
*
* @see #setAutoSizeTextTypeWithDefaults(int)
@@ -1806,7 +1812,7 @@
* {@link TextView#AUTO_SIZE_TEXT_TYPE_NONE} or
* {@link TextView#AUTO_SIZE_TEXT_TYPE_UNIFORM}
*
- * @attr ref android.R.styleable#TextView_autoSizeText
+ * @attr ref android.R.styleable#TextView_autoSizeTextType
*
* @see #setAutoSizeTextTypeWithDefaults(int)
* @see #setAutoSizeTextTypeUniformWithConfiguration(int, int, int, int)
@@ -8208,7 +8214,7 @@
// If we have a fixed width, we can just swap in a new text layout
// if the text height stays the same or if the view height is fixed.
- if (((mLayoutParams.width != LayoutParams.WRAP_CONTENT && mLayoutParams.width != 0)
+ if ((mLayoutParams.width != LayoutParams.WRAP_CONTENT
|| (mMaxWidthMode == mMinWidthMode && mMaxWidth == mMinWidth))
&& (mHint == null || mHintLayout != null)
&& (mRight - mLeft - getCompoundPaddingLeft() - getCompoundPaddingRight() > 0)) {
@@ -10329,7 +10335,7 @@
Selection.setSelection((Spannable) text, start, end);
// Make sure selection mode is engaged.
if (mEditor != null) {
- mEditor.startSelectionActionModeAsync();
+ mEditor.startSelectionActionMode();
}
return true;
}
diff --git a/core/java/android/widget/TimePickerClockDelegate.java b/core/java/android/widget/TimePickerClockDelegate.java
index 3a09063..94bd342 100644
--- a/core/java/android/widget/TimePickerClockDelegate.java
+++ b/core/java/android/widget/TimePickerClockDelegate.java
@@ -813,8 +813,12 @@
private final OnValueSelectedListener mOnValueSelectedListener = new OnValueSelectedListener() {
@Override
public void onValueSelected(int pickerType, int newValue, boolean autoAdvance) {
+ boolean valueChanged = false;
switch (pickerType) {
case RadialTimePickerView.HOURS:
+ if (getHour() != newValue) {
+ valueChanged = true;
+ }
final boolean isTransition = mAllowAutoAdvance && autoAdvance;
setHourInternal(newValue, FROM_RADIAL_PICKER, !isTransition);
if (isTransition) {
@@ -825,11 +829,14 @@
}
break;
case RadialTimePickerView.MINUTES:
+ if (getMinute() != newValue) {
+ valueChanged = true;
+ }
setMinuteInternal(newValue, FROM_RADIAL_PICKER);
break;
}
- if (mOnTimeChangedListener != null) {
+ if (mOnTimeChangedListener != null && valueChanged) {
mOnTimeChangedListener.onTimeChanged(mDelegator, getHour(), getMinute());
}
}
diff --git a/core/java/android/widget/TimePickerSpinnerDelegate.java b/core/java/android/widget/TimePickerSpinnerDelegate.java
index 7ef54a5..20a5512 100644
--- a/core/java/android/widget/TimePickerSpinnerDelegate.java
+++ b/core/java/android/widget/TimePickerSpinnerDelegate.java
@@ -86,7 +86,7 @@
inflater.inflate(layoutResourceId, mDelegator, true);
// hour
- mHourSpinner = (NumberPicker) delegator.findViewById(R.id.hour);
+ mHourSpinner = delegator.findViewById(R.id.hour);
mHourSpinner.setOnValueChangedListener(new NumberPicker.OnValueChangeListener() {
public void onValueChange(NumberPicker spinner, int oldVal, int newVal) {
updateInputState();
@@ -100,17 +100,17 @@
onTimeChanged();
}
});
- mHourSpinnerInput = (EditText) mHourSpinner.findViewById(R.id.numberpicker_input);
+ mHourSpinnerInput = mHourSpinner.findViewById(R.id.numberpicker_input);
mHourSpinnerInput.setImeOptions(EditorInfo.IME_ACTION_NEXT);
// divider (only for the new widget style)
- mDivider = (TextView) mDelegator.findViewById(R.id.divider);
+ mDivider = mDelegator.findViewById(R.id.divider);
if (mDivider != null) {
setDividerText();
}
// minute
- mMinuteSpinner = (NumberPicker) mDelegator.findViewById(R.id.minute);
+ mMinuteSpinner = mDelegator.findViewById(R.id.minute);
mMinuteSpinner.setMinValue(0);
mMinuteSpinner.setMaxValue(59);
mMinuteSpinner.setOnLongPressUpdateInterval(100);
@@ -138,7 +138,7 @@
onTimeChanged();
}
});
- mMinuteSpinnerInput = (EditText) mMinuteSpinner.findViewById(R.id.numberpicker_input);
+ mMinuteSpinnerInput = mMinuteSpinner.findViewById(R.id.numberpicker_input);
mMinuteSpinnerInput.setImeOptions(EditorInfo.IME_ACTION_NEXT);
// Get the localized am/pm strings and use them in the spinner.
@@ -173,13 +173,13 @@
onTimeChanged();
}
});
- mAmPmSpinnerInput = (EditText) mAmPmSpinner.findViewById(R.id.numberpicker_input);
+ mAmPmSpinnerInput = mAmPmSpinner.findViewById(R.id.numberpicker_input);
mAmPmSpinnerInput.setImeOptions(EditorInfo.IME_ACTION_DONE);
}
if (isAmPmAtStart()) {
// Move the am/pm view to the beginning
- ViewGroup amPmParent = (ViewGroup) delegator.findViewById(R.id.timePickerLayout);
+ ViewGroup amPmParent = delegator.findViewById(R.id.timePickerLayout);
amPmParent.removeView(amPmView);
amPmParent.addView(amPmView, 0);
// Swap layout margins if needed. They may be not symmetrical (Old Standard Theme
diff --git a/core/java/android/widget/Toast.java b/core/java/android/widget/Toast.java
index 789e60b..bf0601d 100644
--- a/core/java/android/widget/Toast.java
+++ b/core/java/android/widget/Toast.java
@@ -299,7 +299,7 @@
if (mNextView == null) {
throw new RuntimeException("This Toast was not created with Toast.makeText()");
}
- TextView tv = (TextView) mNextView.findViewById(com.android.internal.R.id.message);
+ TextView tv = mNextView.findViewById(com.android.internal.R.id.message);
if (tv == null) {
throw new RuntimeException("This Toast was not created with Toast.makeText()");
}
diff --git a/core/java/android/widget/VideoView.java b/core/java/android/widget/VideoView.java
index b973324..7b2efea 100644
--- a/core/java/android/widget/VideoView.java
+++ b/core/java/android/widget/VideoView.java
@@ -16,11 +16,13 @@
package android.widget;
+import android.annotation.NonNull;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.res.Resources;
import android.graphics.Canvas;
+import android.media.AudioAttributes;
import android.media.AudioManager;
import android.media.Cea708CaptionRenderer;
import android.media.ClosedCaptionRenderer;
@@ -67,6 +69,14 @@
* {@link android.app.Activity#onRestoreInstanceState}.<p>
* Also note that the audio session id (from {@link #getAudioSessionId}) may
* change from its previously returned value when the VideoView is restored.
+ * <p>
+ * By default, VideoView requests audio focus with {@link AudioManager#AUDIOFOCUS_GAIN}. Use
+ * {@link #setAudioFocusRequest(int)} to change this behavior.
+ * <p>
+ * The default {@link AudioAttributes} used during playback have a usage of
+ * {@link AudioAttributes#USAGE_MEDIA} and a content type of
+ * {@link AudioAttributes#CONTENT_TYPE_MOVIE}, use {@link #setAudioAttributes(AudioAttributes)} to
+ * modify them.
*/
public class VideoView extends SurfaceView
implements MediaPlayerControl, SubtitleController.Anchor {
@@ -113,6 +123,9 @@
private boolean mCanPause;
private boolean mCanSeekBack;
private boolean mCanSeekForward;
+ private AudioManager mAudioManager;
+ private int mAudioFocusType = AudioManager.AUDIOFOCUS_GAIN; // legacy focus gain
+ private AudioAttributes mAudioAttributes;
/** Subtitle rendering widget overlaid on top of the video. */
private RenderingWidget mSubtitleWidget;
@@ -138,6 +151,10 @@
mVideoWidth = 0;
mVideoHeight = 0;
+ mAudioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
+ mAudioAttributes = new AudioAttributes.Builder().setUsage(AudioAttributes.USAGE_MEDIA)
+ .setContentType(AudioAttributes.CONTENT_TYPE_MOVIE).build();
+
getHolder().addCallback(mSHCallback);
getHolder().setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
@@ -260,6 +277,41 @@
}
/**
+ * Sets which type of audio focus will be requested during the playback, or configures playback
+ * to not request audio focus. Valid values for focus requests are
+ * {@link AudioManager#AUDIOFOCUS_GAIN}, {@link AudioManager#AUDIOFOCUS_GAIN_TRANSIENT},
+ * {@link AudioManager#AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK}, and
+ * {@link AudioManager#AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE}. Or use
+ * {@link AudioManager#AUDIOFOCUS_NONE} to express that audio focus should not be
+ * requested when playback starts. You can for instance use this when playing a silent animation
+ * through this class, and you don't want to affect other audio applications playing in the
+ * background.
+ * @param focusGain the type of audio focus gain that will be requested, or
+ * {@link AudioManager#AUDIOFOCUS_NONE} to disable the use audio focus during playback.
+ */
+ public void setAudioFocusRequest(int focusGain) {
+ if (focusGain != AudioManager.AUDIOFOCUS_NONE
+ && focusGain != AudioManager.AUDIOFOCUS_GAIN
+ && focusGain != AudioManager.AUDIOFOCUS_GAIN_TRANSIENT
+ && focusGain != AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK
+ && focusGain != AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE) {
+ throw new IllegalArgumentException("Illegal audio focus type " + focusGain);
+ }
+ mAudioFocusType = focusGain;
+ }
+
+ /**
+ * Sets the {@link AudioAttributes} to be used during the playback of the video.
+ * @param attributes non-null <code>AudioAttributes</code>.
+ */
+ public void setAudioAttributes(@NonNull AudioAttributes attributes) {
+ if (attributes == null) {
+ throw new IllegalArgumentException("Illegal null AudioAttributes");
+ }
+ mAudioAttributes = attributes;
+ }
+
+ /**
* Adds an external subtitle source file (from the provided input stream.)
*
* Note that a single external subtitle source may contain multiple or no
@@ -301,8 +353,7 @@
mMediaPlayer = null;
mCurrentState = STATE_IDLE;
mTargetState = STATE_IDLE;
- AudioManager am = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
- am.abandonAudioFocus(null);
+ mAudioManager.abandonAudioFocus(null);
}
}
@@ -315,8 +366,10 @@
// called start() previously
release(false);
- AudioManager am = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
- am.requestAudioFocus(null, AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN);
+ if (mAudioFocusType != AudioManager.AUDIOFOCUS_NONE) {
+ // TODO this should have a focus listener
+ mAudioManager.requestAudioFocus(null, mAudioAttributes, mAudioFocusType, 0 /*flags*/);
+ }
try {
mMediaPlayer = new MediaPlayer();
@@ -345,7 +398,7 @@
mCurrentBufferPercentage = 0;
mMediaPlayer.setDataSource(mContext, mUri, mHeaders);
mMediaPlayer.setDisplay(mSurfaceHolder);
- mMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
+ mMediaPlayer.setAudioAttributes(mAudioAttributes);
mMediaPlayer.setScreenOnWhilePlaying(true);
mMediaPlayer.prepareAsync();
@@ -482,6 +535,9 @@
if (mOnCompletionListener != null) {
mOnCompletionListener.onCompletion(mMediaPlayer);
}
+ if (mAudioFocusType != AudioManager.AUDIOFOCUS_NONE) {
+ mAudioManager.abandonAudioFocus(null);
+ }
}
};
@@ -644,8 +700,9 @@
if (cleartargetstate) {
mTargetState = STATE_IDLE;
}
- AudioManager am = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
- am.abandonAudioFocus(null);
+ if (mAudioFocusType != AudioManager.AUDIOFOCUS_NONE) {
+ mAudioManager.abandonAudioFocus(null);
+ }
}
}
diff --git a/core/java/android/widget/ZoomButtonsController.java b/core/java/android/widget/ZoomButtonsController.java
index 69b79971..1a3ca86 100644
--- a/core/java/android/widget/ZoomButtonsController.java
+++ b/core/java/android/widget/ZoomButtonsController.java
@@ -264,7 +264,7 @@
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
inflater.inflate(com.android.internal.R.layout.zoom_container, container);
- mControls = (ZoomControls) container.findViewById(com.android.internal.R.id.zoomControls);
+ mControls = container.findViewById(com.android.internal.R.id.zoomControls);
mControls.setOnZoomInClickListener(new OnClickListener() {
public void onClick(View v) {
dismissControlsDelayed(ZOOM_CONTROLS_TIMEOUT);
diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java
index 84c8f7a..79301aa 100644
--- a/core/java/com/android/internal/app/ChooserActivity.java
+++ b/core/java/com/android/internal/app/ChooserActivity.java
@@ -23,15 +23,21 @@
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
+import android.content.IntentFilter;
import android.content.IntentSender;
import android.content.IntentSender.SendIntentException;
import android.content.ServiceConnection;
import android.content.SharedPreferences;
import android.content.pm.ActivityInfo;
+import android.content.pm.ApplicationInfo;
import android.content.pm.LabeledIntent;
+import android.content.pm.LauncherApps;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.pm.ParceledListSlice;
import android.content.pm.ResolveInfo;
+import android.content.pm.ShortcutInfo;
+import android.content.pm.ShortcutManager;
import android.database.DataSetObserver;
import android.graphics.Color;
import android.graphics.drawable.Drawable;
@@ -84,6 +90,14 @@
public class ChooserActivity extends ResolverActivity {
private static final String TAG = "ChooserActivity";
+ /**
+ * Boolean extra to change the following behavior: Normally, ChooserActivity finishes itself
+ * in onStop when launched in a new task. If this extra is set to true, we do not finish
+ * ourselves when onStop gets called.
+ */
+ public static final String EXTRA_PRIVATE_RETAIN_IN_ON_STOP
+ = "com.android.internal.app.ChooserActivity.EXTRA_PRIVATE_RETAIN_IN_ON_STOP";
+
private static final boolean DEBUG = false;
private static final int QUERY_TARGET_SERVICE_LIMIT = 5;
@@ -260,6 +274,7 @@
}
mPinnedSharedPrefs = getPinnedSharedPrefs(this);
+ setRetainInOnStop(intent.getBooleanExtra(EXTRA_PRIVATE_RETAIN_IN_ON_STOP, false));
super.onCreate(savedInstanceState, target, title, defaultTitleRes, initialIntents,
null, false);
@@ -347,6 +362,7 @@
mChooserListAdapter.addServiceResults(null, Lists.newArrayList(mCallerChooserTargets));
}
mChooserRowAdapter = new ChooserRowAdapter(mChooserListAdapter);
+ mChooserRowAdapter.updateRowScales();
mChooserRowAdapter.registerDataSetObserver(new OffsetDataSetObserver(adapterView));
adapterView.setAdapter(mChooserRowAdapter);
if (listView != null) {
@@ -833,7 +849,9 @@
return false;
}
intent.setComponent(mChooserTarget.getComponentName());
- intent.putExtras(mChooserTarget.getIntentExtras());
+ if (mChooserTarget.getIntentExtras() != null) {
+ intent.putExtras(mChooserTarget.getIntentExtras());
+ }
// Important: we will ignore the target security checks in ActivityManager
// if and only if the ChooserTarget's target package is the same package
@@ -916,6 +934,8 @@
private static final int MAX_SERVICE_TARGETS = 8;
private static final int MAX_TARGETS_PER_SERVICE = 4;
+ private boolean mAreChooserShortcutsRetrieved;
+
private final List<ChooserTargetInfo> mServiceTargets = new ArrayList<>();
private final List<TargetInfo> mCallerTargets = new ArrayList<>();
private boolean mShowServiceTargets;
@@ -1007,6 +1027,20 @@
if (mServiceTargets != null) {
pruneServiceTargets();
}
+
+ if (DEBUG) Log.d(TAG, "Adding pushed chooser targets");
+
+ if (!mAreChooserShortcutsRetrieved) {
+ LauncherApps launcherApps = getLauncherApps();
+ LauncherApps.ShortcutQuery query = new LauncherApps.ShortcutQuery();
+ query.setIntent(getTargetIntent());
+ query.setQueryFlags(LauncherApps.ShortcutQuery.FLAG_MATCH_CHOOSER);
+ List<ShortcutInfo> shortcuts = launcherApps.getShortcuts(query, UserHandle.SYSTEM);
+ if (DEBUG) Log.d(TAG, "Adding " + shortcuts.size() + " chooser shortcuts");
+ addShortcuts(shortcuts);
+ mAreChooserShortcutsRetrieved = true;
+ }
+
if (DEBUG) Log.d(TAG, "List built querying services");
queryTargetServices(this);
}
@@ -1032,6 +1066,7 @@
public int getServiceTargetCount() {
if (!mShowServiceTargets) {
+ if (DEBUG) Log.d("TAG", "Hiding service targets");
return 0;
}
return Math.min(mServiceTargets.size(), MAX_SERVICE_TARGETS);
@@ -1123,6 +1158,71 @@
notifyDataSetChanged();
}
+ // TODO: Pushed targets need to be scored correctly
+ public void addShortcuts(List<ShortcutInfo> infos) {
+ for (ShortcutInfo info : infos) {
+ List<ChooserTarget> newTargets = new ArrayList<>();
+ final ComponentName cn = info.getActivity();
+ ActivityInfo ai;
+ ResolveInfo ri = new ResolveInfo();
+ if (cn != null) {
+ try {
+ ai = getPackageManager().getActivityInfo(cn, 0);
+ ri.activityInfo = ai;
+ UserManager userManager =
+ (UserManager) getSystemService(Context.USER_SERVICE);
+ ri.iconResourceId = ai.icon;
+ ri.labelRes = ai.labelRes;
+ ri.resolvePackageName = ai.packageName;
+ ri.activityInfo.applicationInfo = new ApplicationInfo(
+ ri.activityInfo.applicationInfo);
+ ri.activityInfo.applicationInfo = ai.applicationInfo;
+ ri.activityInfo.applicationInfo.uid = getUserId();
+ } catch (PackageManager.NameNotFoundException ignored) {
+ if (DEBUG) Log.d(TAG, "Package not found, skipping this shortcut");
+ continue;
+ }
+ }
+
+ DisplayResolveInfo resolveInfo = new DisplayResolveInfo(getTargetIntent(),
+ ri,
+ info.getShortLabel(),
+ info.getLongLabel(),
+ getTargetIntent());
+
+ int bestMatch = 0;
+ ComponentName bestComponent = null;
+ for (int i = 0; i < info.getChooserIntentFilters().length; i++) {
+ int newMatch = info.getChooserIntentFilters()[i]
+ .match(getContentResolver(), getTargetIntent(), false, TAG);
+ if (DEBUG) Log.d(TAG, "A match was found with value: " + newMatch);
+ if (newMatch > bestMatch) {
+ bestMatch = newMatch;
+ bestComponent = info.getChooserComponentNames()[i];
+ }
+ }
+ if (bestMatch == 0) {
+ Log.e(TAG, "Unexpectedly, no match was found for the provided chooser intent");
+ return;
+ }
+
+ Bundle extrasToAdd =
+ info.getChooserExtras() == null ? null: new Bundle(info.getChooserExtras());
+ if (DEBUG) Log.d(TAG, "Adding service target " + info.getShortLabel());
+ newTargets.add(new ChooserTarget(
+ info.getShortLabel(),
+ info.getIcon(),
+ 1,
+ bestComponent,
+ extrasToAdd));
+ addServiceResults(resolveInfo, newTargets);
+ }
+ if (mChooserRowAdapter != null) {
+ mChooserRowAdapter.updateRowScales();
+ }
+ setShowServiceTargets(true);
+ }
+
/**
* Set to true to reveal all service targets at once.
*/
@@ -1237,37 +1337,7 @@
@Override
public void onChanged() {
super.onChanged();
- final int rcount = getServiceTargetRowCount();
- if (mServiceTargetScale == null
- || mServiceTargetScale.length != rcount) {
- RowScale[] old = mServiceTargetScale;
- int oldRCount = old != null ? old.length : 0;
- mServiceTargetScale = new RowScale[rcount];
- if (old != null && rcount > 0) {
- System.arraycopy(old, 0, mServiceTargetScale, 0,
- Math.min(old.length, rcount));
- }
-
- for (int i = rcount; i < oldRCount; i++) {
- old[i].cancelAnimation();
- }
-
- for (int i = oldRCount; i < rcount; i++) {
- final RowScale rs = new RowScale(ChooserRowAdapter.this, 0.f, 1.f)
- .setInterpolator(mInterpolator);
- mServiceTargetScale[i] = rs;
- }
-
- // Start the animations in a separate loop.
- // The process of starting animations will result in
- // binding views to set up initial values, and we must
- // have ALL of the new RowScale objects created above before
- // we get started.
- for (int i = oldRCount; i < rcount; i++) {
- mServiceTargetScale[i].startAnimation();
- }
- }
-
+ updateRowScales();
notifyDataSetChanged();
}
@@ -1284,6 +1354,40 @@
});
}
+ void updateRowScales() {
+ final int rcount = getServiceTargetRowCount();
+ if (mServiceTargetScale == null
+ || mServiceTargetScale.length != rcount) {
+ if (DEBUG) Log.d(TAG, "Row scales need adjusting to " + rcount + " rows.");
+ RowScale[] old = mServiceTargetScale;
+ int oldRCount = old != null ? old.length : 0;
+ mServiceTargetScale = new RowScale[rcount];
+ if (old != null && rcount > 0) {
+ System.arraycopy(old, 0, mServiceTargetScale, 0,
+ Math.min(old.length, rcount));
+ }
+
+ for (int i = rcount; i < oldRCount; i++) {
+ old[i].cancelAnimation();
+ }
+
+ for (int i = oldRCount; i < rcount; i++) {
+ final RowScale rs = new RowScale(ChooserRowAdapter.this, 0.f, 1.f)
+ .setInterpolator(mInterpolator);
+ mServiceTargetScale[i] = rs;
+ }
+
+ // Start the animations in a separate loop.
+ // The process of starting animations will result in
+ // binding views to set up initial values, and we must
+ // have ALL of the new RowScale objects created above before
+ // we get started.
+ for (int i = oldRCount; i < rcount; i++) {
+ mServiceTargetScale[i].startAnimation();
+ }
+ }
+ }
+
private float getRowScale(int rowPosition) {
final int start = getCallerTargetRowCount();
final int end = start + getServiceTargetRowCount();
@@ -1554,6 +1658,10 @@
}
}
+ public LauncherApps getLauncherApps() {
+ return (LauncherApps) getSystemService(Context.LAUNCHER_APPS_SERVICE);
+ }
+
static class ServiceResultInfo {
public final DisplayResolveInfo originalTarget;
public final List<ChooserTarget> resultTargets;
diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java
index 0b1f0aa..3f1c9ad 100644
--- a/core/java/com/android/internal/app/ResolverActivity.java
+++ b/core/java/com/android/internal/app/ResolverActivity.java
@@ -116,6 +116,10 @@
private Runnable mPostListReadyRunnable;
private boolean mRegistered;
+
+ /** See {@link #setRetainInOnStop}. */
+ private boolean mRetainInOnStop;
+
private final PackageMonitor mPackageMonitor = new PackageMonitor() {
@Override public void onSomePackagesChanged() {
mAdapter.handlePackagesChanged();
@@ -502,7 +506,7 @@
}
final Intent intent = getIntent();
if ((intent.getFlags() & FLAG_ACTIVITY_NEW_TASK) != 0 && !isVoiceInteraction()
- && !mResolvingHome) {
+ && !mResolvingHome && !mRetainInOnStop) {
// This resolver is in the unusual situation where it has been
// launched at the top of a new task. We don't let it be added
// to the recent tasks shown to the user, and we need to make sure
@@ -531,16 +535,7 @@
@Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
- if (mSupportsAlwaysUseOption) {
- final int checkedPos = mAdapterView.getCheckedItemPosition();
- final boolean hasValidSelection = checkedPos != ListView.INVALID_POSITION;
- mLastSelected = checkedPos;
- setAlwaysButtonEnabled(hasValidSelection, checkedPos, true);
- mOnceButton.setEnabled(hasValidSelection);
- if (hasValidSelection) {
- mAdapterView.setSelection(checkedPos);
- }
- }
+ resetAlwaysOrOnceButtonBar();
}
private boolean hasManagedProfile() {
@@ -577,7 +572,13 @@
boolean enabled = false;
if (hasValidSelection) {
ResolveInfo ri = mAdapter.resolveInfoForPosition(checkedPos, filtered);
- if (ri.targetUserId == UserHandle.USER_CURRENT) {
+ if (ri == null) {
+ Log.e(TAG, "Invalid position supplied to setAlwaysButtonEnabled");
+ return;
+ } else if (ri.targetUserId != UserHandle.USER_CURRENT) {
+ Log.e(TAG, "Attempted to set selection to resolve info for another user");
+ return;
+ } else {
enabled = true;
}
}
@@ -1029,6 +1030,14 @@
}
/**
+ * If {@code retainInOnStop} is set to true, we will not finish ourselves when onStop gets
+ * called and we are launched in a new task.
+ */
+ protected void setRetainInOnStop(boolean retainInOnStop) {
+ mRetainInOnStop = retainInOnStop;
+ }
+
+ /**
* Check a simple match for the component of two ResolveInfos.
*/
static boolean resolveInfoMatch(ResolveInfo lhs, ResolveInfo rhs) {
diff --git a/core/java/com/android/internal/content/FileSystemProvider.java b/core/java/com/android/internal/content/FileSystemProvider.java
new file mode 100644
index 0000000..3ac5a72
--- /dev/null
+++ b/core/java/com/android/internal/content/FileSystemProvider.java
@@ -0,0 +1,487 @@
+/*
+ * Copyright (C) 2017 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.content;
+
+import android.annotation.CallSuper;
+import android.content.ContentResolver;
+import android.content.Intent;
+import android.content.res.AssetFileDescriptor;
+import android.database.Cursor;
+import android.database.MatrixCursor;
+import android.database.MatrixCursor.RowBuilder;
+import android.graphics.Point;
+import android.net.Uri;
+import android.os.CancellationSignal;
+import android.os.FileObserver;
+import android.os.FileUtils;
+import android.os.Handler;
+import android.os.ParcelFileDescriptor;
+import android.provider.DocumentsContract;
+import android.provider.DocumentsContract.Document;
+import android.provider.DocumentsProvider;
+import android.provider.MediaStore;
+import android.text.TextUtils;
+import android.util.ArrayMap;
+import android.util.Log;
+import android.webkit.MimeTypeMap;
+
+import com.android.internal.annotations.GuardedBy;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * A helper class for {@link android.provider.DocumentsProvider} to perform file operations on local
+ * files.
+ */
+public abstract class FileSystemProvider extends DocumentsProvider {
+
+ private static final String TAG = "FileSystemProvider";
+
+ private static final boolean LOG_INOTIFY = false;
+
+ private String[] mDefaultProjection;
+
+ @GuardedBy("mObservers")
+ private final ArrayMap<File, DirectoryObserver> mObservers = new ArrayMap<>();
+
+ private Handler mHandler;
+
+ protected abstract File getFileForDocId(String docId, boolean visible)
+ throws FileNotFoundException;
+
+ protected abstract String getDocIdForFile(File file) throws FileNotFoundException;
+
+ protected abstract Uri buildNotificationUri(String docId);
+
+ @Override
+ public boolean onCreate() {
+ throw new UnsupportedOperationException(
+ "Subclass should override this and call onCreate(defaultDocumentProjection)");
+ }
+
+ @CallSuper
+ protected void onCreate(String[] defaultProjection) {
+ mHandler = new Handler();
+ mDefaultProjection = defaultProjection;
+ }
+
+ @Override
+ public boolean isChildDocument(String parentDocId, String docId) {
+ try {
+ final File parent = getFileForDocId(parentDocId).getCanonicalFile();
+ final File doc = getFileForDocId(docId).getCanonicalFile();
+ return FileUtils.contains(parent, doc);
+ } catch (IOException e) {
+ throw new IllegalArgumentException(
+ "Failed to determine if " + docId + " is child of " + parentDocId + ": " + e);
+ }
+ }
+
+ protected final List<String> findDocumentPath(File parent, File doc)
+ throws FileNotFoundException {
+
+ if (!doc.exists()) {
+ throw new FileNotFoundException(doc + " is not found.");
+ }
+
+ if (!FileUtils.contains(parent, doc)) {
+ throw new FileNotFoundException(doc + " is not found under " + parent);
+ }
+
+ LinkedList<String> path = new LinkedList<>();
+ while (doc != null && FileUtils.contains(parent, doc)) {
+ path.addFirst(getDocIdForFile(doc));
+
+ doc = doc.getParentFile();
+ }
+
+ return path;
+ }
+
+ @Override
+ public String createDocument(String docId, String mimeType, String displayName)
+ throws FileNotFoundException {
+ displayName = FileUtils.buildValidFatFilename(displayName);
+
+ final File parent = getFileForDocId(docId);
+ if (!parent.isDirectory()) {
+ throw new IllegalArgumentException("Parent document isn't a directory");
+ }
+
+ final File file = FileUtils.buildUniqueFile(parent, mimeType, displayName);
+ if (Document.MIME_TYPE_DIR.equals(mimeType)) {
+ if (!file.mkdir()) {
+ throw new IllegalStateException("Failed to mkdir " + file);
+ }
+ } else {
+ try {
+ if (!file.createNewFile()) {
+ throw new IllegalStateException("Failed to touch " + file);
+ }
+ } catch (IOException e) {
+ throw new IllegalStateException("Failed to touch " + file + ": " + e);
+ }
+ }
+
+ return getDocIdForFile(file);
+ }
+
+ @Override
+ public String renameDocument(String docId, String displayName) throws FileNotFoundException {
+ // Since this provider treats renames as generating a completely new
+ // docId, we're okay with letting the MIME type change.
+ displayName = FileUtils.buildValidFatFilename(displayName);
+
+ final File before = getFileForDocId(docId);
+ final File after = FileUtils.buildUniqueFile(before.getParentFile(), displayName);
+ final File visibleFileBefore = getFileForDocId(docId, true);
+ if (!before.renameTo(after)) {
+ throw new IllegalStateException("Failed to rename to " + after);
+ }
+ removeFromMediaStore(visibleFileBefore);
+
+ final String afterDocId = getDocIdForFile(after);
+ scanFile(getFileForDocId(afterDocId, true));
+
+ if (!TextUtils.equals(docId, afterDocId)) {
+ return afterDocId;
+ } else {
+ return null;
+ }
+ }
+
+ @Override
+ public void deleteDocument(String docId) throws FileNotFoundException {
+ final File file = getFileForDocId(docId);
+ final File visibleFile = getFileForDocId(docId, true);
+
+ final boolean isDirectory = file.isDirectory();
+ if (isDirectory) {
+ FileUtils.deleteContents(file);
+ }
+ if (!file.delete()) {
+ throw new IllegalStateException("Failed to delete " + file);
+ }
+
+ removeFromMediaStore(visibleFile);
+ }
+
+ @Override
+ public String moveDocument(String sourceDocumentId, String sourceParentDocumentId,
+ String targetParentDocumentId)
+ throws FileNotFoundException {
+ final File before = getFileForDocId(sourceDocumentId);
+ final File after = new File(getFileForDocId(targetParentDocumentId), before.getName());
+ final File visibleFileBefore = getFileForDocId(sourceDocumentId, true);
+
+ if (after.exists()) {
+ throw new IllegalStateException("Already exists " + after);
+ }
+ if (!before.renameTo(after)) {
+ throw new IllegalStateException("Failed to move to " + after);
+ }
+
+ // Notify media store to update its content
+ removeFromMediaStore(visibleFileBefore);
+ final String docId = getDocIdForFile(after);
+ scanFile(getFileForDocId(docId, true));
+
+ return docId;
+ }
+
+ private void removeFromMediaStore(File visibleFile) throws FileNotFoundException {
+ if (visibleFile != null) {
+ final ContentResolver resolver = getContext().getContentResolver();
+ final Uri externalUri = MediaStore.Files.getContentUri("external");
+
+ // Remove media store entries for any files inside this directory, using
+ // path prefix match. Logic borrowed from MtpDatabase.
+ if (visibleFile.isDirectory()) {
+ final String path = visibleFile.getAbsolutePath() + "/";
+ resolver.delete(externalUri,
+ "_data LIKE ?1 AND lower(substr(_data,1,?2))=lower(?3)",
+ new String[] { path + "%", Integer.toString(path.length()), path });
+ }
+
+ // Remove media store entry for this exact file.
+ final String path = visibleFile.getAbsolutePath();
+ resolver.delete(externalUri,
+ "_data LIKE ?1 AND lower(_data)=lower(?2)",
+ new String[] { path, path });
+ }
+ }
+
+ @Override
+ public Cursor queryDocument(String documentId, String[] projection)
+ throws FileNotFoundException {
+ final MatrixCursor result = new MatrixCursor(resolveProjection(projection));
+ includeFile(result, documentId, null);
+ return result;
+ }
+
+ @Override
+ public Cursor queryChildDocuments(
+ String parentDocumentId, String[] projection, String sortOrder)
+ throws FileNotFoundException {
+
+ final File parent = getFileForDocId(parentDocumentId);
+ final MatrixCursor result = new DirectoryCursor(
+ resolveProjection(projection), parentDocumentId, parent);
+ for (File file : parent.listFiles()) {
+ includeFile(result, null, file);
+ }
+ return result;
+ }
+
+ /**
+ * Searches documents under the given folder.
+ *
+ * To avoid runtime explosion only returns the at most 23 items.
+ *
+ * @param folder the root folder where recursive search begins
+ * @param query the search condition used to match file names
+ * @param projection projection of the returned cursor
+ * @param exclusion absolute file paths to exclude from result
+ * @return cursor containing search result
+ * @throws FileNotFoundException when root folder doesn't exist or search fails
+ */
+ protected final Cursor querySearchDocuments(
+ File folder, String query, String[] projection, Set<String> exclusion)
+ throws FileNotFoundException {
+
+ query = query.toLowerCase();
+ final MatrixCursor result = new MatrixCursor(resolveProjection(projection));
+ final LinkedList<File> pending = new LinkedList<>();
+ pending.add(folder);
+ while (!pending.isEmpty() && result.getCount() < 24) {
+ final File file = pending.removeFirst();
+ if (file.isDirectory()) {
+ for (File child : file.listFiles()) {
+ pending.add(child);
+ }
+ }
+ if (file.getName().toLowerCase().contains(query)
+ && !exclusion.contains(file.getAbsolutePath())) {
+ includeFile(result, null, file);
+ }
+ }
+ return result;
+ }
+
+ @Override
+ public String getDocumentType(String documentId) throws FileNotFoundException {
+ final File file = getFileForDocId(documentId);
+ return getTypeForFile(file);
+ }
+
+ @Override
+ public ParcelFileDescriptor openDocument(
+ String documentId, String mode, CancellationSignal signal)
+ throws FileNotFoundException {
+ final File file = getFileForDocId(documentId);
+ final File visibleFile = getFileForDocId(documentId, true);
+
+ final int pfdMode = ParcelFileDescriptor.parseMode(mode);
+ if (pfdMode == ParcelFileDescriptor.MODE_READ_ONLY || visibleFile == null) {
+ return ParcelFileDescriptor.open(file, pfdMode);
+ } else {
+ try {
+ // When finished writing, kick off media scanner
+ return ParcelFileDescriptor.open(
+ file, pfdMode, mHandler, (IOException e) -> scanFile(visibleFile));
+ } catch (IOException e) {
+ throw new FileNotFoundException("Failed to open for writing: " + e);
+ }
+ }
+ }
+
+ private void scanFile(File visibleFile) {
+ final Intent intent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
+ intent.setData(Uri.fromFile(visibleFile));
+ getContext().sendBroadcast(intent);
+ }
+
+ @Override
+ public AssetFileDescriptor openDocumentThumbnail(
+ String documentId, Point sizeHint, CancellationSignal signal)
+ throws FileNotFoundException {
+ final File file = getFileForDocId(documentId);
+ return DocumentsContract.openImageThumbnail(file);
+ }
+
+ protected RowBuilder includeFile(MatrixCursor result, String docId, File file)
+ throws FileNotFoundException {
+ if (docId == null) {
+ docId = getDocIdForFile(file);
+ } else {
+ file = getFileForDocId(docId);
+ }
+
+ int flags = 0;
+
+ if (file.canWrite()) {
+ if (file.isDirectory()) {
+ flags |= Document.FLAG_DIR_SUPPORTS_CREATE;
+ flags |= Document.FLAG_SUPPORTS_DELETE;
+ flags |= Document.FLAG_SUPPORTS_RENAME;
+ flags |= Document.FLAG_SUPPORTS_MOVE;
+ } else {
+ flags |= Document.FLAG_SUPPORTS_WRITE;
+ flags |= Document.FLAG_SUPPORTS_DELETE;
+ flags |= Document.FLAG_SUPPORTS_RENAME;
+ flags |= Document.FLAG_SUPPORTS_MOVE;
+ }
+ }
+
+ final String mimeType = getTypeForFile(file);
+ final String displayName = file.getName();
+ if (mimeType.startsWith("image/")) {
+ flags |= Document.FLAG_SUPPORTS_THUMBNAIL;
+ }
+
+ final RowBuilder row = result.newRow();
+ row.add(Document.COLUMN_DOCUMENT_ID, docId);
+ row.add(Document.COLUMN_DISPLAY_NAME, displayName);
+ row.add(Document.COLUMN_SIZE, file.length());
+ row.add(Document.COLUMN_MIME_TYPE, mimeType);
+ row.add(Document.COLUMN_FLAGS, flags);
+
+ // Only publish dates reasonably after epoch
+ long lastModified = file.lastModified();
+ if (lastModified > 31536000000L) {
+ row.add(Document.COLUMN_LAST_MODIFIED, lastModified);
+ }
+
+ // Return the row builder just in case any subclass want to add more stuff to it.
+ return row;
+ }
+
+ private static String getTypeForFile(File file) {
+ if (file.isDirectory()) {
+ return Document.MIME_TYPE_DIR;
+ } else {
+ return getTypeForName(file.getName());
+ }
+ }
+
+ private static String getTypeForName(String name) {
+ final int lastDot = name.lastIndexOf('.');
+ if (lastDot >= 0) {
+ final String extension = name.substring(lastDot + 1).toLowerCase();
+ final String mime = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension);
+ if (mime != null) {
+ return mime;
+ }
+ }
+
+ return "application/octet-stream";
+ }
+
+ protected final File getFileForDocId(String docId) throws FileNotFoundException {
+ return getFileForDocId(docId, false);
+ }
+
+ private String[] resolveProjection(String[] projection) {
+ return projection == null ? mDefaultProjection : projection;
+ }
+
+ private void startObserving(File file, Uri notifyUri) {
+ synchronized (mObservers) {
+ DirectoryObserver observer = mObservers.get(file);
+ if (observer == null) {
+ observer = new DirectoryObserver(
+ file, getContext().getContentResolver(), notifyUri);
+ observer.startWatching();
+ mObservers.put(file, observer);
+ }
+ observer.mRefCount++;
+
+ if (LOG_INOTIFY) Log.d(TAG, "after start: " + observer);
+ }
+ }
+
+ private void stopObserving(File file) {
+ synchronized (mObservers) {
+ DirectoryObserver observer = mObservers.get(file);
+ if (observer == null) return;
+
+ observer.mRefCount--;
+ if (observer.mRefCount == 0) {
+ mObservers.remove(file);
+ observer.stopWatching();
+ }
+
+ if (LOG_INOTIFY) Log.d(TAG, "after stop: " + observer);
+ }
+ }
+
+ private static class DirectoryObserver extends FileObserver {
+ private static final int NOTIFY_EVENTS = ATTRIB | CLOSE_WRITE | MOVED_FROM | MOVED_TO
+ | CREATE | DELETE | DELETE_SELF | MOVE_SELF;
+
+ private final File mFile;
+ private final ContentResolver mResolver;
+ private final Uri mNotifyUri;
+
+ private int mRefCount = 0;
+
+ public DirectoryObserver(File file, ContentResolver resolver, Uri notifyUri) {
+ super(file.getAbsolutePath(), NOTIFY_EVENTS);
+ mFile = file;
+ mResolver = resolver;
+ mNotifyUri = notifyUri;
+ }
+
+ @Override
+ public void onEvent(int event, String path) {
+ if ((event & NOTIFY_EVENTS) != 0) {
+ if (LOG_INOTIFY) Log.d(TAG, "onEvent() " + event + " at " + path);
+ mResolver.notifyChange(mNotifyUri, null, false);
+ }
+ }
+
+ @Override
+ public String toString() {
+ return "DirectoryObserver{file=" + mFile.getAbsolutePath() + ", ref=" + mRefCount + "}";
+ }
+ }
+
+ private class DirectoryCursor extends MatrixCursor {
+ private final File mFile;
+
+ public DirectoryCursor(String[] columnNames, String docId, File file) {
+ super(columnNames);
+
+ final Uri notifyUri = buildNotificationUri(docId);
+ setNotificationUri(getContext().getContentResolver(), notifyUri);
+
+ mFile = file;
+ startObserving(mFile, notifyUri);
+ }
+
+ @Override
+ public void close() {
+ super.close();
+ stopObserving(mFile);
+ }
+ }
+}
diff --git a/core/java/com/android/internal/notification/SystemNotificationChannels.java b/core/java/com/android/internal/notification/SystemNotificationChannels.java
new file mode 100644
index 0000000..c840f26
--- /dev/null
+++ b/core/java/com/android/internal/notification/SystemNotificationChannels.java
@@ -0,0 +1,136 @@
+/*
+ * Copyright (C) 2017 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.notification;
+
+import android.app.Notification;
+import android.app.NotificationChannel;
+import android.app.NotificationManager;
+import android.content.Context;
+import android.provider.Settings;
+
+import com.android.internal.R;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+// Manages the NotificationChannels used by the frameworks itself.
+public class SystemNotificationChannels {
+ public static String VIRTUAL_KEYBOARD = "VIRTUAL_KEYBOARD";
+ public static String PHYSICAL_KEYBOARD = "PHYSICAL_KEYBOARD";
+ public static String SECURITY = "SECURITY";
+ public static String CAR_MODE = "CAR_MODE";
+ public static String ACCOUNT = "ACCOUNT";
+ public static String DEVELOPER = "DEVELOPER";
+ public static String UPDATES = "UPDATES";
+ public static String NETWORK_STATUS = "NETWORK_STATUS";
+ public static String NETWORK_ALERTS = "NETWORK_ALERTS";
+ public static String VPN = "VPN";
+ public static String DEVICE_ADMIN = "DEVICE_ADMIN";
+ public static String ALERTS = "ALERTS";
+ public static String RETAIL_MODE = "RETAIL_MODE";
+ public static String USB = "USB";
+
+ public static void createAll(Context context) {
+ final NotificationManager nm = context.getSystemService(NotificationManager.class);
+ List<NotificationChannel> channelsList = new ArrayList<NotificationChannel>();
+ channelsList.add(new NotificationChannel(
+ VIRTUAL_KEYBOARD,
+ context.getString(R.string.notification_channel_virtual_keyboard),
+ NotificationManager.IMPORTANCE_LOW));
+
+ final NotificationChannel physicalKeyboardChannel = new NotificationChannel(
+ PHYSICAL_KEYBOARD,
+ context.getString(R.string.notification_channel_physical_keyboard),
+ NotificationManager.IMPORTANCE_DEFAULT);
+ physicalKeyboardChannel.setSound(Settings.System.DEFAULT_NOTIFICATION_URI,
+ Notification.AUDIO_ATTRIBUTES_DEFAULT);
+ channelsList.add(physicalKeyboardChannel);
+
+ channelsList.add(new NotificationChannel(
+ SECURITY,
+ context.getString(R.string.notification_channel_security),
+ NotificationManager.IMPORTANCE_LOW));
+
+ channelsList.add(new NotificationChannel(
+ CAR_MODE,
+ context.getString(R.string.notification_channel_car_mode),
+ NotificationManager.IMPORTANCE_LOW));
+
+ channelsList.add(new NotificationChannel(
+ DEVELOPER,
+ context.getString(R.string.notification_channel_developer),
+ NotificationManager.IMPORTANCE_LOW));
+
+ channelsList.add(new NotificationChannel(
+ UPDATES,
+ context.getString(R.string.notification_channel_updates),
+ NotificationManager.IMPORTANCE_LOW));
+
+ channelsList.add(new NotificationChannel(
+ NETWORK_STATUS,
+ context.getString(R.string.notification_channel_network_status),
+ NotificationManager.IMPORTANCE_LOW));
+
+ final NotificationChannel networkAlertsChannel = new NotificationChannel(
+ NETWORK_ALERTS,
+ context.getString(R.string.notification_channel_network_alerts),
+ NotificationManager.IMPORTANCE_HIGH);
+ networkAlertsChannel.setSound(Settings.System.DEFAULT_NOTIFICATION_URI,
+ Notification.AUDIO_ATTRIBUTES_DEFAULT);
+ channelsList.add(networkAlertsChannel);
+
+ channelsList.add(new NotificationChannel(
+ VPN,
+ context.getString(R.string.notification_channel_vpn),
+ NotificationManager.IMPORTANCE_LOW));
+
+ channelsList.add(new NotificationChannel(
+ DEVICE_ADMIN,
+ context.getString(R.string.notification_channel_device_admin),
+ NotificationManager.IMPORTANCE_LOW));
+
+ final NotificationChannel alertsChannel = new NotificationChannel(
+ ALERTS,
+ context.getString(R.string.notification_channel_alerts),
+ NotificationManager.IMPORTANCE_DEFAULT);
+ alertsChannel.setSound(Settings.System.DEFAULT_NOTIFICATION_URI,
+ Notification.AUDIO_ATTRIBUTES_DEFAULT);
+ channelsList.add(alertsChannel);
+
+ channelsList.add(new NotificationChannel(
+ RETAIL_MODE,
+ context.getString(R.string.notification_channel_retail_mode),
+ NotificationManager.IMPORTANCE_LOW));
+
+ channelsList.add(new NotificationChannel(
+ USB,
+ context.getString(R.string.notification_channel_usb),
+ NotificationManager.IMPORTANCE_MIN));
+
+ nm.createNotificationChannels(channelsList);
+ createAccountChannelForPackage(context.getPackageName(), context);
+ }
+
+ public static void createAccountChannelForPackage(String pkg, Context context) {
+ final NotificationManager nm = context.getSystemService(NotificationManager.class);
+ nm.createNotificationChannelsForPackage(pkg, Arrays.asList(new NotificationChannel(
+ ACCOUNT,
+ context.getString(R.string.notification_channel_account),
+ NotificationManager.IMPORTANCE_LOW)));
+ }
+
+ private SystemNotificationChannels() {}
+}
diff --git a/core/java/com/android/internal/util/ParcelableString.java b/core/java/com/android/internal/util/ParcelableString.java
deleted file mode 100644
index 6bd856f..0000000
--- a/core/java/com/android/internal/util/ParcelableString.java
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright 2014, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.util;
-
-import android.os.Parcel;
-import android.os.Parcelable;
-
-/**
- * Helper class to adapt a simple String to cases where a Parcelable is expected.
- * @hide
- */
-public class ParcelableString implements Parcelable {
- public String string;
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- @Override
- public void writeToParcel(Parcel out, int flags) {
- out.writeString(string);
- }
-
- public static final Parcelable.Creator<ParcelableString> CREATOR =
- new Parcelable.Creator<ParcelableString>() {
- @Override
- public ParcelableString createFromParcel(Parcel in) {
- ParcelableString ret = new ParcelableString();
- ret.string = in.readString();
- return ret;
- }
- @Override
- public ParcelableString[] newArray(int size) {
- return new ParcelableString[size];
- }
- };
-}
\ No newline at end of file
diff --git a/core/java/com/android/internal/util/Predicate.java b/core/java/com/android/internal/util/Predicate.java
index bc6d6b3..1b5eaff 100644
--- a/core/java/com/android/internal/util/Predicate.java
+++ b/core/java/com/android/internal/util/Predicate.java
@@ -25,7 +25,10 @@
* <p/>
* Implementors of Predicate which may cause side effects upon evaluation are
* strongly encouraged to state this fact clearly in their API documentation.
+ *
+ * @deprecated Use {@code java.util.function.Predicate} instead.
*/
+@Deprecated
public interface Predicate<T> {
boolean apply(T t);
diff --git a/core/java/com/android/internal/util/StateMachine.java b/core/java/com/android/internal/util/StateMachine.java
index be10608df..d67cef3 100644
--- a/core/java/com/android/internal/util/StateMachine.java
+++ b/core/java/com/android/internal/util/StateMachine.java
@@ -23,6 +23,8 @@
import android.text.TextUtils;
import android.util.Log;
+import com.android.internal.annotations.VisibleForTesting;
+
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.io.StringWriter;
@@ -1495,7 +1497,7 @@
}
/**
- * @return number of log records
+ * @return the number of log records currently readable
*/
public final int getLogRecSize() {
// mSmHandler can be null if the state machine has quit.
@@ -1505,6 +1507,17 @@
}
/**
+ * @return the number of log records we can store
+ */
+ @VisibleForTesting
+ public final int getLogRecMaxSize() {
+ // mSmHandler can be null if the state machine has quit.
+ SmHandler smh = mSmHandler;
+ if (smh == null) return 0;
+ return smh.mLogRecords.mMaxSize;
+ }
+
+ /**
* @return the total number of records processed
*/
public final int getLogRecCount() {
diff --git a/core/java/com/android/internal/view/IInputConnectionWrapper.java b/core/java/com/android/internal/view/IInputConnectionWrapper.java
index 555263d..28291ae 100644
--- a/core/java/com/android/internal/view/IInputConnectionWrapper.java
+++ b/core/java/com/android/internal/view/IInputConnectionWrapper.java
@@ -496,6 +496,7 @@
} finally {
args.recycle();
}
+ return;
}
case DO_REQUEST_UPDATE_CURSOR_ANCHOR_INFO: {
SomeArgs args = (SomeArgs)msg.obj;
diff --git a/core/java/com/android/internal/view/SurfaceCallbackHelper.java b/core/java/com/android/internal/view/SurfaceCallbackHelper.java
index 5b6a82c..507b673 100644
--- a/core/java/com/android/internal/view/SurfaceCallbackHelper.java
+++ b/core/java/com/android/internal/view/SurfaceCallbackHelper.java
@@ -17,14 +17,11 @@
package com.android.internal.view;
import android.os.RemoteException;
-import android.view.IWindow;
-import android.view.IWindowSession;
import android.view.Surface;
import android.view.SurfaceHolder;
public class SurfaceCallbackHelper {
- IWindowSession mSession;
- IWindow.Stub mWindow;
+ Runnable mRunnable;
int mFinishDrawingCollected = 0;
int mFinishDrawingExpected = 0;
@@ -37,26 +34,18 @@
if (mFinishDrawingCollected < mFinishDrawingExpected) {
return;
}
- try {
- mSession.finishDrawing(mWindow);
- } catch (RemoteException e) {
- }
+ mRunnable.run();
}
}
};
- public SurfaceCallbackHelper(IWindowSession session,
- IWindow.Stub window) {
- mSession = session;
- mWindow = window;
+ public SurfaceCallbackHelper(Runnable callbacksCollected) {
+ mRunnable = callbacksCollected;
}
public void dispatchSurfaceRedrawNeededAsync(SurfaceHolder holder, SurfaceHolder.Callback callbacks[]) {
if (callbacks == null || callbacks.length == 0) {
- try {
- mSession.finishDrawing(mWindow);
- } catch (RemoteException e) {
- }
+ mRunnable.run();
return;
}
diff --git a/core/java/com/android/internal/view/menu/CascadingMenuPopup.java b/core/java/com/android/internal/view/menu/CascadingMenuPopup.java
index 69e974c..1de0af6 100644
--- a/core/java/com/android/internal/view/menu/CascadingMenuPopup.java
+++ b/core/java/com/android/internal/view/menu/CascadingMenuPopup.java
@@ -388,14 +388,22 @@
final boolean showOnRight = nextMenuPosition == HORIZ_POSITION_RIGHT;
mLastPosition = nextMenuPosition;
- final int[] tempLocation = new int[2];
+ // A popup anchored to mAnchorView with (0,0) offset would be shown at this position.
+ final int[] offsetOrigin = new int[2];
+ mAnchorView.getLocationOnScreen(offsetOrigin);
+ offsetOrigin[1] += mAnchorView.getHeight();
- // This popup menu will be positioned relative to the top-left edge
- // of the view representing its parent menu.
- parentView.getLocationInWindow(tempLocation);
- final int parentOffsetLeft = parentInfo.window.getHorizontalOffset() + tempLocation[0];
- final int parentOffsetTop = parentInfo.window.getVerticalOffset() + tempLocation[1];
+ final int[] parentViewScreenLocation = new int[2];
+ parentView.getLocationOnScreen(parentViewScreenLocation);
+ // Translate the parent view location into the offset coordinate space.
+ // If used as horizontal/vertical offsets, these values would position the submenu
+ // at the exact same position as the parent item.
+ final int parentOffsetLeft = parentViewScreenLocation[0] - offsetOrigin[0];
+ final int parentOffsetTop = parentViewScreenLocation[1] - offsetOrigin[1];
+
+ // Adjust the horizontal offset to display the submenu to the right or to the left
+ // of the parent item.
// By now, mDropDownGravity is the resolved absolute gravity, so
// this should work in both LTR and RTL.
final int x;
@@ -412,11 +420,10 @@
x = parentOffsetLeft - menuWidth;
}
}
-
popupWindow.setHorizontalOffset(x);
- final int y = parentOffsetTop;
- popupWindow.setVerticalOffset(y);
+ // Use the same vertical offset as the parent item.
+ popupWindow.setVerticalOffset(parentOffsetTop);
} else {
if (mHasXOffset) {
popupWindow.setHorizontalOffset(mXOffset);
diff --git a/core/java/com/android/internal/view/menu/ListMenuItemView.java b/core/java/com/android/internal/view/menu/ListMenuItemView.java
index 43005e6..919cf99 100644
--- a/core/java/com/android/internal/view/menu/ListMenuItemView.java
+++ b/core/java/com/android/internal/view/menu/ListMenuItemView.java
@@ -115,7 +115,6 @@
setEnabled(itemData.isEnabled());
setSubMenuArrowVisible(itemData.hasSubMenu());
setContentDescription(itemData.getContentDescription());
- setTooltipText(itemData.getTooltipText());
}
public void setForceShowIcon(boolean forceShow) {
diff --git a/core/java/com/android/internal/widget/FloatingToolbar.java b/core/java/com/android/internal/widget/FloatingToolbar.java
index 817b186..79b0cd1 100644
--- a/core/java/com/android/internal/widget/FloatingToolbar.java
+++ b/core/java/com/android/internal/widget/FloatingToolbar.java
@@ -1195,6 +1195,8 @@
}
setButtonTagAndClickListener(menuItemButton, menuItem);
+ // Set tooltips for main panel items, but not overflow items (b/35726766).
+ menuItemButton.setTooltipText(menuItem.getTooltipText());
mMainPanel.addView(menuItemButton);
final ViewGroup.LayoutParams params = menuItemButton.getLayoutParams();
params.width = menuItemButtonWidth + extraPadding / 2;
@@ -1635,7 +1637,6 @@
buttonText.setPaddingRelative(iconTextSpacing, 0, 0, 0);
}
}
- menuItemButton.setTooltipText(menuItem.getTooltipText());
final CharSequence contentDescription = menuItem.getContentDescription();
if (TextUtils.isEmpty(contentDescription)) {
menuItemButton.setContentDescription(menuItem.getTitle());
diff --git a/core/java/com/android/internal/widget/LockPatternView.java b/core/java/com/android/internal/widget/LockPatternView.java
index ae2e0ac..cc1c65e 100644
--- a/core/java/com/android/internal/widget/LockPatternView.java
+++ b/core/java/com/android/internal/widget/LockPatternView.java
@@ -278,7 +278,8 @@
public LockPatternView(Context context, AttributeSet attrs) {
super(context, attrs);
- TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.LockPatternView);
+ TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.LockPatternView,
+ R.attr.lockPatternStyle, R.style.Widget_LockPatternView);
final String aspect = a.getString(R.styleable.LockPatternView_aspect);
@@ -298,12 +299,9 @@
mPathPaint.setAntiAlias(true);
mPathPaint.setDither(true);
- mRegularColor = context.getColor(R.color.lock_pattern_view_regular_color);
- mErrorColor = context.getColor(R.color.lock_pattern_view_error_color);
- mSuccessColor = context.getColor(R.color.lock_pattern_view_success_color);
- mRegularColor = a.getColor(R.styleable.LockPatternView_regularColor, mRegularColor);
- mErrorColor = a.getColor(R.styleable.LockPatternView_errorColor, mErrorColor);
- mSuccessColor = a.getColor(R.styleable.LockPatternView_successColor, mSuccessColor);
+ mRegularColor = a.getColor(R.styleable.LockPatternView_regularColor, 0);
+ mErrorColor = a.getColor(R.styleable.LockPatternView_errorColor, 0);
+ mSuccessColor = a.getColor(R.styleable.LockPatternView_successColor, 0);
int pathColor = a.getColor(R.styleable.LockPatternView_pathColor, mRegularColor);
mPathPaint.setColor(pathColor);
diff --git a/core/java/com/android/internal/widget/ResolverDrawerLayout.java b/core/java/com/android/internal/widget/ResolverDrawerLayout.java
index e84cc27..e224b17 100644
--- a/core/java/com/android/internal/widget/ResolverDrawerLayout.java
+++ b/core/java/com/android/internal/widget/ResolverDrawerLayout.java
@@ -748,6 +748,10 @@
final int widthSpec = MeasureSpec.makeMeasureSpec(widthSize, MeasureSpec.EXACTLY);
final int heightSpec = MeasureSpec.makeMeasureSpec(heightSize, MeasureSpec.EXACTLY);
final int widthPadding = getPaddingLeft() + getPaddingRight();
+
+ // Currently we allot more height than is really needed so that the entirety of the
+ // sheet may be pulled up.
+ // TODO: Restrict the height here to be the right value.
int heightUsed = getPaddingTop() + getPaddingBottom();
// Measure always-show children first.
@@ -757,7 +761,7 @@
final LayoutParams lp = (LayoutParams) child.getLayoutParams();
if (lp.alwaysShow && child.getVisibility() != GONE) {
measureChildWithMargins(child, widthSpec, widthPadding, heightSpec, heightUsed);
- heightUsed += getHeightUsed(child);
+ heightUsed += child.getMeasuredHeight();
}
}
@@ -769,7 +773,7 @@
final LayoutParams lp = (LayoutParams) child.getLayoutParams();
if (!lp.alwaysShow && child.getVisibility() != GONE) {
measureChildWithMargins(child, widthSpec, widthPadding, heightSpec, heightUsed);
- heightUsed += getHeightUsed(child);
+ heightUsed += child.getMeasuredHeight();
}
}
@@ -785,36 +789,6 @@
setMeasuredDimension(sourceWidth, heightSize);
}
- private int getHeightUsed(View child) {
- // This method exists because we're taking a fast path at measuring ListViews that
- // lets us get away with not doing the more expensive wrap_content measurement which
- // imposes double child view measurement costs. If we're looking at a ListView, we can
- // check against the lowest child view plus padding and margin instead of the actual
- // measured height of the ListView. This lets the ListView hang off the edge when
- // all of the content would fit on-screen.
-
- int heightUsed = child.getMeasuredHeight();
- if (child instanceof AbsListView) {
- final AbsListView lv = (AbsListView) child;
- final int lvPaddingBottom = lv.getPaddingBottom();
-
- int lowest = 0;
- for (int i = 0, N = lv.getChildCount(); i < N; i++) {
- final int bottom = lv.getChildAt(i).getBottom() + lvPaddingBottom;
- if (bottom > lowest) {
- lowest = bottom;
- }
- }
-
- if (lowest < heightUsed) {
- heightUsed = lowest;
- }
- }
-
- final LayoutParams lp = (LayoutParams) child.getLayoutParams();
- return lp.topMargin + heightUsed + lp.bottomMargin;
- }
-
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
final int width = getWidth();
diff --git a/core/java/com/android/internal/widget/WatchHeaderListView.java b/core/java/com/android/internal/widget/WatchHeaderListView.java
index 7e91537..0654454 100644
--- a/core/java/com/android/internal/widget/WatchHeaderListView.java
+++ b/core/java/com/android/internal/widget/WatchHeaderListView.java
@@ -91,13 +91,14 @@
}
@Override
- protected View findViewByPredicateTraversal(Predicate<View> predicate, View childToSkip) {
+ protected <T extends View> T findViewByPredicateTraversal(
+ Predicate<View> predicate, View childToSkip) {
View v = super.findViewByPredicateTraversal(predicate, childToSkip);
if (v == null && mTopPanel != null && mTopPanel != childToSkip
&& !mTopPanel.isRootNamespace()) {
- return mTopPanel.findViewByPredicate(predicate);
+ return (T) mTopPanel.findViewByPredicate(predicate);
}
- return v;
+ return (T) v;
}
@Override
diff --git a/core/java/com/android/server/SystemConfig.java b/core/java/com/android/server/SystemConfig.java
index 3d012bf..67f9f8f 100644
--- a/core/java/com/android/server/SystemConfig.java
+++ b/core/java/com/android/server/SystemConfig.java
@@ -59,6 +59,7 @@
private static final int ALLOW_LIBS = 0x02;
private static final int ALLOW_PERMISSIONS = 0x04;
private static final int ALLOW_APP_CONFIGS = 0x08;
+ private static final int ALLOW_PRIVAPP_PERMISSIONS = 0x10;
private static final int ALLOW_ALL = ~0;
// Group-ids that are given to all packages as read from etc/permissions/*.xml.
@@ -225,6 +226,13 @@
// Read configuration from the old permissions dir
readPermissions(Environment.buildPath(
Environment.getRootDirectory(), "etc", "permissions"), ALLOW_ALL);
+ // Allow Vendor to customize system configs around libs, features, permissions and apps
+ int vendorPermissionFlag = ALLOW_LIBS | ALLOW_FEATURES | ALLOW_PERMISSIONS |
+ ALLOW_APP_CONFIGS;
+ readPermissions(Environment.buildPath(
+ Environment.getVendorDirectory(), "etc", "sysconfig"), vendorPermissionFlag);
+ readPermissions(Environment.buildPath(
+ Environment.getVendorDirectory(), "etc", "permissions"), vendorPermissionFlag);
// Allow ODM to customize system configs around libs, features and apps
int odmPermissionFlag = ALLOW_LIBS | ALLOW_FEATURES | ALLOW_APP_CONFIGS;
readPermissions(Environment.buildPath(
@@ -313,6 +321,7 @@
boolean allowFeatures = (permissionFlag & ALLOW_FEATURES) != 0;
boolean allowPermissions = (permissionFlag & ALLOW_PERMISSIONS) != 0;
boolean allowAppConfigs = (permissionFlag & ALLOW_APP_CONFIGS) != 0;
+ boolean allowPrivappPermissions = (permissionFlag & ALLOW_PRIVAPP_PERMISSIONS) != 0;
while (true) {
XmlUtils.nextElement(parser);
if (parser.getEventType() == XmlPullParser.END_DOCUMENT) {
@@ -553,7 +562,7 @@
associatedPkgs.add(pkgname);
}
XmlUtils.skipCurrentTag(parser);
- } else if ("privapp-permissions".equals(name) && allowAppConfigs) {
+ } else if ("privapp-permissions".equals(name) && allowPrivappPermissions) {
readPrivAppPermissions(parser);
} else {
XmlUtils.skipCurrentTag(parser);
diff --git a/core/jni/Android.mk b/core/jni/Android.mk
index 0c07192..cb60c62 100644
--- a/core/jni/Android.mk
+++ b/core/jni/Android.mk
@@ -220,7 +220,6 @@
external/skia/src/effects \
external/skia/src/image \
external/skia/src/images \
- external/skia/src/utils \
external/sqlite/dist \
external/sqlite/android \
external/tremor/Tremor \
@@ -284,11 +283,16 @@
libhidltransport \
libhwbinder \
libvintf \
+ libnativewindow \
LOCAL_SHARED_LIBRARIES += \
libhwui \
libdl \
+# our headers include libnativewindow's public headers
+LOCAL_EXPORT_SHARED_LIBRARY_HEADERS := \
+ libnativewindow \
+
# we need to access the private Bionic header
# <bionic_tls.h> in com_google_android_gles_jni_GLImpl.cpp
LOCAL_C_INCLUDES += bionic/libc/private
diff --git a/core/jni/android/graphics/Bitmap.cpp b/core/jni/android/graphics/Bitmap.cpp
index 3ca455d..c348cc5 100755
--- a/core/jni/android/graphics/Bitmap.cpp
+++ b/core/jni/android/graphics/Bitmap.cpp
@@ -643,7 +643,7 @@
if (!bitmap.get()) {
return NULL;
}
- return createBitmap(env, bitmap.release(), kBitmapCreateFlag_None);
+ return createBitmap(env, bitmap.release(), getPremulBitmapCreateFlags(isMutable));
}
SkColorType dstCT = GraphicsJNI::legacyBitmapConfigToColorType(dstConfigHandle);
@@ -1306,7 +1306,7 @@
doThrowRE(env, "Could not copy a hardware bitmap.");
return NULL;
}
- return createBitmap(env, allocator.getStorageObjAndReset(), kBitmapCreateFlag_None);
+ return createBitmap(env, allocator.getStorageObjAndReset(), getPremulBitmapCreateFlags(false));
}
static jobject Bitmap_createHardwareBitmap(JNIEnv* env, jobject, jobject graphicBuffer) {
@@ -1316,7 +1316,7 @@
ALOGW("failed to create hardware bitmap from graphic buffer");
return NULL;
}
- return bitmap::createBitmap(env, bitmap.release(), android::bitmap::kBitmapCreateFlag_None);
+ return bitmap::createBitmap(env, bitmap.release(), getPremulBitmapCreateFlags(false));
}
static jobject Bitmap_createGraphicBufferHandle(JNIEnv* env, jobject, jlong bitmapPtr) {
diff --git a/core/jni/android/graphics/BitmapFactory.cpp b/core/jni/android/graphics/BitmapFactory.cpp
index 30d6337..417ef8a0 100644
--- a/core/jni/android/graphics/BitmapFactory.cpp
+++ b/core/jni/android/graphics/BitmapFactory.cpp
@@ -8,7 +8,6 @@
#include "SkBRDAllocator.h"
#include "SkFrontBufferedStream.h"
#include "SkMath.h"
-#include "SkOpts.h"
#include "SkPixelRef.h"
#include "SkStream.h"
#include "SkUtils.h"
@@ -229,45 +228,6 @@
needsFineScale(fullSize.height(), decodedSize.height(), sampleSize);
}
-static inline SkAlphaType computeDecodeAlphaType(SkColorType colorType, SkAlphaType alphaType) {
-#ifndef ANDROID_ENABLE_LINEAR_BLENDING
- // Skia premultiplies linearly. Until the framework enables linear blending,
- // it expects a legacy premultiply.
- if (kPremul_SkAlphaType == alphaType && kRGBA_F16_SkColorType != colorType) {
- return kUnpremul_SkAlphaType;
- }
-#endif
-
- return alphaType;
-}
-
-static inline void premultiplyIfNecessary(SkBitmap* bitmap, SkPMColor* colorPtr, int* colorCount,
- SkAlphaType alphaType, bool requireUnpremultiplied) {
-#ifndef ANDROID_ENABLE_LINEAR_BLENDING
- if (kUnpremul_SkAlphaType != alphaType || requireUnpremultiplied) {
- return;
- }
-
- switch (bitmap->colorType()) {
- case kN32_SkColorType:
- for (int y = 0; y < bitmap->height(); y++) {
- SkOpts::RGBA_to_rgbA(bitmap->getAddr32(0, y), bitmap->getAddr32(0, y),
- bitmap->width());
- }
-
- return;
- case kIndex_8_SkColorType:
- SkOpts::RGBA_to_rgbA(colorPtr, colorPtr, *colorCount);
- return;
- default:
- // kRGBA_F16 will be premultiplied by the codec if necessary.
- // kGray_8 (alias kAlpha_8) and k565 are opaque.
- LOG_ALWAYS_FATAL("Should be unreachable - no need for legacy premultiply.");
- return;
- }
-#endif
-}
-
static jobject doDecode(JNIEnv* env, SkStreamRewindable* stream, jobject padding, jobject options) {
// This function takes ownership of the input stream. Since the SkAndroidCodec
// will take ownership of the stream, we don't necessarily need to take ownership
@@ -450,15 +410,13 @@
}
SkAlphaType alphaType = codec->computeOutputAlphaType(requireUnpremultiplied);
- SkAlphaType decodeAlphaType = computeDecodeAlphaType(decodeColorType, alphaType);
const SkImageInfo decodeInfo = SkImageInfo::Make(size.width(), size.height(),
- decodeColorType, decodeAlphaType, codec->computeOutputColorSpace(decodeColorType));
-
- SkImageInfo bitmapInfo = decodeInfo.makeAlphaType(alphaType);
+ decodeColorType, alphaType, codec->computeOutputColorSpace(decodeColorType));
// For wide gamut images, we will leave the color space on the SkBitmap. Otherwise,
// use the default.
+ SkImageInfo bitmapInfo = decodeInfo;
sk_sp<SkColorSpace> srgb =
SkColorSpace::MakeRGB(SkColorSpace::kSRGB_RenderTargetGamma,
SkColorSpace::kSRGB_Gamut,
@@ -502,8 +460,6 @@
default:
return nullObjectReturn("codec->getAndroidPixels() failed.");
}
- premultiplyIfNecessary(&decodingBitmap, colorPtr, colorCount, decodeAlphaType,
- requireUnpremultiplied);
jbyteArray ninePatchChunk = NULL;
if (peeker.mPatch != NULL) {
diff --git a/core/jni/android/graphics/FontFamily.cpp b/core/jni/android/graphics/FontFamily.cpp
index c090a75..49024b6 100644
--- a/core/jni/android/graphics/FontFamily.cpp
+++ b/core/jni/android/graphics/FontFamily.cpp
@@ -63,27 +63,27 @@
return 0;
}
NativeFamilyBuilder* builder = reinterpret_cast<NativeFamilyBuilder*>(builderPtr);
- minikin::FontFamily* family = new minikin::FontFamily(
- builder->langId, builder->variant, std::move(builder->fonts));
+ FontFamilyWrapper* family = new FontFamilyWrapper(
+ std::make_shared<minikin::FontFamily>(
+ builder->langId, builder->variant, std::move(builder->fonts)));
delete builder;
return reinterpret_cast<jlong>(family);
}
static void FontFamily_abort(jlong builderPtr) {
NativeFamilyBuilder* builder = reinterpret_cast<NativeFamilyBuilder*>(builderPtr);
- minikin::Font::clearElementsWithLock(&builder->fonts);
delete builder;
}
static void FontFamily_unref(jlong familyPtr) {
- minikin::FontFamily* fontFamily = reinterpret_cast<minikin::FontFamily*>(familyPtr);
- fontFamily->Unref();
+ FontFamilyWrapper* family = reinterpret_cast<FontFamilyWrapper*>(familyPtr);
+ delete family;
}
static void addSkTypeface(jlong builderPtr, sk_sp<SkTypeface> face, const void* fontData,
size_t fontSize, int ttcIndex, jint givenWeight, jboolean givenItalic) {
- minikin::MinikinFont* minikinFont =
- new MinikinFontSkia(std::move(face), fontData, fontSize, ttcIndex,
+ std::shared_ptr<minikin::MinikinFont> minikinFont =
+ std::make_shared<MinikinFontSkia>(std::move(face), fontData, fontSize, ttcIndex,
std::vector<minikin::FontVariation>());
NativeFamilyBuilder* builder = reinterpret_cast<NativeFamilyBuilder*>(builderPtr);
int weight = givenWeight / 100;
@@ -96,8 +96,8 @@
}
}
- builder->fonts.push_back(minikin::Font(minikinFont, minikin::FontStyle(weight, italic)));
- minikinFont->Unref();
+ builder->fonts.push_back(minikin::Font(
+ std::move(minikinFont), minikin::FontStyle(weight, italic)));
}
static void release_global_ref(const void* /*data*/, void* context) {
@@ -208,13 +208,12 @@
ALOGE("addFont failed to create font, invalid request");
return false;
}
- minikin::MinikinFont* minikinFont =
- new MinikinFontSkia(std::move(face), fontPtr, fontSize, ttcIndex,
+ std::shared_ptr<minikin::MinikinFont> minikinFont =
+ std::make_shared<MinikinFontSkia>(std::move(face), fontPtr, fontSize, ttcIndex,
std::vector<minikin::FontVariation>());
NativeFamilyBuilder* builder = reinterpret_cast<NativeFamilyBuilder*>(builderPtr);
- builder->fonts.push_back(minikin::Font(minikinFont,
+ builder->fonts.push_back(minikin::Font(std::move(minikinFont),
minikin::FontStyle(weight / 100, isItalic)));
- minikinFont->Unref();
return true;
}
diff --git a/core/jni/android/graphics/FontUtils.h b/core/jni/android/graphics/FontUtils.h
index 8f44b1e..9eaaa49 100644
--- a/core/jni/android/graphics/FontUtils.h
+++ b/core/jni/android/graphics/FontUtils.h
@@ -18,9 +18,19 @@
#define _ANDROID_GRAPHICS_FONT_UTILS_H_
#include <jni.h>
+#include <memory>
+
+namespace minikin {
+class FontFamily;
+} // namespace minikin
namespace android {
+struct FontFamilyWrapper {
+ FontFamilyWrapper(std::shared_ptr<minikin::FontFamily>&& family) : family(family) {}
+ std::shared_ptr<minikin::FontFamily> family;
+};
+
// Utility wrapper for java.util.List
class ListHelper {
public:
diff --git a/core/jni/android/graphics/Paint.cpp b/core/jni/android/graphics/Paint.cpp
index bdf79d3..1846237 100644
--- a/core/jni/android/graphics/Paint.cpp
+++ b/core/jni/android/graphics/Paint.cpp
@@ -300,8 +300,8 @@
static void getTextPath(JNIEnv* env, Paint* paint, Typeface* typeface, const jchar* text,
jint count, jint bidiFlags, jfloat x, jfloat y, SkPath* path) {
- minikin::Layout layout;
- MinikinUtils::doLayout(&layout, paint, bidiFlags, typeface, text, 0, count, count);
+ minikin::Layout layout = MinikinUtils::doLayout(
+ paint, bidiFlags, typeface, text, 0, count, count);
size_t nGlyphs = layout.nGlyphs();
uint16_t* glyphs = new uint16_t[nGlyphs];
SkPoint* pos = new SkPoint[nGlyphs];
@@ -344,8 +344,8 @@
SkRect r;
SkIRect ir;
- minikin::Layout layout;
- MinikinUtils::doLayout(&layout, &paint, bidiFlags, typeface, text, 0, count, count);
+ minikin::Layout layout = MinikinUtils::doLayout(
+ &paint, bidiFlags, typeface, text, 0, count, count);
minikin::MinikinRect rect;
layout.getBounds(&rect);
r.fLeft = rect.mLeft;
@@ -459,9 +459,8 @@
nChars++;
prevCp = cp;
}
- minikin::Layout layout;
- MinikinUtils::doLayout(&layout, paint, bidiFlags, typeface, str.get(), 0, str.size(),
- str.size());
+ minikin::Layout layout = MinikinUtils::doLayout(
+ paint, bidiFlags, typeface, str.get(), 0, str.size(), str.size());
size_t nGlyphs = countNonSpaceGlyphs(layout);
if (nGlyphs != 1 && nChars > 1) {
// multiple-character input, and was not a ligature
@@ -480,8 +479,8 @@
// since ZZ is reserved for unknown or invalid territory.
// U+1F1FF (REGIONAL INDICATOR SYMBOL LETTER Z) is \uD83C\uDDFF in UTF16.
static const jchar ZZ_FLAG_STR[] = { 0xD83C, 0xDDFF, 0xD83C, 0xDDFF };
- minikin::Layout zzLayout;
- MinikinUtils::doLayout(&zzLayout, paint, bidiFlags, typeface, ZZ_FLAG_STR, 0, 4, 4);
+ minikin::Layout zzLayout = MinikinUtils::doLayout(
+ paint, bidiFlags, typeface, ZZ_FLAG_STR, 0, 4, 4);
if (zzLayout.nGlyphs() != 1 || layoutContainsNotdef(zzLayout)) {
// The font collection doesn't have a glyph for unknown flag. Just return true.
return true;
diff --git a/core/jni/android/graphics/Typeface.cpp b/core/jni/android/graphics/Typeface.cpp
index 0a0fce3e..0cdc74f 100644
--- a/core/jni/android/graphics/Typeface.cpp
+++ b/core/jni/android/graphics/Typeface.cpp
@@ -67,9 +67,7 @@
static void Typeface_unref(JNIEnv* env, jobject obj, jlong faceHandle) {
Typeface* face = reinterpret_cast<Typeface*>(faceHandle);
- if (face != NULL) {
- face->unref();
- }
+ delete face;
}
static jint Typeface_getStyle(JNIEnv* env, jobject obj, jlong faceHandle) {
@@ -79,12 +77,13 @@
static jlong Typeface_createFromArray(JNIEnv *env, jobject, jlongArray familyArray) {
ScopedLongArrayRO families(env, familyArray);
- std::vector<minikin::FontFamily*> familyVec;
+ std::vector<std::shared_ptr<minikin::FontFamily>> familyVec;
+ familyVec.reserve(families.size());
for (size_t i = 0; i < families.size(); i++) {
- minikin::FontFamily* family = reinterpret_cast<minikin::FontFamily*>(families[i]);
- familyVec.push_back(family);
+ FontFamilyWrapper* family = reinterpret_cast<FontFamilyWrapper*>(families[i]);
+ familyVec.emplace_back(family->family);
}
- return reinterpret_cast<jlong>(Typeface::createFromFamilies(familyVec));
+ return reinterpret_cast<jlong>(Typeface::createFromFamilies(std::move(familyVec)));
}
static void Typeface_setDefault(JNIEnv *env, jobject, jlong faceHandle) {
diff --git a/core/jni/android_hardware_HardwareBuffer.cpp b/core/jni/android_hardware_HardwareBuffer.cpp
index 5f0664b..b91bd5c 100644
--- a/core/jni/android_hardware_HardwareBuffer.cpp
+++ b/core/jni/android_hardware_HardwareBuffer.cpp
@@ -26,15 +26,17 @@
#include <android_runtime/android_hardware_HardwareBuffer.h>
#include <android_runtime/AndroidRuntime.h>
#include <android_runtime/Log.h>
+#include <private/android/AHardwareBufferHelpers.h>
#include <binder/Parcel.h>
+
+#include <ui/GraphicBuffer.h>
#include <gui/IGraphicBufferAlloc.h>
#include <gui/ISurfaceComposer.h>
-#include <hardware/gralloc1.h>
-#include <ui/GraphicBuffer.h>
-
#include <private/gui/ComposerService.h>
+#include <hardware/gralloc1.h>
+
#include "core_jni_helpers.h"
using namespace android;
@@ -44,7 +46,7 @@
// ----------------------------------------------------------------------------
// Debug
-static const bool kDebugGraphicBuffer = false;
+static constexpr bool kDebugGraphicBuffer = false;
// ----------------------------------------------------------------------------
// Types
@@ -64,15 +66,6 @@
sp<GraphicBuffer> buffer;
};
-
-// ----------------------------------------------------------------------------
-// Helper functions
-// ----------------------------------------------------------------------------
-
-static inline bool containsBits(uint64_t mask, uint64_t bitsToCheck) {
- return (mask & bitsToCheck) == bitsToCheck;
-}
-
// ----------------------------------------------------------------------------
// HardwareBuffer lifecycle
// ----------------------------------------------------------------------------
@@ -99,8 +92,8 @@
}
uint64_t producerUsage = 0;
uint64_t consumerUsage = 0;
- android_hardware_HardwareBuffer_convertToGrallocUsageBits(usage, 0, &producerUsage,
- &consumerUsage);
+ android_hardware_HardwareBuffer_convertToGrallocUsageBits(&producerUsage, &consumerUsage, usage,
+ 0);
status_t error;
sp<GraphicBuffer> buffer(alloc->createGraphicBuffer(width, height, pixelFormat,
layers, producerUsage, consumerUsage,
@@ -121,8 +114,7 @@
delete wrapper;
}
-static jlong android_hardware_HardwareBuffer_getNativeFinalizer(JNIEnv* env,
- jobject clazz) {
+static jlong android_hardware_HardwareBuffer_getNativeFinalizer(JNIEnv* env, jobject clazz) {
return static_cast<jlong>(reinterpret_cast<uintptr_t>(&destroyWrapper));
}
@@ -163,8 +155,11 @@
static jlong android_hardware_HardwareBuffer_getUsage(JNIEnv* env,
jobject clazz, jlong nativeObject) {
GraphicBuffer* buffer = GraphicBufferWrapper_to_GraphicBuffer(nativeObject);
- return android_hardware_HardwareBuffer_convertFromGrallocUsageBits(
+ uint64_t usage0 = 0;
+ uint64_t usage1 = 0;
+ android_hardware_HardwareBuffer_convertFromGrallocUsageBits(&usage0, &usage1,
buffer->getUsage(), buffer->getUsage());
+ return usage0;
}
// ----------------------------------------------------------------------------
@@ -203,7 +198,8 @@
if (env->IsInstanceOf(hardwareBufferObj, gHardwareBufferClassInfo.clazz)) {
GraphicBuffer* buffer = GraphicBufferWrapper_to_GraphicBuffer(
env->GetLongField(hardwareBufferObj, gHardwareBufferClassInfo.mNativeObject));
- return reinterpret_cast<AHardwareBuffer*>(buffer);
+ return AHardwareBuffer_from_GraphicBuffer(buffer);
+
} else {
return nullptr;
}
@@ -211,7 +207,7 @@
jobject android_hardware_HardwareBuffer_createFromAHardwareBuffer(
JNIEnv* env, AHardwareBuffer* hardwareBuffer) {
- GraphicBuffer* buffer = reinterpret_cast<GraphicBuffer*>(hardwareBuffer);
+ GraphicBuffer* buffer = AHardwareBuffer_to_GraphicBuffer(hardwareBuffer);
GraphicBufferWrapper* wrapper = new GraphicBufferWrapper(buffer);
jobject hardwareBufferObj = env->NewObject(gHardwareBufferClassInfo.clazz,
gHardwareBufferClassInfo.ctor, reinterpret_cast<jlong>(wrapper));
@@ -228,103 +224,21 @@
}
uint32_t android_hardware_HardwareBuffer_convertFromPixelFormat(uint32_t format) {
- switch (format) {
- case HAL_PIXEL_FORMAT_RGBA_8888:
- return AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM;
- case HAL_PIXEL_FORMAT_RGBX_8888:
- return AHARDWAREBUFFER_FORMAT_R8G8B8X8_UNORM;
- case HAL_PIXEL_FORMAT_RGB_565:
- return AHARDWAREBUFFER_FORMAT_R5G6B5_UNORM;
- case HAL_PIXEL_FORMAT_RGB_888:
- return AHARDWAREBUFFER_FORMAT_R8G8B8_UNORM;
- case HAL_PIXEL_FORMAT_RGBA_FP16:
- return AHARDWAREBUFFER_FORMAT_R16G16B16A16_SFLOAT;
- case HAL_PIXEL_FORMAT_RGBA_1010102:
- return AHARDWAREBUFFER_FORMAT_A2R10G10B10_UNORM_PACK32;
- case HAL_PIXEL_FORMAT_BLOB:
- return AHARDWAREBUFFER_FORMAT_BLOB;
- default:
- ALOGE("Unknown pixel format %u", format);
- return 0;
- }
+ return AHardwareBuffer_convertFromPixelFormat(format);
}
uint32_t android_hardware_HardwareBuffer_convertToPixelFormat(uint32_t format) {
- switch (format) {
- case AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM:
- return HAL_PIXEL_FORMAT_RGBA_8888;
- case AHARDWAREBUFFER_FORMAT_R8G8B8X8_UNORM:
- return HAL_PIXEL_FORMAT_RGBX_8888;
- case AHARDWAREBUFFER_FORMAT_R5G6B5_UNORM:
- return HAL_PIXEL_FORMAT_RGB_565;
- case AHARDWAREBUFFER_FORMAT_R8G8B8_UNORM:
- return HAL_PIXEL_FORMAT_RGB_888;
- case AHARDWAREBUFFER_FORMAT_R16G16B16A16_SFLOAT:
- return HAL_PIXEL_FORMAT_RGBA_FP16;
- case AHARDWAREBUFFER_FORMAT_A2R10G10B10_UNORM_PACK32:
- return HAL_PIXEL_FORMAT_RGBA_1010102;
- case AHARDWAREBUFFER_FORMAT_BLOB:
- return HAL_PIXEL_FORMAT_BLOB;
- default:
- ALOGE("Unknown AHardwareBuffer format %u", format);
- return 0;
- }
+ return AHardwareBuffer_convertToPixelFormat(format);
}
-void android_hardware_HardwareBuffer_convertToGrallocUsageBits(uint64_t usage0,
- uint64_t usage1, uint64_t* outProducerUsage,
- uint64_t* outConsumerUsage) {
- *outProducerUsage = 0;
- *outConsumerUsage = 0;
- if (containsBits(usage0, AHARDWAREBUFFER_USAGE0_CPU_READ))
- *outConsumerUsage |= GRALLOC1_CONSUMER_USAGE_CPU_READ;
- if (containsBits(usage0, AHARDWAREBUFFER_USAGE0_CPU_READ_OFTEN))
- *outConsumerUsage |= GRALLOC1_CONSUMER_USAGE_CPU_READ_OFTEN;
- if (containsBits(usage0, AHARDWAREBUFFER_USAGE0_CPU_WRITE))
- *outProducerUsage |= GRALLOC1_PRODUCER_USAGE_CPU_WRITE;
- if (containsBits(usage0, AHARDWAREBUFFER_USAGE0_CPU_WRITE_OFTEN))
- *outProducerUsage |= GRALLOC1_PRODUCER_USAGE_CPU_WRITE_OFTEN;
- if (containsBits(usage0, AHARDWAREBUFFER_USAGE0_GPU_SAMPLED_IMAGE))
- *outConsumerUsage |= GRALLOC1_CONSUMER_USAGE_GPU_TEXTURE;
- if (containsBits(usage0, AHARDWAREBUFFER_USAGE0_GPU_COLOR_OUTPUT))
- *outProducerUsage |= GRALLOC1_PRODUCER_USAGE_GPU_RENDER_TARGET;
- // Not sure what this should be.
- //if (containsBits(usage0, AHARDWAREBUFFER_USAGE0_GPU_CUBEMAP)) bits |= 0;
- if (containsBits(usage0, AHARDWAREBUFFER_USAGE0_GPU_DATA_BUFFER))
- *outConsumerUsage |= GRALLOC1_CONSUMER_USAGE_GPU_DATA_BUFFER;
- if (containsBits(usage0, AHARDWAREBUFFER_USAGE0_VIDEO_ENCODE))
- *outConsumerUsage |= GRALLOC1_CONSUMER_USAGE_VIDEO_ENCODER;
- if (containsBits(usage0, AHARDWAREBUFFER_USAGE0_PROTECTED_CONTENT))
- *outProducerUsage |= GRALLOC1_PRODUCER_USAGE_PROTECTED;
- if (containsBits(usage0, AHARDWAREBUFFER_USAGE0_SENSOR_DIRECT_DATA))
- *outProducerUsage |= GRALLOC1_PRODUCER_USAGE_SENSOR_DIRECT_DATA;
+void android_hardware_HardwareBuffer_convertToGrallocUsageBits(uint64_t* outProducerUsage,
+ uint64_t* outConsumerUsage, uint64_t usage0, uint64_t usage1) {
+ AHardwareBuffer_convertToGrallocUsageBits(outProducerUsage, outConsumerUsage, usage0, usage1);
}
-uint64_t android_hardware_HardwareBuffer_convertFromGrallocUsageBits(
- uint64_t producerUsage, uint64_t consumerUsage) {
- uint64_t bits = 0;
- if (containsBits(consumerUsage, GRALLOC1_CONSUMER_USAGE_CPU_READ))
- bits |= AHARDWAREBUFFER_USAGE0_CPU_READ;
- if (containsBits(consumerUsage, GRALLOC1_CONSUMER_USAGE_CPU_READ_OFTEN))
- bits |= AHARDWAREBUFFER_USAGE0_CPU_READ_OFTEN;
- if (containsBits(producerUsage, GRALLOC1_PRODUCER_USAGE_CPU_WRITE))
- bits |= AHARDWAREBUFFER_USAGE0_CPU_WRITE;
- if (containsBits(producerUsage, GRALLOC1_PRODUCER_USAGE_CPU_WRITE_OFTEN))
- bits |= AHARDWAREBUFFER_USAGE0_CPU_WRITE_OFTEN;
- if (containsBits(consumerUsage, GRALLOC1_CONSUMER_USAGE_GPU_TEXTURE))
- bits |= AHARDWAREBUFFER_USAGE0_GPU_SAMPLED_IMAGE;
- if (containsBits(producerUsage, GRALLOC1_PRODUCER_USAGE_GPU_RENDER_TARGET))
- bits |= AHARDWAREBUFFER_USAGE0_GPU_COLOR_OUTPUT;
- if (containsBits(consumerUsage, GRALLOC1_CONSUMER_USAGE_GPU_DATA_BUFFER))
- bits |= AHARDWAREBUFFER_USAGE0_GPU_DATA_BUFFER;
- if (containsBits(consumerUsage, GRALLOC1_CONSUMER_USAGE_VIDEO_ENCODER))
- bits |= AHARDWAREBUFFER_USAGE0_VIDEO_ENCODE;
- if (containsBits(producerUsage, GRALLOC1_PRODUCER_USAGE_PROTECTED))
- bits |= AHARDWAREBUFFER_USAGE0_PROTECTED_CONTENT;
- if (containsBits(producerUsage, GRALLOC1_PRODUCER_USAGE_SENSOR_DIRECT_DATA))
- bits |= AHARDWAREBUFFER_USAGE0_SENSOR_DIRECT_DATA;
-
- return bits;
+void android_hardware_HardwareBuffer_convertFromGrallocUsageBits(uint64_t* outUsage0,
+ uint64_t* outUsage1, uint64_t producerUsage, uint64_t consumerUsage) {
+ AHardwareBuffer_convertFromGrallocUsageBits(outUsage0, outUsage1, producerUsage, consumerUsage);
}
} // namespace android
@@ -336,19 +250,21 @@
const char* const kClassPathName = "android/hardware/HardwareBuffer";
static const JNINativeMethod gMethods[] = {
- { "nCreateHardwareBuffer", "(IIIIJ)J", (void*) android_hardware_HardwareBuffer_create },
- { "nGetNativeFinalizer", "()J", (void*) android_hardware_HardwareBuffer_getNativeFinalizer },
+ { "nCreateHardwareBuffer", "(IIIIJ)J",
+ (void*) android_hardware_HardwareBuffer_create },
+ { "nGetNativeFinalizer", "()J",
+ (void*) android_hardware_HardwareBuffer_getNativeFinalizer },
{ "nWriteHardwareBufferToParcel", "(JLandroid/os/Parcel;)V",
(void*) android_hardware_HardwareBuffer_write },
{ "nReadHardwareBufferFromParcel", "(Landroid/os/Parcel;)J",
(void*) android_hardware_HardwareBuffer_read },
// --------------- @FastNative ----------------------
- { "nGetWidth", "(J)I", (void*) android_hardware_HardwareBuffer_getWidth },
- { "nGetHeight", "(J)I", (void*) android_hardware_HardwareBuffer_getHeight },
- { "nGetFormat", "(J)I", (void*) android_hardware_HardwareBuffer_getFormat },
- { "nGetLayers", "(J)I", (void*) android_hardware_HardwareBuffer_getLayers },
- { "nGetUsage", "(J)J", (void*) android_hardware_HardwareBuffer_getUsage },
+ { "nGetWidth", "(J)I", (void*) android_hardware_HardwareBuffer_getWidth },
+ { "nGetHeight", "(J)I", (void*) android_hardware_HardwareBuffer_getHeight },
+ { "nGetFormat", "(J)I", (void*) android_hardware_HardwareBuffer_getFormat },
+ { "nGetLayers", "(J)I", (void*) android_hardware_HardwareBuffer_getLayers },
+ { "nGetUsage", "(J)J", (void*) android_hardware_HardwareBuffer_getUsage },
};
int register_android_hardware_HardwareBuffer(JNIEnv* env) {
diff --git a/core/jni/android_os_Debug.cpp b/core/jni/android_os_Debug.cpp
index eaf9e91..4322105 100644
--- a/core/jni/android_os_Debug.cpp
+++ b/core/jni/android_os_Debug.cpp
@@ -1021,17 +1021,13 @@
env->ReleaseStringCritical(fileName, str);
}
- int fd = open(fileName8.string(), O_CREAT | O_WRONLY | O_NOFOLLOW, 0666); /* -rw-rw-rw- */
+ int fd = open(fileName8.string(), O_CREAT | O_WRONLY | O_NOFOLLOW | O_CLOEXEC | O_APPEND, 0666);
if (fd < 0) {
fprintf(stderr, "Can't open %s: %s\n", fileName8.string(), strerror(errno));
return;
}
- if (lseek(fd, 0, SEEK_END) < 0) {
- fprintf(stderr, "lseek: %s\n", strerror(errno));
- } else {
- dump_backtrace_to_file_timeout(pid, fd, timeoutSecs);
- }
+ dump_backtrace_to_file_timeout(pid, fd, timeoutSecs);
close(fd);
}
diff --git a/core/jni/android_os_seccomp.cpp b/core/jni/android_os_seccomp.cpp
index 45d5061..dd5622d 100644
--- a/core/jni/android_os_seccomp.cpp
+++ b/core/jni/android_os_seccomp.cpp
@@ -14,219 +14,11 @@
* limitations under the License.
*/
-#include "JNIHelp.h"
#include "core_jni_helpers.h"
#include "JniConstants.h"
#include "utils/Log.h"
-#include "utils/misc.h"
-
-#if defined __arm__ || defined __aarch64__
-
-#include <vector>
-
-#include <sys/prctl.h>
-
-#include <linux/unistd.h>
-#include <linux/audit.h>
-#include <linux/filter.h>
-#include <linux/seccomp.h>
-
#include "seccomp_policy.h"
-#define syscall_nr (offsetof(struct seccomp_data, nr))
-#define arch_nr (offsetof(struct seccomp_data, arch))
-
-typedef std::vector<sock_filter> filter;
-
-// We want to keep the below inline functions for debugging and future
-// development even though they are not all sed currently.
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wunused-function"
-
-static inline void Kill(filter& f) {
- f.push_back(BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_KILL));
-}
-
-static inline void Trap(filter& f) {
- f.push_back(BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_TRAP));
-}
-
-static inline void Error(filter& f, __u16 retcode) {
- f.push_back(BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ERRNO + retcode));
-}
-
-inline static void Trace(filter& f) {
- f.push_back(BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_TRACE));
-}
-
-inline static void Allow(filter& f) {
- f.push_back(BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW));
-}
-
-#pragma clang diagnostic pop
-
-inline static void AllowSyscall(filter& f, __u32 num) {
- f.push_back(BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, num, 0, 1));
- Allow(f);
-}
-
-inline static void ExamineSyscall(filter& f) {
- f.push_back(BPF_STMT(BPF_LD|BPF_W|BPF_ABS, syscall_nr));
-}
-
-inline static int SetValidateArchitectureJumpTarget(size_t offset, filter& f) {
- size_t jump_length = f.size() - offset - 1;
- auto u8_jump_length = (__u8) jump_length;
- if (u8_jump_length != jump_length) {
- ALOGE("Can't set jump greater than 255 - actual jump is %zu",
- jump_length);
- return -1;
- }
- f[offset] = BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, AUDIT_ARCH_ARM, u8_jump_length, 0);
- return 0;
-}
-
-inline static size_t ValidateArchitectureAndJumpIfNeeded(filter& f) {
- f.push_back(BPF_STMT(BPF_LD|BPF_W|BPF_ABS, arch_nr));
-
- f.push_back(BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, AUDIT_ARCH_AARCH64, 2, 0));
- f.push_back(BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, AUDIT_ARCH_ARM, 1, 0));
- Trap(f);
- return f.size() - 2;
-}
-
-static bool install_filter(filter const& f) {
- struct sock_fprog prog = {
- (unsigned short) f.size(),
- (struct sock_filter*) &f[0],
- };
-
- if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog) < 0) {
- ALOGE("SECCOMP: Could not set seccomp filter of size %zu: %s", f.size(), strerror(errno));
- return false;
- }
-
- ALOGI("SECCOMP: Global filter of size %zu installed", f.size());
- return true;
-}
-
-bool set_seccomp_filter() {
- filter f;
-
- // Note that for mixed 64/32 bit architectures, ValidateArchitecture inserts a
- // jump that must be changed to point to the start of the 32-bit policy
- // 32 bit syscalls will not hit the policy between here and the call to SetJump
- auto offset_to_32bit_filter =
- ValidateArchitectureAndJumpIfNeeded(f);
-
- // 64-bit filter
- ExamineSyscall(f);
-
- // arm64-only filter - autogenerated from bionic syscall usage
- for (size_t i = 0; i < arm64_filter_size; ++i)
- f.push_back(arm64_filter[i]);
-
- // Syscalls needed to boot Android
- AllowSyscall(f, 41); // __NR_pivot_root
- AllowSyscall(f, 31); // __NR_ioprio_get
- AllowSyscall(f, 30); // __NR_ioprio_set
- AllowSyscall(f, 178); // __NR_gettid
- AllowSyscall(f, 98); // __NR_futex
- AllowSyscall(f, 220); // __NR_clone
- AllowSyscall(f, 139); // __NR_rt_sigreturn
- AllowSyscall(f, 240); // __NR_rt_tgsigqueueinfo
- AllowSyscall(f, 128); // __NR_restart_syscall
- AllowSyscall(f, 278); // __NR_getrandom
-
- // Needed for performance tools
- AllowSyscall(f, 241); // __NR_perf_event_open
-
- // Needed for strace
- AllowSyscall(f, 130); // __NR_tkill
-
- // Needed for kernel to restart syscalls
- AllowSyscall(f, 128); // __NR_restart_syscall
-
- // b/35034743
- AllowSyscall(f, 267); // __NR_syncfs
-
- // b/34763393
- AllowSyscall(f, 277); // __NR_seccomp
-
- Trap(f);
-
- if (SetValidateArchitectureJumpTarget(offset_to_32bit_filter, f) != 0)
- return -1;
-
- // 32-bit filter
- ExamineSyscall(f);
-
- // arm32 filter - autogenerated from bionic syscall usage
- for (size_t i = 0; i < arm_filter_size; ++i)
- f.push_back(arm_filter[i]);
-
- // Syscalls needed to boot android
- AllowSyscall(f, 120); // __NR_clone
- AllowSyscall(f, 240); // __NR_futex
- AllowSyscall(f, 119); // __NR_sigreturn
- AllowSyscall(f, 173); // __NR_rt_sigreturn
- AllowSyscall(f, 363); // __NR_rt_tgsigqueueinfo
- AllowSyscall(f, 224); // __NR_gettid
-
- // Syscalls needed to run Chrome
- AllowSyscall(f, 383); // __NR_seccomp - needed to start Chrome
- AllowSyscall(f, 384); // __NR_getrandom - needed to start Chrome
-
- // Syscalls needed to run GFXBenchmark
- AllowSyscall(f, 190); // __NR_vfork
-
- // Needed for strace
- AllowSyscall(f, 238); // __NR_tkill
-
- // Needed for kernel to restart syscalls
- AllowSyscall(f, 0); // __NR_restart_syscall
-
- // Needed for debugging 32-bit Chrome
- AllowSyscall(f, 42); // __NR_pipe
-
- // b/34732712
- AllowSyscall(f, 364); // __NR_perf_event_open
-
- // b/34651972
- AllowSyscall(f, 33); // __NR_access
- AllowSyscall(f, 195); // __NR_stat64
-
- // b/34813887
- AllowSyscall(f, 5); // __NR_open
- AllowSyscall(f, 141); // __NR_getdents
- AllowSyscall(f, 217); // __NR_getdents64
-
- // b/34719286
- AllowSyscall(f, 351); // __NR_eventfd
-
- // b/34817266
- AllowSyscall(f, 252); // __NR_epoll_wait
-
- // Needed by sanitizers (b/34606909)
- // 5 (__NR_open) and 195 (__NR_stat64) are also required, but they are
- // already allowed.
- AllowSyscall(f, 85); // __NR_readlink
-
- // b/34908783
- AllowSyscall(f, 250); // __NR_epoll_create
-
- // b/34979910
- AllowSyscall(f, 8); // __NR_creat
- AllowSyscall(f, 10); // __NR_unlink
-
- // b/35059702
- AllowSyscall(f, 196); // __NR_lstat64
-
- Trap(f);
-
- return install_filter(f);
-}
-
static void Seccomp_setPolicy(JNIEnv* /*env*/) {
if (!set_seccomp_filter()) {
ALOGE("Failed to set seccomp policy - killing");
@@ -234,13 +26,6 @@
}
}
-#else // #if defined __arm__ || defined __aarch64__
-
-static void Seccomp_setPolicy(JNIEnv* /*env*/) {
-}
-
-#endif
-
static const JNINativeMethod method_table[] = {
NATIVE_METHOD(Seccomp, setPolicy, "()V"),
};
diff --git a/core/jni/android_text_StaticLayout.cpp b/core/jni/android_text_StaticLayout.cpp
index c05ef26..90ed6eb 100644
--- a/core/jni/android_text_StaticLayout.cpp
+++ b/core/jni/android_text_StaticLayout.cpp
@@ -159,11 +159,12 @@
minikin::LineBreaker* b = reinterpret_cast<minikin::LineBreaker*>(nativePtr);
Paint* paint = reinterpret_cast<Paint*>(nativePaint);
Typeface* typeface = reinterpret_cast<Typeface*>(nativeTypeface);
- minikin::FontCollection *font;
minikin::MinikinPaint minikinPaint;
- minikin::FontStyle style = MinikinUtils::prepareMinikinPaint(&minikinPaint, &font, paint,
+ Typeface* resolvedTypeface = Typeface::resolveDefault(typeface);
+ minikin::FontStyle style = MinikinUtils::prepareMinikinPaint(&minikinPaint, paint,
typeface);
- return b->addStyleRun(&minikinPaint, font, style, start, end, isRtl);
+ return b->addStyleRun(&minikinPaint, resolvedTypeface->fFontCollection, style, start, end,
+ isRtl);
}
// Accept width measurements for the run, passed in from Java
diff --git a/core/jni/android_util_AssetManager.cpp b/core/jni/android_util_AssetManager.cpp
index 723dce6..314595f 100644
--- a/core/jni/android_util_AssetManager.cpp
+++ b/core/jni/android_util_AssetManager.cpp
@@ -119,96 +119,6 @@
return block;
}
-// This is called by zygote (running as user root) as part of preloadResources.
-static void verifySystemIdmaps()
-{
- pid_t pid;
- char system_id[10];
-
- snprintf(system_id, sizeof(system_id), "%d", AID_SYSTEM);
-
- switch (pid = fork()) {
- case -1:
- ALOGE("failed to fork for idmap: %s", strerror(errno));
- break;
- case 0: // child
- {
- struct __user_cap_header_struct capheader;
- struct __user_cap_data_struct capdata;
-
- memset(&capheader, 0, sizeof(capheader));
- memset(&capdata, 0, sizeof(capdata));
-
- capheader.version = _LINUX_CAPABILITY_VERSION;
- capheader.pid = 0;
-
- if (capget(&capheader, &capdata) != 0) {
- ALOGE("capget: %s\n", strerror(errno));
- exit(1);
- }
-
- capdata.effective = capdata.permitted;
- if (capset(&capheader, &capdata) != 0) {
- ALOGE("capset: %s\n", strerror(errno));
- exit(1);
- }
-
- if (setgid(AID_SYSTEM) != 0) {
- ALOGE("setgid: %s\n", strerror(errno));
- exit(1);
- }
-
- if (setuid(AID_SYSTEM) != 0) {
- ALOGE("setuid: %s\n", strerror(errno));
- exit(1);
- }
-
- // Generic idmap parameters
- const char* argv[8];
- int argc = 0;
- struct stat st;
-
- memset(argv, NULL, sizeof(argv));
- argv[argc++] = AssetManager::IDMAP_BIN;
- argv[argc++] = "--scan";
- argv[argc++] = AssetManager::TARGET_PACKAGE_NAME;
- argv[argc++] = AssetManager::TARGET_APK_PATH;
- argv[argc++] = AssetManager::IDMAP_DIR;
-
- // Directories to scan for overlays: if OVERLAY_THEME_DIR_PROPERTY is defined,
- // use OVERLAY_DIR/<value of OVERLAY_THEME_DIR_PROPERTY> in addition to OVERLAY_DIR.
- char subdir[PROP_VALUE_MAX];
- int len = __system_property_get(AssetManager::OVERLAY_THEME_DIR_PERSIST_PROPERTY,
- subdir);
- if (len == 0) {
- len = __system_property_get(AssetManager::OVERLAY_THEME_DIR_PROPERTY, subdir);
- }
- if (len > 0) {
- String8 overlayPath = String8(AssetManager::OVERLAY_DIR) + "/" + subdir;
- if (stat(overlayPath.string(), &st) == 0) {
- argv[argc++] = overlayPath.string();
- }
- }
- if (stat(AssetManager::OVERLAY_DIR, &st) == 0) {
- argv[argc++] = AssetManager::OVERLAY_DIR;
- }
-
- // Finally, invoke idmap (if any overlay directory exists)
- if (argc > 5) {
- execv(AssetManager::IDMAP_BIN, (char* const*)argv);
- ALOGE("failed to execv for idmap: %s", strerror(errno));
- exit(1); // should never get here
- } else {
- exit(0);
- }
- }
- break;
- default: // parent
- waitpid(pid, NULL, 0);
- break;
- }
-}
-
// ----------------------------------------------------------------------------
// this guy is exported to other jni routines
@@ -1597,9 +1507,6 @@
static void android_content_AssetManager_init(JNIEnv* env, jobject clazz, jboolean isSystem)
{
- if (isSystem) {
- verifySystemIdmaps();
- }
AssetManager* am = new AssetManager();
if (am == NULL) {
jniThrowException(env, "java/lang/OutOfMemoryError", "");
diff --git a/core/jni/android_view_InputChannel.cpp b/core/jni/android_view_InputChannel.cpp
index c7998a1..1c6ead0 100644
--- a/core/jni/android_view_InputChannel.cpp
+++ b/core/jni/android_view_InputChannel.cpp
@@ -111,11 +111,12 @@
}
static jobject android_view_InputChannel_createInputChannel(JNIEnv* env,
- NativeInputChannel* nativeInputChannel) {
+ std::unique_ptr<NativeInputChannel> nativeInputChannel) {
jobject inputChannelObj = env->NewObject(gInputChannelClassInfo.clazz,
gInputChannelClassInfo.ctor);
if (inputChannelObj) {
- android_view_InputChannel_setNativeInputChannel(env, inputChannelObj, nativeInputChannel);
+ android_view_InputChannel_setNativeInputChannel(env, inputChannelObj,
+ nativeInputChannel.release());
}
return inputChannelObj;
}
@@ -143,13 +144,13 @@
}
jobject serverChannelObj = android_view_InputChannel_createInputChannel(env,
- new NativeInputChannel(serverChannel));
+ std::make_unique<NativeInputChannel>(serverChannel));
if (env->ExceptionCheck()) {
return NULL;
}
jobject clientChannelObj = android_view_InputChannel_createInputChannel(env,
- new NativeInputChannel(clientChannel));
+ std::make_unique<NativeInputChannel>(clientChannel));
if (env->ExceptionCheck()) {
return NULL;
}
diff --git a/core/jni/android_view_RenderNode.cpp b/core/jni/android_view_RenderNode.cpp
index f221392..edcbb3f 100644
--- a/core/jni/android_view_RenderNode.cpp
+++ b/core/jni/android_view_RenderNode.cpp
@@ -627,9 +627,9 @@
int register_android_view_RenderNode(JNIEnv* env) {
jclass clazz = FindClassOrDie(env, "android/view/SurfaceView");
gSurfaceViewPositionUpdateMethod = GetMethodIDOrDie(env, clazz,
- "updateWindowPosition_renderWorker", "(JIIII)V");
+ "updateSurfacePosition_renderWorker", "(JIIII)V");
gSurfaceViewPositionLostMethod = GetMethodIDOrDie(env, clazz,
- "windowPositionLost_uiRtSync", "(J)V");
+ "surfacePositionLost_uiRtSync", "(J)V");
return RegisterMethodsOrDie(env, kClassPathName, gMethods, NELEM(gMethods));
}
diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp
index 0171562..be86f5c 100644
--- a/core/jni/android_view_SurfaceControl.cpp
+++ b/core/jni/android_view_SurfaceControl.cpp
@@ -356,9 +356,9 @@
}
static void nativeSetMatrix(JNIEnv* env, jclass clazz, jlong nativeObject,
- jfloat dsdx, jfloat dtdx, jfloat dsdy, jfloat dtdy) {
+ jfloat dsdx, jfloat dtdx, jfloat dtdy, jfloat dsdy) {
SurfaceControl* const ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
- status_t err = ctrl->setMatrix(dsdx, dtdx, dsdy, dtdy);
+ status_t err = ctrl->setMatrix(dsdx, dtdx, dtdy, dsdy);
if (err < 0 && err != NO_INIT) {
doThrowIAE(env);
}
@@ -693,7 +693,6 @@
return JNI_TRUE;
}
-
static void nativeDeferTransactionUntil(JNIEnv* env, jclass clazz, jlong nativeObject,
jobject handleObject, jlong frameNumber) {
auto ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
@@ -702,6 +701,27 @@
ctrl->deferTransactionUntil(handle, frameNumber);
}
+static void nativeDeferTransactionUntilSurface(JNIEnv* env, jclass clazz, jlong nativeObject,
+ jobject surfaceObject, jlong frameNumber) {
+ auto ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
+ sp<Surface> barrier = reinterpret_cast<Surface *>(surfaceObject);
+
+ ctrl->deferTransactionUntil(barrier, frameNumber);
+}
+
+static void nativeReparentChildren(JNIEnv* env, jclass clazz, jlong nativeObject,
+ jobject newParentObject) {
+ auto ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
+ sp<IBinder> handle = ibinderForJavaObject(env, newParentObject);
+
+ ctrl->reparentChildren(handle);
+}
+
+static void nativeSeverChildren(JNIEnv* env, jclass clazz, jlong nativeObject) {
+ auto ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
+ ctrl->detachChildren();
+}
+
static void nativeSetOverrideScalingMode(JNIEnv* env, jclass clazz, jlong nativeObject,
jint scalingMode) {
auto ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
@@ -824,6 +844,12 @@
(void*)nativeSetDisplayPowerMode },
{"nativeDeferTransactionUntil", "(JLandroid/os/IBinder;J)V",
(void*)nativeDeferTransactionUntil },
+ {"nativeDeferTransactionUntilSurface", "(JJJ)V",
+ (void*)nativeDeferTransactionUntilSurface },
+ {"nativeReparentChildren", "(JLandroid/os/IBinder;)V",
+ (void*)nativeReparentChildren } ,
+ {"nativeSeverChildren", "(J)V",
+ (void*)nativeSeverChildren } ,
{"nativeSetOverrideScalingMode", "(JI)V",
(void*)nativeSetOverrideScalingMode },
{"nativeGetHandle", "(J)Landroid/os/IBinder;",
diff --git a/core/jni/android_view_SurfaceSession.cpp b/core/jni/android_view_SurfaceSession.cpp
index dad6958..508d897 100644
--- a/core/jni/android_view_SurfaceSession.cpp
+++ b/core/jni/android_view_SurfaceSession.cpp
@@ -24,6 +24,7 @@
#include <utils/RefBase.h>
#include <gui/SurfaceComposerClient.h>
+#include <gui/Surface.h>
namespace android {
@@ -45,6 +46,13 @@
return reinterpret_cast<jlong>(client);
}
+static jlong nativeCreateScoped(JNIEnv* env, jclass clazz, jlong surfaceObject) {
+ Surface *parent = reinterpret_cast<Surface*>(surfaceObject);
+ SurfaceComposerClient* client = new SurfaceComposerClient(parent->getIGraphicBufferProducer());
+ client->incStrong((void*)nativeCreate);
+ return reinterpret_cast<jlong>(client);
+}
+
static void nativeDestroy(JNIEnv* env, jclass clazz, jlong ptr) {
SurfaceComposerClient* client = reinterpret_cast<SurfaceComposerClient*>(ptr);
client->decStrong((void*)nativeCreate);
@@ -55,11 +63,12 @@
client->dispose();
}
-
static const JNINativeMethod gMethods[] = {
/* name, signature, funcPtr */
{ "nativeCreate", "()J",
(void*)nativeCreate },
+ { "nativeCreateScoped", "(J)J",
+ (void*)nativeCreateScoped },
{ "nativeDestroy", "(J)V",
(void*)nativeDestroy },
{ "nativeKill", "(J)V",
diff --git a/core/jni/include/android_runtime/android_hardware_HardwareBuffer.h b/core/jni/include/android_runtime/android_hardware_HardwareBuffer.h
index a5d0596..3545c56 100644
--- a/core/jni/include/android_runtime/android_hardware_HardwareBuffer.h
+++ b/core/jni/include/android_runtime/android_hardware_HardwareBuffer.h
@@ -41,12 +41,13 @@
/* Convert from AHARDWAREBUFFER_USAGE* flags to to gralloc usage flags. */
extern void android_hardware_HardwareBuffer_convertToGrallocUsageBits(
- uint64_t usage0, uint64_t usage1, uint64_t* outProducerUsage,
- uint64_t* outConsumerUsage);
+ uint64_t* outProducerUsage, uint64_t* outConsumerUsage, uint64_t usage0,
+ uint64_t usage1);
/* Convert from gralloc usage flags to to AHARDWAREBUFFER_USAGE0* flags. */
-extern uint64_t android_hardware_HardwareBuffer_convertFromGrallocUsageBits(
- uint64_t producerUsage, uint64_t consumerUsage);
+extern void android_hardware_HardwareBuffer_convertFromGrallocUsageBits(
+ uint64_t* outUsage0, uint64_t* outUsage1, uint64_t producerUsage,
+ uint64_t consumerUsage);
} // namespace android
diff --git a/core/proto/android/os/looper.proto b/core/proto/android/os/looper.proto
new file mode 100644
index 0000000..9fcc781
--- /dev/null
+++ b/core/proto/android/os/looper.proto
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+syntax = "proto3";
+
+package android.os;
+
+option java_multiple_files = true;
+
+import "frameworks/base/core/proto/android/os/messagequeue.proto";
+
+message LooperProto {
+ string thread_name = 1;
+ int64 thread_id = 2;
+ int32 identity_hash_code = 3;
+ android.os.MessageQueueProto queue = 4;
+}
diff --git a/core/proto/android/os/message.proto b/core/proto/android/os/message.proto
new file mode 100644
index 0000000..604935d
--- /dev/null
+++ b/core/proto/android/os/message.proto
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+syntax = "proto3";
+
+package android.os;
+
+option java_multiple_files = true;
+
+message MessageProto {
+ int64 when = 1;
+ // Name of callback class.
+ string callback = 2;
+ // User-defined message code so that the recipient can identify what this
+ // message is about.
+ int32 what = 3;
+ int32 arg1 = 4;
+ int32 arg2 = 5;
+ // String representation of an arbitrary object to send to the recipient.
+ string obj = 6;
+ // Name of target class.
+ string target = 7;
+ int32 barrier = 8;
+}
diff --git a/core/proto/android/os/messagequeue.proto b/core/proto/android/os/messagequeue.proto
new file mode 100644
index 0000000..9bff13e
--- /dev/null
+++ b/core/proto/android/os/messagequeue.proto
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+syntax = "proto3";
+
+package android.os;
+
+option java_multiple_files = true;
+
+import "frameworks/base/core/proto/android/os/message.proto";
+
+message MessageQueueProto {
+ repeated android.os.MessageProto messages = 1;
+ bool is_polling_locked = 2;
+ bool is_quitting = 3;
+}
diff --git a/core/proto/android/os/worksource.proto b/core/proto/android/os/worksource.proto
new file mode 100644
index 0000000..c2aa5cb
--- /dev/null
+++ b/core/proto/android/os/worksource.proto
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+syntax = "proto3";
+
+package android.os;
+
+option java_multiple_files = true;
+
+message WorkSourceProto {
+ message WorkSourceContentProto {
+ int32 uid = 1;
+ string name = 2;
+ }
+
+ repeated WorkSourceContentProto work_source_contents = 1;
+}
\ No newline at end of file
diff --git a/core/proto/android/service/package.proto b/core/proto/android/service/package.proto
new file mode 100644
index 0000000..326b0eb
--- /dev/null
+++ b/core/proto/android/service/package.proto
@@ -0,0 +1,120 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+syntax = "proto3";
+
+package android.service.pm;
+
+option java_multiple_files = true;
+option java_outer_classname = "PackageServiceProto";
+
+message PackageServiceDumpProto {
+ message PackageShortProto {
+ // Name of package. e.g. "com.android.providers.telephony".
+ string name = 1;
+ // UID for this package as assigned by Android OS.
+ int32 uid = 2;
+ }
+ message SharedLibraryProto {
+ string name = 1;
+ // True if library path is not null (jar), false otherwise (apk)
+ bool is_jar = 2;
+ // Should be filled if is_jar is true
+ string path = 3;
+ // Should be filled if is_jar is false
+ string apk = 4;
+ }
+ message FeatureProto {
+ string name = 1;
+ int32 version = 2;
+ }
+ message SharedUserProto {
+ int32 user_id = 1;
+ string name = 2;
+ }
+
+ // Installed packages.
+ PackageShortProto required_verifier_package = 1;
+ PackageShortProto verifier_package = 2;
+ repeated SharedLibraryProto shared_libraries = 3;
+ repeated FeatureProto features = 4;
+ repeated PackageProto packages = 5;
+ repeated SharedUserProto shared_users = 6;
+ // Messages from the settings problem file
+ repeated string messages = 7;
+}
+
+message PackageProto {
+ message SplitProto {
+ string name = 1;
+ int32 revision_code = 2;
+ }
+ message UserInfoProto {
+ enum InstallType {
+ NOT_INSTALLED_FOR_USER = 0;
+ FULL_APP_INSTALL = 1;
+ INSTANT_APP_INSTALL = 2;
+ }
+ // Enum values gotten from PackageManger.java
+ enum EnabledState {
+ // This component or application is in its default enabled state
+ // (as specified in its manifest).
+ COMPONENT_ENABLED_STATE_DEFAULT = 0;
+ // This component or application has been explictily enabled, regardless
+ // of what it has specified in its manifest.
+ COMPONENT_ENABLED_STATE_ENABLED = 1;
+ // This component or application has been explicitly disabled, regardless of
+ // what it has specified in its manifest.
+ COMPONENT_ENABLED_STATE_DISABLED = 2;
+ // The user has explicitly disabled the application, regardless of what it has
+ // specified in its manifest.
+ COMPONENT_ENABLED_STATE_DISABLED_USER = 3;
+ // This application should be considered, until the point where the user actually
+ // wants to use it.
+ COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED = 4;
+ }
+
+ int32 id = 1;
+ InstallType install_type = 2;
+ // Is the app restricted by owner / admin
+ bool is_hidden = 3;
+ bool is_suspended = 4;
+ bool is_stopped = 5;
+ bool is_launched = 6;
+ EnabledState enabled_state = 7;
+ string last_disabled_app_caller = 8;
+ }
+
+ // Name of package. e.g. "com.android.providers.telephony".
+ string name = 1;
+ // UID for this package as assigned by Android OS.
+ int32 uid = 2;
+ // Package's reported version.
+ int32 version_code = 3;
+ // Package's reported version string (what's displayed to the user).
+ string version_string = 4;
+ // UTC timestamp of install
+ int64 install_time_ms = 5;
+ // Millisecond UTC timestamp of latest update adjusted to Google's server clock.
+ int64 update_time_ms = 6;
+ // From "dumpsys package" - name of package which installed this one.
+ // Typically "" if system app or "com.android.vending" if Play Store.
+ string installer_name = 7;
+ // Split APKs.
+ repeated SplitProto splits = 8;
+ // Per-user package info.
+ repeated UserInfoProto users = 9;
+}
diff --git a/core/proto/android/service/power.proto b/core/proto/android/service/power.proto
new file mode 100644
index 0000000..1830dbf
--- /dev/null
+++ b/core/proto/android/service/power.proto
@@ -0,0 +1,408 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+syntax = "proto3";
+
+package android.service.power;
+
+option java_multiple_files = true;
+option java_outer_classname = "PowerServiceProto";
+
+import "frameworks/base/core/proto/android/os/looper.proto";
+import "frameworks/base/core/proto/android/os/worksource.proto";
+import "frameworks/base/core/proto/android/service/wirelesschargerdetector.proto";
+
+message PowerServiceDumpProto {
+ message ConstantsProto {
+ bool is_no_cached_wake_locks = 1;
+ }
+ message ActiveWakeLocksProto {
+ bool is_cpu = 1;
+ bool is_screen_bright = 2;
+ bool is_screen_dim = 3;
+ bool is_button_bright = 4;
+ bool is_proximity_screen_off = 5;
+ // only set if already awake
+ bool is_stay_awake = 6;
+ bool is_doze = 7;
+ bool is_draw = 8;
+ }
+ message UserActivityProto {
+ bool is_screen_bright = 1;
+ bool is_screen_dim = 2;
+ bool is_screen_dream = 3;
+ }
+ message UidProto {
+ // Enum values gotten from ActivityManager.java
+ enum ProcessState {
+ // Process is a persistent system process.
+ PROCESS_STATE_PERSISTENT = 0;
+ // Process is a persistent system process and is doing UI.
+ PROCESS_STATE_PERSISTENT_UI = 1;
+ // Process is hosting the current top activities. Note that this
+ // covers all activities that are visible to the user.
+ PROCESS_STATE_TOP = 2;
+ // Process is hosting a foreground service due to a system binding.
+ PROCESS_STATE_BOUND_FOREGROUND_SERVICE = 3;
+ // Process is hosting a foreground service.
+ PROCESS_STATE_FOREGROUND_SERVICE = 4;
+ // Same as {@link #PROCESS_STATE_TOP} but while device is sleeping.
+ PROCESS_STATE_TOP_SLEEPING = 5;
+ // Process is important to the user, and something they are aware of.
+ PROCESS_STATE_IMPORTANT_FOREGROUND = 6;
+ // Process is important to the user, but not something they are aware of.
+ PROCESS_STATE_IMPORTANT_BACKGROUND = 7;
+ // Process is in the background running a backup/restore operation.
+ PROCESS_STATE_BACKUP = 8;
+ // Process is in the background, but it can't restore its state so
+ // we want to try to avoid killing it.
+ PROCESS_STATE_HEAVY_WEIGHT = 9;
+ // Process is in the background running a service.
+ PROCESS_STATE_SERVICE = 10;
+ // Process is in the background running a receiver.
+ PROCESS_STATE_RECEIVER = 11;
+ // Process is in the background but hosts the home activity.
+ PROCESS_STATE_HOME = 12;
+ // Process is in the background but hosts the last shown activity.
+ PROCESS_STATE_LAST_ACTIVITY = 13;
+ // Process is being cached for later use and contains activities.
+ PROCESS_STATE_CACHED_ACTIVITY = 14;
+ // Process is being cached for later use and is a client of another
+ // cached process that contains activities.
+ PROCESS_STATE_CACHED_ACTIVITY_CLIENT = 15;
+ // Process is being cached for later use and is empty.
+ PROCESS_STATE_CACHED_EMPTY = 16;
+ // Process does not exist.
+ PROCESS_STATE_NONEXISTENT = 17;
+ }
+ int32 uid = 1;
+ string uid_string = 2;
+ bool is_active = 3;
+ int32 num_wake_locks = 4;
+ bool is_process_state_unknown = 5;
+ ProcessState process_state = 6;
+ }
+
+ // Enum values gotten from PowerManagerInternal.java
+ enum Wakefulness {
+ WAKEFULNESS_ASLEEP = 0;
+ WAKEFULNESS_AWAKE = 1;
+ WAKEFULNESS_DREAMING = 2;
+ WAKEFULNESS_DOZING = 3;
+ WAKEFULNESS_UNKNOWN = 4;
+ }
+ // Enum values gotten from BatteryManager.java
+ enum PlugType {
+ PLUG_TYPE_NONE = 0;
+ PLUG_TYPE_PLUGGED_AC = 1;
+ PLUG_TYPE_PLUGGED_USB = 2;
+ PLUG_TYPE_PLUGGED_WIRELESS = 4;
+ }
+ // Enum values gotten from Intent.java
+ enum DockState {
+ DOCK_STATE_UNDOCKED = 0;
+ DOCK_STATE_DESK = 1;
+ DOCK_STATE_CAR = 2;
+ DOCK_STATE_LE_DESK = 3;
+ DOCK_STATE_HE_DESK = 4;
+ }
+
+ ConstantsProto constants = 1;
+ // A bitfield that indicates what parts of the power state have
+ // changed and need to be recalculated.
+ int32 dirty = 2;
+ // Indicates whether the device is awake or asleep or somewhere in between.
+ Wakefulness wakefulness = 3;
+ bool is_wakefulness_changing = 4;
+ // True if the device is plugged into a power source.
+ bool is_powered = 5;
+ // The current plug type
+ PlugType plug_type = 6;
+ // The current battery level percentage.
+ int32 battery_level = 7;
+ // The battery level percentage at the time the dream started.
+ int32 battery_level_when_dream_started = 8;
+ // The current dock state.
+ DockState dock_state = 9;
+ // True if the device should stay on.
+ bool is_stay_on = 10;
+ // True if the proximity sensor reads a positive result.
+ bool is_proximity_positive = 11;
+ // True if boot completed occurred. We keep the screen on until this happens.
+ bool is_boot_completed = 12;
+ // True if systemReady() has been called.
+ bool is_system_ready = 13;
+ // True if auto-suspend mode is enabled.
+ bool is_hal_auto_suspend_mode_enabled = 14;
+ // True if interactive mode is enabled.
+ bool is_hal_auto_interactive_mode_enabled = 15;
+ // Summarizes the state of all active wakelocks.
+ ActiveWakeLocksProto active_wake_locks = 16;
+ // Have we scheduled a message to check for long wake locks? This is when
+ // we will check. (In milliseconds timestamp)
+ int64 notify_long_scheduled_ms = 17;
+ // Last time we checked for long wake locks. (In milliseconds timestamp)
+ int64 notify_long_dispatched_ms = 18;
+ // The time we decided to do next long check. (In milliseconds timestamp)
+ int64 notify_long_next_check_ms = 19;
+ // Summarizes the effect of the user activity timer.
+ UserActivityProto user_activity = 20;
+ // If true, instructs the display controller to wait for the proximity
+ // sensor to go negative before turning the screen on.
+ bool is_request_wait_for_negative_proximity = 21;
+ // True if MSG_SANDMAN has been scheduled.
+ bool is_sandman_scheduled = 22;
+ // True if the sandman has just been summoned for the first time since entering
+ // the dreaming or dozing state. Indicates whether a new dream should begin.
+ bool is_sandman_summoned = 23;
+ // If true, the device is in low power mode.
+ bool is_low_power_mode_enabled = 24;
+ // True if the battery level is currently considered low.
+ bool is_battery_level_low = 25;
+ // True if we are currently in light device idle mode.
+ bool is_light_device_idle_mode = 26;
+ // True if we are currently in device idle mode.
+ bool is_device_idle_mode = 27;
+ // Set of app ids that we will always respect the wake locks for.
+ repeated int32 device_idle_whitelist = 28;
+ // Set of app ids that are temporarily allowed to acquire wakelocks due to
+ // high-pri message
+ repeated int32 device_idle_temp_whitelist = 29;
+ // Timestamp of the last time the device was awoken.
+ int64 last_wake_time_ms = 30;
+ // Timestamp of the last time the device was put to sleep.
+ int64 last_sleep_time_ms = 31;
+ // Timestamp of the last call to user activity.
+ int64 last_user_activity_time_ms = 32;
+ int64 last_user_activity_time_no_change_lights_ms = 33;
+ // Timestamp of last interactive power hint.
+ int64 last_interactive_power_hint_time_ms = 34;
+ // Timestamp of the last screen brightness boost.
+ int64 last_screen_brightness_boost_time_ms = 35;
+ // True if screen brightness boost is in progress.
+ bool is_screen_brightness_boost_in_progress = 36;
+ // True if the display power state has been fully applied, which means the
+ // display is actually on or actually off or whatever was requested.
+ bool is_display_ready = 37;
+ // True if the wake lock suspend blocker has been acquired.
+ bool is_holding_wake_lock_suspend_blocker = 38;
+ // The suspend blocker used to keep the CPU alive when the display is on, the
+ // display is getting ready or there is user activity (in which case the
+ // display must be on).
+ bool is_holding_display_suspend_blocker = 39;
+ // Settings and configuration
+ PowerServiceSettingsAndConfigurationDumpProto settings_and_configuration = 40;
+ // Sleep timeout in ms
+ sint32 sleep_timeout_ms = 41;
+ // Screen off timeout in ms
+ int32 screen_off_timeout_ms = 42;
+ // Screen dim duration in ms
+ int32 screen_dim_duration_ms = 43;
+ // We are currently in the middle of a batch change of uids.
+ bool are_uids_changing = 44;
+ // Some uids have actually changed while mUidsChanging was true.
+ bool are_uids_changed = 45;
+ // List of UIDs and their states
+ repeated UidProto uids = 46;
+ android.os.LooperProto looper = 47;
+ // List of all wake locks acquired by applications.
+ repeated WakeLockProto wake_locks = 48;
+ // List of all suspend blockers.
+ repeated SuspendBlockerProto suspend_blockers = 49;
+ WirelessChargerDetectorProto wireless_charger_detector = 50;
+}
+
+message SuspendBlockerProto {
+ string name = 1;
+ int32 reference_count = 2;
+}
+
+message WakeLockProto {
+ message WakeLockFlagsProto {
+ // Turn the screen on when the wake lock is acquired.
+ bool is_acquire_causes_wakeup = 1;
+ // When this wake lock is released, poke the user activity timer
+ // so the screen stays on for a little longer.
+ bool is_on_after_release = 2;
+ }
+
+ // Enum values gotten from PowerManager.java
+ enum LockLevel {
+ WAKE_LOCK_INVALID = 0;
+ // Ensures that the CPU is running.
+ PARTIAL_WAKE_LOCK = 1;
+ // Ensures that the screen is on (but may be dimmed).
+ SCREEN_DIM_WAKE_LOCK = 6;
+ // Ensures that the screen is on at full brightness.
+ SCREEN_BRIGHT_WAKE_LOCK = 10;
+ // Ensures that the screen and keyboard backlight are on at full brightness.
+ FULL_WAKE_LOCK = 26;
+ // Turns the screen off when the proximity sensor activates.
+ PROXIMITY_SCREEN_OFF_WAKE_LOCK = 32;
+ // Put the screen in a low power state and allow the CPU to suspend
+ // if no other wake locks are held.
+ DOZE_WAKE_LOCK = 64;
+ // Keep the device awake enough to allow drawing to occur.
+ DRAW_WAKE_LOCK = 128;
+ }
+
+ LockLevel lock_level = 1;
+ string tag = 2;
+ WakeLockFlagsProto flags = 3;
+ bool is_disabled = 4;
+ // Acquire time in ms
+ int64 acq_ms = 5;
+ bool is_notified_long = 6;
+ // Owner UID
+ int32 uid = 7;
+ // Owner PID
+ int32 pid = 8;
+ android.os.WorkSourceProto work_source = 9;
+}
+
+message PowerServiceSettingsAndConfigurationDumpProto {
+ message StayOnWhilePluggedInProto {
+ bool is_stay_on_while_plugged_in_ac = 1;
+ bool is_stay_on_while_plugged_in_usb = 2;
+ bool is_stay_on_while_plugged_in_wireless = 3;
+ }
+ message ScreenBrightnessSettingLimitsProto {
+ int32 setting_minimum = 1;
+ int32 setting_maximum = 2;
+ int32 setting_default = 3;
+ int32 setting_for_vr_default = 4;
+ }
+
+ // Enum values gotten from Settings.java
+ enum ScreenBrightnessMode {
+ SCREEN_BRIGHTNESS_MODE_MANUAL = 0;
+ SCREEN_BRIGHTNESS_MODE_AUTOMATIC = 1;
+ }
+ // Enum values gotten from Display.java
+ enum DisplayState {
+ DISPLAY_STATE_UNKNOWN = 0;
+ DISPLAY_STATE_OFF = 1;
+ DISPLAY_STATE_ON = 2;
+ DISPLAY_STATE_DOZE = 3;
+ DISPLAY_STATE_DOZE_SUSPEND = 4;
+ DISPLAY_STATE_VR = 5;
+ }
+
+
+ // True to decouple auto-suspend mode from the display state.
+ bool is_decouple_hal_auto_suspend_mode_from_display_config = 1;
+ // True to decouple interactive mode from the display state.
+ bool is_decouple_hal_interactive_mode_from_display_config = 2;
+ // True if the device should wake up when plugged or unplugged.
+ bool is_wake_up_when_plugged_or_unplugged_config = 3;
+ // True if the device should wake up when plugged or unplugged in theater mode.
+ bool is_wake_up_when_plugged_or_unplugged_in_theater_mode_config = 4;
+ // True if theater mode is enabled
+ bool is_theater_mode_enabled = 5;
+ // True if the device should suspend when the screen is off due to proximity.
+ bool is_suspend_when_screen_off_due_to_proximity_config = 6;
+ // True if dreams are supported on this device.
+ bool are_dreams_supported_config = 7;
+ // Default value for dreams enabled
+ bool are_dreams_enabled_by_default_config = 8;
+ // Default value for dreams activate-on-sleep
+ bool are_dreams_activated_on_sleep_by_default_config = 9;
+ // Default value for dreams activate-on-dock
+ bool are_dreams_activated_on_dock_by_default_config = 10;
+ // True if dreams can run while not plugged in.
+ bool are_dreams_enabled_on_battery_config = 11;
+ // Minimum battery level to allow dreaming when powered.
+ // Use -1 to disable this safety feature.
+ sint32 dreams_battery_level_minimum_when_powered_config = 12;
+ // Minimum battery level to allow dreaming when not powered.
+ // Use -1 to disable this safety feature.
+ sint32 dreams_battery_level_minimum_when_not_powered_config = 13;
+ // If the battery level drops by this percentage and the user activity
+ // timeout has expired, then assume the device is receiving insufficient
+ // current to charge effectively and terminate the dream. Use -1 to disable
+ // this safety feature.
+ sint32 dreams_battery_level_drain_cutoff_config = 14;
+ // True if dreams are enabled by the user.
+ bool are_dreams_enabled_setting = 15;
+ // True if dreams should be activated on sleep.
+ bool are_dreams_activate_on_sleep_setting = 16;
+ // True if dreams should be activated on dock.
+ bool are_dreams_activate_on_dock_setting = 17;
+ // True if doze should not be started until after the screen off transition.
+ bool is_doze_after_screen_off_config = 18;
+ // If true, the device is in low power mode.
+ bool is_low_power_mode_setting = 19;
+ // Current state of whether the settings are allowing auto low power mode.
+ bool is_auto_low_power_mode_configured = 20;
+ // The user turned off low power mode below the trigger level
+ bool is_auto_low_power_mode_snoozing = 21;
+ // The minimum screen off timeout, in milliseconds.
+ int32 minimum_screen_off_timeout_config_ms = 22;
+ // The screen dim duration, in milliseconds.
+ int32 maximum_screen_dim_duration_config_ms = 23;
+ // The maximum screen dim time expressed as a ratio relative to the screen off timeout.
+ float maximum_screen_dim_ratio_config = 24;
+ // The screen off timeout setting value in milliseconds.
+ int32 screen_off_timeout_setting_ms = 25;
+ // The sleep timeout setting value in milliseconds.
+ sint32 sleep_timeout_setting_ms = 26;
+ // The maximum allowable screen off timeout according to the device administration policy.
+ int32 maximum_screen_off_timeout_from_device_admin_ms = 27;
+ bool is_maximum_screen_off_timeout_from_device_admin_enforced_locked = 28;
+ // The stay on while plugged in setting.
+ // A set of battery conditions under which to make the screen stay on.
+ StayOnWhilePluggedInProto stay_on_while_plugged_in = 29;
+ // The screen brightness setting, from 0 to 255.
+ // Use -1 if no value has been set.
+ sint32 screen_brightness_setting = 30;
+ // The screen auto-brightness adjustment setting, from -1 to 1.
+ // Use 0 if there is no adjustment.
+ float screen_auto_brightness_adjustment_setting = 31;
+ // The screen brightness mode.
+ ScreenBrightnessMode screen_brightness_mode_setting = 32;
+ // The screen brightness setting override from the window manager
+ // to allow the current foreground activity to override the brightness.
+ // Use -1 to disable.
+ sint32 screen_brightness_override_from_window_manager = 33;
+ // The user activity timeout override from the window manager
+ // to allow the current foreground activity to override the user activity
+ // timeout. Use -1 to disable.
+ sint64 user_activity_timeout_override_from_window_manager_ms = 34;
+ // The window manager has determined the user to be inactive via other means.
+ // Set this to false to disable.
+ bool is_user_inactive_override_from_window_manager = 35;
+ // The screen brightness setting override from the settings application
+ // to temporarily adjust the brightness until next updated,
+ // Use -1 to disable.
+ sint32 temporary_screen_brightness_setting_override = 36;
+ // The screen brightness adjustment setting override from the settings
+ // application to temporarily adjust the auto-brightness adjustment factor
+ // until next updated, in the range -1..1.
+ // Use NaN to disable.
+ float temporary_screen_auto_brightness_adjustment_setting_override = 37;
+ // The screen state to use while dozing.
+ DisplayState doze_screen_state_override_from_dream_manager = 38;
+ // The screen brightness to use while dozing.
+ float dozed_screen_brightness_override_from_dream_manager = 39;
+ // Screen brightness settings limits.
+ ScreenBrightnessSettingLimitsProto screen_brightness_setting_limits = 40;
+ // The screen brightness setting, from 0 to 255, to be used while in VR Mode.
+ int32 screen_brightness_for_vr_setting = 41;
+ // True if double tap to wake is enabled
+ bool is_double_tap_wake_enabled = 42;
+ // True if we are currently in VR Mode.
+ bool is_vr_mode_enabled = 43;
+}
diff --git a/core/proto/android/service/wirelesschargerdetector.proto b/core/proto/android/service/wirelesschargerdetector.proto
new file mode 100644
index 0000000..7ba7c17
--- /dev/null
+++ b/core/proto/android/service/wirelesschargerdetector.proto
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+syntax = "proto3";
+
+package android.service.power;
+
+option java_multiple_files = true;
+
+message WirelessChargerDetectorProto {
+ message VectorProto {
+ float x = 1;
+ float y = 2;
+ float z = 3;
+ }
+
+ // Previously observed wireless power state.
+ bool is_powered_wirelessly = 1;
+ // True if the device is thought to be at rest on a wireless charger.
+ bool is_at_rest = 2;
+ // The gravity vector most recently observed while at rest.
+ VectorProto rest = 3;
+ // True if detection is in progress.
+ bool is_detection_in_progress = 4;
+ // The time when detection was last performed.
+ int64 detection_start_time_ms = 5;
+ // True if the rest position should be updated if at rest.
+ bool is_must_update_rest_position = 6;
+ // The total number of samples collected.
+ int32 total_samples = 7;
+ // The number of samples collected that showed evidence of not being at rest.
+ int32 moving_samples = 8;
+ // The value of the first sample that was collected.
+ VectorProto first_sample = 9;
+ // The value of the last sample that was collected.
+ VectorProto last_sample = 10;
+}
\ No newline at end of file
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 64759ff..aea7a5d 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -522,6 +522,8 @@
<protected-broadcast android:name="android.app.action.APPLICATION_DELEGATION_SCOPES_CHANGED" />
<protected-broadcast android:name="com.android.server.wm.ACTION_REVOKE_SYSTEM_ALERT_WINDOW_PERMISSION" />
+ <protected-broadcast android:name="android.content.pm.action.SESSION_COMMITTED" />
+
<!-- ====================================================================== -->
<!-- RUNTIME PERMISSIONS -->
<!-- ====================================================================== -->
@@ -895,6 +897,17 @@
android:description="@string/permdesc_processOutgoingCalls"
android:protectionLevel="dangerous" />
+
+ <!-- Allows the app to answer an incoming phone call.
+ <p>Protection level: dangerous
+ -->
+ <permission android:name="android.permission.ANSWER_PHONE_CALLS"
+ android:permissionGroup="android.permission-group.PHONE"
+ android:label="@string/permlab_answerPhoneCalls"
+ android:description="@string/permdesc_answerPhoneCalls"
+ android:protectionLevel="dangerous" />
+
+
<!-- ====================================================================== -->
<!-- Permissions for accessing the device microphone -->
<!-- ====================================================================== -->
@@ -2138,7 +2151,7 @@
runtime resource overlays.
@hide -->
<permission android:name="android.permission.CHANGE_OVERLAY_PACKAGES"
- android:protectionLevel="signature|privileged|development" />
+ android:protectionLevel="signature|privileged" />
<!-- ========================================= -->
<!-- Permissions for special development tools -->
@@ -3489,7 +3502,7 @@
<receiver android:name="com.android.server.updates.ApnDbInstallReceiver"
android:permission="android.permission.UPDATE_CONFIG">
<intent-filter>
- <action android:name="android.intent.action.UPDATE_APN_DB" />
+ <action android:name="com.android.internal.intent.action.UPDATE_APN_DB" />
<data android:scheme="content" android:host="*" android:mimeType="*/*" />
</intent-filter>
</receiver>
diff --git a/core/res/res/layout/app_permission_item_money.xml b/core/res/res/layout/app_permission_item_money.xml
index 2056285..764c883 100644
--- a/core/res/res/layout/app_permission_item_money.xml
+++ b/core/res/res/layout/app_permission_item_money.xml
@@ -57,14 +57,14 @@
android:layout_alignParentStart="true"
android:layout_alignBottom="@+id/perm_money_label"
android:scaleType="fitCenter"
- android:tint="@color/perms_costs_money"
+ android:tint="?android:attr/colorError"
android:tintMode="src_in"
android:src="@android:drawable/ic_coins_s" />
<TextView
android:id="@+id/perm_money_label"
android:textAppearance="?android:attr/textAppearanceSmall"
android:textSize="16sp"
- android:textColor="@color/perms_costs_money"
+ android:textColor="?android:attr/colorError"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toEndOf="@id/perm_money_icon"
diff --git a/core/res/res/layout/autofill_dataset_picker.xml b/core/res/res/layout/autofill_dataset_picker.xml
index 40cce7b..9b90de6 100644
--- a/core/res/res/layout/autofill_dataset_picker.xml
+++ b/core/res/res/layout/autofill_dataset_picker.xml
@@ -15,7 +15,7 @@
-->
<ListView xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/list"
+ android:id="@+id/autofill_dataset_picker"
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:divider="?android:attr/listDivider"
diff --git a/core/res/res/layout/autofill_save.xml b/core/res/res/layout/autofill_save.xml
index d55a012..dad9aad 100644
--- a/core/res/res/layout/autofill_save.xml
+++ b/core/res/res/layout/autofill_save.xml
@@ -14,44 +14,87 @@
limitations under the License.
-->
-<!-- TODO(b/33197203) remove hardcoded color once color is final -->
-<RelativeLayout
+<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
+ android:id="@+id/autofill_save"
+ android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:paddingStart="16dip"
android:paddingEnd="16dip"
android:paddingTop="16dip"
android:paddingBottom="16dip"
- android:background="#FDF8C8">
+ android:elevation="16dp"
+ android:background="?android:attr/colorBackground"
+ android:orientation="vertical">
- <!-- TODO(b/33197203) use.R.string once final wording is done -->
- <TextView
- android:id="@+id/autofill_save_title"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:text="Save for autofill?"
- android:singleLine="true"/>
+ <LinearLayout
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal">
- <TextView
- android:id="@+id/autofill_save_no"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_below="@+id/autofill_save_title"
- android:layout_toLeftOf="@+id/autofill_save_yes"
- android:layout_marginRight="16dip"
- android:text="No thanks"
- android:textAllCaps="true"
- android:singleLine="true"/>
+ <TextView
+ android:id="@+id/autofill_save_title"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/autofill_save_title"
+ android:singleLine="true">
+ </TextView>
- <TextView
- android:id="@+id/autofill_save_yes"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_below="@+id/autofill_save_title"
- android:layout_alignParentRight="true"
- android:text="Save"
- android:textAllCaps="true"
- android:singleLine="true"/>
+ <TextView
+ android:id="@+id/autofill_save_subtitle"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:visibility="invisible">
+ </TextView>
-</RelativeLayout>
+ <Space
+ android:layout_width="0dp"
+ android:layout_height="0dp"
+ android:layout_weight="1"
+ android:visibility="invisible" >
+ </Space>
+
+ <ImageView
+ android:id="@+id/autofill_save_close"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:src="@android:drawable/ic_close"
+ android:background="?android:attr/selectableItemBackgroundBorderless">
+ </ImageView>
+
+ </LinearLayout>
+
+ <com.android.internal.widget.ButtonBarLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="end"
+ android:layout_marginTop="16dp"
+ android:layout_weight="1"
+ android:orientation="horizontal">
+
+ <Space
+ android:layout_width="0dp"
+ android:layout_height="0dp"
+ android:layout_weight="1"
+ android:visibility="invisible" >
+ </Space>
+
+ <Button
+ android:id="@+id/autofill_save_no"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ style="?android:attr/buttonBarButtonStyle"
+ android:text="@string/autofill_save_no" >
+ </Button>
+
+ <Button
+ android:id="@+id/autofill_save_yes"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ style="?android:attr/buttonBarButtonStyle"
+ android:text="@string/autofill_save_yes" >
+ </Button>
+
+ </com.android.internal.widget.ButtonBarLayout>
+
+</LinearLayout>
diff --git a/core/res/res/layout/time_picker_text_input_material.xml b/core/res/res/layout/time_picker_text_input_material.xml
index f17b80e..632a4c1 100644
--- a/core/res/res/layout/time_picker_text_input_material.xml
+++ b/core/res/res/layout/time_picker_text_input_material.xml
@@ -77,7 +77,7 @@
android:layout_height="wrap_content"
android:layout_below="@id/input_hour"
android:layout_alignStart="@id/input_hour"
- android:textColor="?attr/textColorError"
+ android:textColor="?attr/colorError"
android:text="@string/time_picker_input_error" />
</RelativeLayout>
<Spinner
@@ -87,4 +87,4 @@
android:layout_alignBaseline="@id/input_block"
android:layout_alignParentEnd="true"/>
-</merge>
\ No newline at end of file
+</merge>
diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml
index 6f50d5a..c7696b0 100644
--- a/core/res/res/values-af/strings.xml
+++ b/core/res/res/values-af/strings.xml
@@ -1167,14 +1167,10 @@
<string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Tik om taal en uitleg te kies"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
- <!-- no translation found for alert_windows_notification_channel_name (7443890103456396837) -->
- <skip />
- <!-- no translation found for alert_windows_notification_title (5399998516035621282) -->
- <skip />
- <!-- no translation found for alert_windows_notification_message (2456738662997073459) -->
- <skip />
- <!-- no translation found for alert_windows_notification_turn_off_action (3367294525884949878) -->
- <skip />
+ <string name="alert_windows_notification_channel_name" msgid="7443890103456396837">"<xliff:g id="NAME">%s</xliff:g> teken oor ander programme"</string>
+ <string name="alert_windows_notification_title" msgid="5399998516035621282">"<xliff:g id="NAME">%s</xliff:g>-program verskyn bo-op."</string>
+ <string name="alert_windows_notification_message" msgid="2456738662997073459">"Dele van hierdie program sal dalk altyd sigbaar wees. Skakel hierdie kenmerk af as dit nie reg werk nie."</string>
+ <string name="alert_windows_notification_turn_off_action" msgid="3367294525884949878">"SKAKEL AF"</string>
<string name="ext_media_checking_notification_title" msgid="5734005953288045806">"Berei tans <xliff:g id="NAME">%s</xliff:g> voor"</string>
<string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Kyk tans vir foute"</string>
<string name="ext_media_new_notification_message" msgid="7589986898808506239">"Nuwe <xliff:g id="NAME">%s</xliff:g> bespeur"</string>
@@ -1712,4 +1708,18 @@
<string name="time_picker_prompt_label" msgid="7588093983899966783">"Tik tyd in"</string>
<string name="time_picker_text_input_mode_description" msgid="4148166758173708199">"Skakel oor na teksmodus vir die tydinvoer."</string>
<string name="time_picker_radial_mode_description" msgid="4953403779779557198">"Skakel oor na horlosiemodus vir die tydinvoer."</string>
+ <!-- no translation found for autofill_save_title (7081244500504163245) -->
+ <skip />
+ <!-- no translation found for autofill_save_title_with_type (4977385733042555659) -->
+ <skip />
+ <!-- no translation found for autofill_save_yes (6398026094049005921) -->
+ <skip />
+ <!-- no translation found for autofill_save_no (2625132258725581787) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_password (5288448918465971568) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_address (4936707762193009542) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_credit_card (7127694776265563071) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml
index 5d68f37..a031ff8 100644
--- a/core/res/res/values-am/strings.xml
+++ b/core/res/res/values-am/strings.xml
@@ -1167,14 +1167,10 @@
<string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"ቋንቋ እና አቀማመጥን ለመምረጥ መታ ያድርጉ"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
- <!-- no translation found for alert_windows_notification_channel_name (7443890103456396837) -->
- <skip />
- <!-- no translation found for alert_windows_notification_title (5399998516035621282) -->
- <skip />
- <!-- no translation found for alert_windows_notification_message (2456738662997073459) -->
- <skip />
- <!-- no translation found for alert_windows_notification_turn_off_action (3367294525884949878) -->
- <skip />
+ <string name="alert_windows_notification_channel_name" msgid="7443890103456396837">"<xliff:g id="NAME">%s</xliff:g> በሌሎች መተግበሪያዎች ላይ ሣል"</string>
+ <string name="alert_windows_notification_title" msgid="5399998516035621282">"<xliff:g id="NAME">%s</xliff:g> መተግበሪያ ከላይ እየታየ ያለ።"</string>
+ <string name="alert_windows_notification_message" msgid="2456738662997073459">"የዚህ መተግበሪያ ክፍሎች በሁሉም ጊዜያት የሚታዩ እንደሆኑ ሊቆዩ ይችላሉ። ይህ ባህሪ በትክክል የማይሠራ ከሆነ ያጥፉት።"</string>
+ <string name="alert_windows_notification_turn_off_action" msgid="3367294525884949878">"አጥፋ"</string>
<string name="ext_media_checking_notification_title" msgid="5734005953288045806">"<xliff:g id="NAME">%s</xliff:g>ን በማዘጋጀት ላይ"</string>
<string name="ext_media_checking_notification_message" msgid="4747432538578886744">"ስህተቶች ካሉ በመፈተሽ ላይ"</string>
<string name="ext_media_new_notification_message" msgid="7589986898808506239">"አዲስ <xliff:g id="NAME">%s</xliff:g> ተገኝቷል"</string>
@@ -1712,4 +1708,18 @@
<string name="time_picker_prompt_label" msgid="7588093983899966783">"ሰዓት ይተይቡ"</string>
<string name="time_picker_text_input_mode_description" msgid="4148166758173708199">"ለጊዜ ግቤቱ ወደ የጽሑፍ ግቤት ሁነታ ቀይር።"</string>
<string name="time_picker_radial_mode_description" msgid="4953403779779557198">"ለጊዜ ግቤቱ ወደ የሰዓት ሁነታ ቀይር።"</string>
+ <!-- no translation found for autofill_save_title (7081244500504163245) -->
+ <skip />
+ <!-- no translation found for autofill_save_title_with_type (4977385733042555659) -->
+ <skip />
+ <!-- no translation found for autofill_save_yes (6398026094049005921) -->
+ <skip />
+ <!-- no translation found for autofill_save_no (2625132258725581787) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_password (5288448918465971568) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_address (4936707762193009542) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_credit_card (7127694776265563071) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index 92aa4fc..6d55ada 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -1247,14 +1247,10 @@
<string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"انقر لاختيار لغة وتنسيق"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" أ ب ت ث ج ح خ د ذ ر ز س ش ص ض ط ظ ع غ ف ق ك ل م ن ه و ي"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789 أ ب ت ث ج ح خ د ذ ر ز س ش ص ض ط ظ ع غ ف ق ك ل م ن ه و ي"</string>
- <!-- no translation found for alert_windows_notification_channel_name (7443890103456396837) -->
- <skip />
- <!-- no translation found for alert_windows_notification_title (5399998516035621282) -->
- <skip />
- <!-- no translation found for alert_windows_notification_message (2456738662997073459) -->
- <skip />
- <!-- no translation found for alert_windows_notification_turn_off_action (3367294525884949878) -->
- <skip />
+ <string name="alert_windows_notification_channel_name" msgid="7443890103456396837">"يتم عرض <xliff:g id="NAME">%s</xliff:g> فوق التطبيقات الأخرى"</string>
+ <string name="alert_windows_notification_title" msgid="5399998516035621282">"يتم عرض تطبيق <xliff:g id="NAME">%s</xliff:g> فوق التطبيقات."</string>
+ <string name="alert_windows_notification_message" msgid="2456738662997073459">"قد تظل أجزاء من هذا التطبيق مرئية في جميع الأوقات. فإذا كانت هذه الميزة لا تعمل بشكل صحيح، يمكنك إيقافها."</string>
+ <string name="alert_windows_notification_turn_off_action" msgid="3367294525884949878">"إيقاف"</string>
<string name="ext_media_checking_notification_title" msgid="5734005953288045806">"جارٍ تحضير <xliff:g id="NAME">%s</xliff:g>"</string>
<string name="ext_media_checking_notification_message" msgid="4747432538578886744">"جارٍ التحقق من الأخطاء"</string>
<string name="ext_media_new_notification_message" msgid="7589986898808506239">"تم اكتشاف <xliff:g id="NAME">%s</xliff:g> جديدة"</string>
@@ -1836,4 +1832,18 @@
<string name="time_picker_prompt_label" msgid="7588093983899966783">"يُرجى تحديد الوقت"</string>
<string name="time_picker_text_input_mode_description" msgid="4148166758173708199">"يُرجى التبديل إلى وضع إدخال النص لإدخال الوقت."</string>
<string name="time_picker_radial_mode_description" msgid="4953403779779557198">"يُرجى التبديل إلى وضع الساعة لإدخال الوقت."</string>
+ <!-- no translation found for autofill_save_title (7081244500504163245) -->
+ <skip />
+ <!-- no translation found for autofill_save_title_with_type (4977385733042555659) -->
+ <skip />
+ <!-- no translation found for autofill_save_yes (6398026094049005921) -->
+ <skip />
+ <!-- no translation found for autofill_save_no (2625132258725581787) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_password (5288448918465971568) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_address (4936707762193009542) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_credit_card (7127694776265563071) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-az/strings.xml b/core/res/res/values-az/strings.xml
index 43f0133..07ea197 100644
--- a/core/res/res/values-az/strings.xml
+++ b/core/res/res/values-az/strings.xml
@@ -1167,14 +1167,10 @@
<string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Dil və tərtibatı seçmək üçün tıklayın"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCÇDEƏFGĞHXIİJKQLMNOÖPRSŞTUÜVYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCÇDEƏFGĞHİIJKLMNOÖPQRSŞTUÜVWXYZ"</string>
- <!-- no translation found for alert_windows_notification_channel_name (7443890103456396837) -->
- <skip />
- <!-- no translation found for alert_windows_notification_title (5399998516035621282) -->
- <skip />
- <!-- no translation found for alert_windows_notification_message (2456738662997073459) -->
- <skip />
- <!-- no translation found for alert_windows_notification_turn_off_action (3367294525884949878) -->
- <skip />
+ <string name="alert_windows_notification_channel_name" msgid="7443890103456396837">"<xliff:g id="NAME">%s</xliff:g> digər tətbiqlərin üzərinə çəkilir"</string>
+ <string name="alert_windows_notification_title" msgid="5399998516035621282">"<xliff:g id="NAME">%s</xliff:g> tətbiqi üstdə göstərilir."</string>
+ <string name="alert_windows_notification_message" msgid="2456738662997073459">"Bu tətbiqin hissələri həmişə görünən qala bilər. Bu funksiya düzgün işləmirsə, onu deaktiv edin."</string>
+ <string name="alert_windows_notification_turn_off_action" msgid="3367294525884949878">"DEAKTİV EDİN"</string>
<string name="ext_media_checking_notification_title" msgid="5734005953288045806">"<xliff:g id="NAME">%s</xliff:g> hazırlanır"</string>
<string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Səhvlər yoxlanılır"</string>
<string name="ext_media_new_notification_message" msgid="7589986898808506239">"Yeni <xliff:g id="NAME">%s</xliff:g> aşkarlandı"</string>
@@ -1712,4 +1708,18 @@
<string name="time_picker_prompt_label" msgid="7588093983899966783">"Zamanı daxil edin"</string>
<string name="time_picker_text_input_mode_description" msgid="4148166758173708199">"Zamanı daxil etmək üçün mətnlə daxiletmə rejiminə keçin"</string>
<string name="time_picker_radial_mode_description" msgid="4953403779779557198">"Zamanı daxil etmək üçün saat rejiminə keçin"</string>
+ <!-- no translation found for autofill_save_title (7081244500504163245) -->
+ <skip />
+ <!-- no translation found for autofill_save_title_with_type (4977385733042555659) -->
+ <skip />
+ <!-- no translation found for autofill_save_yes (6398026094049005921) -->
+ <skip />
+ <!-- no translation found for autofill_save_no (2625132258725581787) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_password (5288448918465971568) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_address (4936707762193009542) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_credit_card (7127694776265563071) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-b+sr+Latn/strings.xml b/core/res/res/values-b+sr+Latn/strings.xml
index 9a02a43..894bd28 100644
--- a/core/res/res/values-b+sr+Latn/strings.xml
+++ b/core/res/res/values-b+sr+Latn/strings.xml
@@ -1187,14 +1187,10 @@
<string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Dodirnite da biste izabrali jezik i raspored"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
- <!-- no translation found for alert_windows_notification_channel_name (7443890103456396837) -->
- <skip />
- <!-- no translation found for alert_windows_notification_title (5399998516035621282) -->
- <skip />
- <!-- no translation found for alert_windows_notification_message (2456738662997073459) -->
- <skip />
- <!-- no translation found for alert_windows_notification_turn_off_action (3367294525884949878) -->
- <skip />
+ <string name="alert_windows_notification_channel_name" msgid="7443890103456396837">"Aplikacija <xliff:g id="NAME">%s</xliff:g> se prikazuje preko drugih aplikacija"</string>
+ <string name="alert_windows_notification_title" msgid="5399998516035621282">"Aplikacija <xliff:g id="NAME">%s</xliff:g> se prikazuje preko."</string>
+ <string name="alert_windows_notification_message" msgid="2456738662997073459">"Delovi ove aplikacije mogu da ostanu vidljivi u svakom trenutku. Ako ova funkcija ne radi ispravno, isključite je."</string>
+ <string name="alert_windows_notification_turn_off_action" msgid="3367294525884949878">"ISKLJUČI"</string>
<string name="ext_media_checking_notification_title" msgid="5734005953288045806">"<xliff:g id="NAME">%s</xliff:g> se priprema"</string>
<string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Proverava se da li postoje greške"</string>
<string name="ext_media_new_notification_message" msgid="7589986898808506239">"Novi uređaj <xliff:g id="NAME">%s</xliff:g> je otkriven"</string>
@@ -1743,4 +1739,18 @@
<string name="time_picker_prompt_label" msgid="7588093983899966783">"Unesite vreme"</string>
<string name="time_picker_text_input_mode_description" msgid="4148166758173708199">"Pređite u režim unosa teksta radi unosa vremena."</string>
<string name="time_picker_radial_mode_description" msgid="4953403779779557198">"Pređite u režim sata radi unosa vremena."</string>
+ <!-- no translation found for autofill_save_title (7081244500504163245) -->
+ <skip />
+ <!-- no translation found for autofill_save_title_with_type (4977385733042555659) -->
+ <skip />
+ <!-- no translation found for autofill_save_yes (6398026094049005921) -->
+ <skip />
+ <!-- no translation found for autofill_save_no (2625132258725581787) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_password (5288448918465971568) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_address (4936707762193009542) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_credit_card (7127694776265563071) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-be/strings.xml b/core/res/res/values-be/strings.xml
index 070dda7..d567c93 100644
--- a/core/res/res/values-be/strings.xml
+++ b/core/res/res/values-be/strings.xml
@@ -1207,14 +1207,10 @@
<string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Дакраніцеся, каб выбраць мову і раскладку"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" АБВГДЕЁЖЗІЙКЛМНОПРСТУЎФХЦЧШ\'ЫЬЭЮЯ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
- <!-- no translation found for alert_windows_notification_channel_name (7443890103456396837) -->
- <skip />
- <!-- no translation found for alert_windows_notification_title (5399998516035621282) -->
- <skip />
- <!-- no translation found for alert_windows_notification_message (2456738662997073459) -->
- <skip />
- <!-- no translation found for alert_windows_notification_turn_off_action (3367294525884949878) -->
- <skip />
+ <string name="alert_windows_notification_channel_name" msgid="7443890103456396837">"<xliff:g id="NAME">%s</xliff:g> паверх іншых праграм"</string>
+ <string name="alert_windows_notification_title" msgid="5399998516035621282">"Праграма <xliff:g id="NAME">%s</xliff:g> паказваецца зверху."</string>
+ <string name="alert_windows_notification_message" msgid="2456738662997073459">"Часткі гэтай праграмы могуць заставацца бачнымі ў любы час. Калі гэта функцыя не працуе належным чынам, адключыце яе."</string>
+ <string name="alert_windows_notification_turn_off_action" msgid="3367294525884949878">"АДКЛЮЧЫЦЬ"</string>
<string name="ext_media_checking_notification_title" msgid="5734005953288045806">"Падрыхтоўка <xliff:g id="NAME">%s</xliff:g>"</string>
<string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Праверка на наяўнасць памылак"</string>
<string name="ext_media_new_notification_message" msgid="7589986898808506239">"Выяўлены новы носьбіт <xliff:g id="NAME">%s</xliff:g>"</string>
@@ -1774,4 +1770,18 @@
<string name="time_picker_prompt_label" msgid="7588093983899966783">"Увядзіце час"</string>
<string name="time_picker_text_input_mode_description" msgid="4148166758173708199">"Пераключыцца на рэжым тэксту пры ўводзе часу."</string>
<string name="time_picker_radial_mode_description" msgid="4953403779779557198">"Пераключыцца на рэжым гадзінніка пры ўводзе часу."</string>
+ <!-- no translation found for autofill_save_title (7081244500504163245) -->
+ <skip />
+ <!-- no translation found for autofill_save_title_with_type (4977385733042555659) -->
+ <skip />
+ <!-- no translation found for autofill_save_yes (6398026094049005921) -->
+ <skip />
+ <!-- no translation found for autofill_save_no (2625132258725581787) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_password (5288448918465971568) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_address (4936707762193009542) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_credit_card (7127694776265563071) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml
index 10887a0..90d3bff 100644
--- a/core/res/res/values-bg/strings.xml
+++ b/core/res/res/values-bg/strings.xml
@@ -1167,14 +1167,10 @@
<string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Докоснете, за да изберете език и подредба"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
- <!-- no translation found for alert_windows_notification_channel_name (7443890103456396837) -->
- <skip />
- <!-- no translation found for alert_windows_notification_title (5399998516035621282) -->
- <skip />
- <!-- no translation found for alert_windows_notification_message (2456738662997073459) -->
- <skip />
- <!-- no translation found for alert_windows_notification_turn_off_action (3367294525884949878) -->
- <skip />
+ <string name="alert_windows_notification_channel_name" msgid="7443890103456396837">"<xliff:g id="NAME">%s</xliff:g> се изобразява върху други приложения"</string>
+ <string name="alert_windows_notification_title" msgid="5399998516035621282">"<xliff:g id="NAME">%s</xliff:g> се показва в/у други прилож."</string>
+ <string name="alert_windows_notification_message" msgid="2456738662997073459">"Части от това приложение може да останат видими за постоянно. Ако функцията не работи правилно, изключете я."</string>
+ <string name="alert_windows_notification_turn_off_action" msgid="3367294525884949878">"ИЗКЛЮЧВАНЕ"</string>
<string name="ext_media_checking_notification_title" msgid="5734005953288045806">"<xliff:g id="NAME">%s</xliff:g>: Подготвя се"</string>
<string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Проверява се за грешки"</string>
<string name="ext_media_new_notification_message" msgid="7589986898808506239">"Открито е ново хранилище (<xliff:g id="NAME">%s</xliff:g>)"</string>
@@ -1712,4 +1708,18 @@
<string name="time_picker_prompt_label" msgid="7588093983899966783">"Въведете часа"</string>
<string name="time_picker_text_input_mode_description" msgid="4148166758173708199">"Превключете към режима за въвеждане на текст, за да въведете часа."</string>
<string name="time_picker_radial_mode_description" msgid="4953403779779557198">"Превключете към режима за часовник, за да въведете часа."</string>
+ <!-- no translation found for autofill_save_title (7081244500504163245) -->
+ <skip />
+ <!-- no translation found for autofill_save_title_with_type (4977385733042555659) -->
+ <skip />
+ <!-- no translation found for autofill_save_yes (6398026094049005921) -->
+ <skip />
+ <!-- no translation found for autofill_save_no (2625132258725581787) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_password (5288448918465971568) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_address (4936707762193009542) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_credit_card (7127694776265563071) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-bn/strings.xml b/core/res/res/values-bn/strings.xml
index b6ebd71..1f5b0a1 100644
--- a/core/res/res/values-bn/strings.xml
+++ b/core/res/res/values-bn/strings.xml
@@ -1168,14 +1168,10 @@
<string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"ভাষা এবং লেআউট নির্বাচন করুন আলতো চাপ দিন"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
- <!-- no translation found for alert_windows_notification_channel_name (7443890103456396837) -->
- <skip />
- <!-- no translation found for alert_windows_notification_title (5399998516035621282) -->
- <skip />
- <!-- no translation found for alert_windows_notification_message (2456738662997073459) -->
- <skip />
- <!-- no translation found for alert_windows_notification_turn_off_action (3367294525884949878) -->
- <skip />
+ <string name="alert_windows_notification_channel_name" msgid="7443890103456396837">"<xliff:g id="NAME">%s</xliff:g> অন্যান্য অ্যাপের উপরেও দেখা যায়"</string>
+ <string name="alert_windows_notification_title" msgid="5399998516035621282">"<xliff:g id="NAME">%s</xliff:g> অ্যাপ সবার উপরে দেখা যাচ্ছে।"</string>
+ <string name="alert_windows_notification_message" msgid="2456738662997073459">"এই অ্যাপের কিছু কিছু অংশ সব সময় স্ক্রিনে দেখা যেতে পারে। যদি এই বৈশিষ্ট্যটি ঠিক ভাবে কাজ না করে, তাহলে অ্যাপটি বন্ধ করে দিন।"</string>
+ <string name="alert_windows_notification_turn_off_action" msgid="3367294525884949878">"বন্ধ করুন"</string>
<string name="ext_media_checking_notification_title" msgid="5734005953288045806">"<xliff:g id="NAME">%s</xliff:g> প্রস্তুত করা হচ্ছে"</string>
<string name="ext_media_checking_notification_message" msgid="4747432538578886744">"ত্রুটি রয়েছে কিনা পরীক্ষা করা হচ্ছে"</string>
<string name="ext_media_new_notification_message" msgid="7589986898808506239">"নতুন <xliff:g id="NAME">%s</xliff:g> সনাক্ত করা হয়েছে"</string>
@@ -1713,4 +1709,18 @@
<string name="time_picker_prompt_label" msgid="7588093983899966783">"সময় টাইপ করুন"</string>
<string name="time_picker_text_input_mode_description" msgid="4148166758173708199">"সময় ইনপুট দেওয়ার জন্য পাঠ্য ইনপুট মোডে যান।"</string>
<string name="time_picker_radial_mode_description" msgid="4953403779779557198">"সময় ইনপুট দেওয়ার জন্য ঘড়ি মোডে যান।"</string>
+ <!-- no translation found for autofill_save_title (7081244500504163245) -->
+ <skip />
+ <!-- no translation found for autofill_save_title_with_type (4977385733042555659) -->
+ <skip />
+ <!-- no translation found for autofill_save_yes (6398026094049005921) -->
+ <skip />
+ <!-- no translation found for autofill_save_no (2625132258725581787) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_password (5288448918465971568) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_address (4936707762193009542) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_credit_card (7127694776265563071) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-bs/strings.xml b/core/res/res/values-bs/strings.xml
index c63f92c..d0017ad 100644
--- a/core/res/res/values-bs/strings.xml
+++ b/core/res/res/values-bs/strings.xml
@@ -1190,14 +1190,10 @@
<string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Dodirnite za odabir jezika i rasporeda"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
- <!-- no translation found for alert_windows_notification_channel_name (7443890103456396837) -->
- <skip />
- <!-- no translation found for alert_windows_notification_title (5399998516035621282) -->
- <skip />
- <!-- no translation found for alert_windows_notification_message (2456738662997073459) -->
- <skip />
- <!-- no translation found for alert_windows_notification_turn_off_action (3367294525884949878) -->
- <skip />
+ <string name="alert_windows_notification_channel_name" msgid="7443890103456396837">"Aplikacija <xliff:g id="NAME">%s</xliff:g> prekriva ostale aplikacije"</string>
+ <string name="alert_windows_notification_title" msgid="5399998516035621282">"Apl. <xliff:g id="NAME">%s</xliff:g> prikazana je na vrhu."</string>
+ <string name="alert_windows_notification_message" msgid="2456738662997073459">"Dijelovi aplikacije mogu ostati vidljivi sve vrijeme. Ako ta funkcija ne radi ispravno, isključite je."</string>
+ <string name="alert_windows_notification_turn_off_action" msgid="3367294525884949878">"ISKLJUČI"</string>
<string name="ext_media_checking_notification_title" msgid="5734005953288045806">"Priprema se <xliff:g id="NAME">%s</xliff:g>"</string>
<string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Provjera grešaka"</string>
<string name="ext_media_new_notification_message" msgid="7589986898808506239">"Novi uređaj <xliff:g id="NAME">%s</xliff:g> je otkriven"</string>
@@ -1746,4 +1742,18 @@
<string name="time_picker_prompt_label" msgid="7588093983899966783">"Upišite vrijeme"</string>
<string name="time_picker_text_input_mode_description" msgid="4148166758173708199">"Prebacite u način unosa teksta za unos vremena."</string>
<string name="time_picker_radial_mode_description" msgid="4953403779779557198">"Prebacite u način rada kao sat za unos vremena."</string>
+ <!-- no translation found for autofill_save_title (7081244500504163245) -->
+ <skip />
+ <!-- no translation found for autofill_save_title_with_type (4977385733042555659) -->
+ <skip />
+ <!-- no translation found for autofill_save_yes (6398026094049005921) -->
+ <skip />
+ <!-- no translation found for autofill_save_no (2625132258725581787) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_password (5288448918465971568) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_address (4936707762193009542) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_credit_card (7127694776265563071) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index 507bc59..2402232 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -1167,14 +1167,10 @@
<string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Toca per seleccionar l\'idioma i el disseny"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
- <!-- no translation found for alert_windows_notification_channel_name (7443890103456396837) -->
- <skip />
- <!-- no translation found for alert_windows_notification_title (5399998516035621282) -->
- <skip />
- <!-- no translation found for alert_windows_notification_message (2456738662997073459) -->
- <skip />
- <!-- no translation found for alert_windows_notification_turn_off_action (3367294525884949878) -->
- <skip />
+ <string name="alert_windows_notification_channel_name" msgid="7443890103456396837">"<xliff:g id="NAME">%s</xliff:g> se superposa a altres aplicacions"</string>
+ <string name="alert_windows_notification_title" msgid="5399998516035621282">"L\'aplicació <xliff:g id="NAME">%s</xliff:g> s\'està superposant."</string>
+ <string name="alert_windows_notification_message" msgid="2456738662997073459">"Algunes parts d\'aquesta aplicació seran visibles en tot moment. Si aquesta funció presenta problemes, desactiva-la."</string>
+ <string name="alert_windows_notification_turn_off_action" msgid="3367294525884949878">"DESACTIVA"</string>
<string name="ext_media_checking_notification_title" msgid="5734005953288045806">"S\'està preparant <xliff:g id="NAME">%s</xliff:g>"</string>
<string name="ext_media_checking_notification_message" msgid="4747432538578886744">"S\'està comprovant si hi ha errors"</string>
<string name="ext_media_new_notification_message" msgid="7589986898808506239">"S\'ha detectat <xliff:g id="NAME">%s</xliff:g>"</string>
@@ -1712,4 +1708,18 @@
<string name="time_picker_prompt_label" msgid="7588093983899966783">"Escriu l\'hora"</string>
<string name="time_picker_text_input_mode_description" msgid="4148166758173708199">"Canvia al mode d\'introducció de text per introduir l\'hora."</string>
<string name="time_picker_radial_mode_description" msgid="4953403779779557198">"Canvia al mode de rellotge per introduir l\'hora."</string>
+ <!-- no translation found for autofill_save_title (7081244500504163245) -->
+ <skip />
+ <!-- no translation found for autofill_save_title_with_type (4977385733042555659) -->
+ <skip />
+ <!-- no translation found for autofill_save_yes (6398026094049005921) -->
+ <skip />
+ <!-- no translation found for autofill_save_no (2625132258725581787) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_password (5288448918465971568) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_address (4936707762193009542) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_credit_card (7127694776265563071) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index 41dc69b..7d59c43 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -1207,14 +1207,10 @@
<string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Klepnutím vyberte jazyk a rozvržení"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" AÁBCČDĎEÉĚFGHCHIÍJKLMNŇOÓPQRŘSŠTŤUÚVWXYÝZŽ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789AÁBCČDĎEÉĚFGHCHIÍJKLMNŇOÓPQRŘSŠTŤUÚVWXYÝZŽ"</string>
- <!-- no translation found for alert_windows_notification_channel_name (7443890103456396837) -->
- <skip />
- <!-- no translation found for alert_windows_notification_title (5399998516035621282) -->
- <skip />
- <!-- no translation found for alert_windows_notification_message (2456738662997073459) -->
- <skip />
- <!-- no translation found for alert_windows_notification_turn_off_action (3367294525884949878) -->
- <skip />
+ <string name="alert_windows_notification_channel_name" msgid="7443890103456396837">"Aplikace <xliff:g id="NAME">%s</xliff:g> se může vykreslovat přes ostatní aplikace"</string>
+ <string name="alert_windows_notification_title" msgid="5399998516035621282">"Aplikace <xliff:g id="NAME">%s</xliff:g> se zobrazuje nahoře."</string>
+ <string name="alert_windows_notification_message" msgid="2456738662997073459">"Části této aplikace mohou zůstat vždy viditelné. Pokud tato funkce nepracuje správně, vypněte ji."</string>
+ <string name="alert_windows_notification_turn_off_action" msgid="3367294525884949878">"VYPNOUT"</string>
<string name="ext_media_checking_notification_title" msgid="5734005953288045806">"Probíhá příprava úložiště <xliff:g id="NAME">%s</xliff:g>"</string>
<string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Kontrola chyb"</string>
<string name="ext_media_new_notification_message" msgid="7589986898808506239">"Zjištěno nové úložiště <xliff:g id="NAME">%s</xliff:g>"</string>
@@ -1774,4 +1770,18 @@
<string name="time_picker_prompt_label" msgid="7588093983899966783">"Zadejte čas"</string>
<string name="time_picker_text_input_mode_description" msgid="4148166758173708199">"Chcete-li zadat čas, přepněte na režim textu."</string>
<string name="time_picker_radial_mode_description" msgid="4953403779779557198">"Chcete-li zadat čas, přepněte na režim hodin."</string>
+ <!-- no translation found for autofill_save_title (7081244500504163245) -->
+ <skip />
+ <!-- no translation found for autofill_save_title_with_type (4977385733042555659) -->
+ <skip />
+ <!-- no translation found for autofill_save_yes (6398026094049005921) -->
+ <skip />
+ <!-- no translation found for autofill_save_no (2625132258725581787) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_password (5288448918465971568) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_address (4936707762193009542) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_credit_card (7127694776265563071) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index 2d19eb6..c62cece 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -1167,14 +1167,10 @@
<string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Tryk for at vælge sprog og layout"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
- <!-- no translation found for alert_windows_notification_channel_name (7443890103456396837) -->
- <skip />
- <!-- no translation found for alert_windows_notification_title (5399998516035621282) -->
- <skip />
- <!-- no translation found for alert_windows_notification_message (2456738662997073459) -->
- <skip />
- <!-- no translation found for alert_windows_notification_turn_off_action (3367294525884949878) -->
- <skip />
+ <string name="alert_windows_notification_channel_name" msgid="7443890103456396837">"<xliff:g id="NAME">%s</xliff:g> vises over andre apps"</string>
+ <string name="alert_windows_notification_title" msgid="5399998516035621282">"Appen <xliff:g id="NAME">%s</xliff:g> vises øverst."</string>
+ <string name="alert_windows_notification_message" msgid="2456738662997073459">"Dele af denne app kan være synlig hele tiden. Deaktiver denne funktion, hvis den ikke fungerer korrekt."</string>
+ <string name="alert_windows_notification_turn_off_action" msgid="3367294525884949878">"SLÅ FRA"</string>
<string name="ext_media_checking_notification_title" msgid="5734005953288045806">"Forbereder <xliff:g id="NAME">%s</xliff:g>"</string>
<string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Kontrollerer for fejl"</string>
<string name="ext_media_new_notification_message" msgid="7589986898808506239">"Der blev registreret et nyt <xliff:g id="NAME">%s</xliff:g>"</string>
@@ -1712,4 +1708,18 @@
<string name="time_picker_prompt_label" msgid="7588093983899966783">"Angiv klokkeslæt"</string>
<string name="time_picker_text_input_mode_description" msgid="4148166758173708199">"Skift til teksttilstand for at angive klokkeslæt."</string>
<string name="time_picker_radial_mode_description" msgid="4953403779779557198">"Skift til urtilstand for at angive klokkeslæt."</string>
+ <!-- no translation found for autofill_save_title (7081244500504163245) -->
+ <skip />
+ <!-- no translation found for autofill_save_title_with_type (4977385733042555659) -->
+ <skip />
+ <!-- no translation found for autofill_save_yes (6398026094049005921) -->
+ <skip />
+ <!-- no translation found for autofill_save_no (2625132258725581787) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_password (5288448918465971568) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_address (4936707762193009542) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_credit_card (7127694776265563071) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index 054af7c..4564231 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -1167,14 +1167,10 @@
<string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Zum Auswählen von Sprache und Layout tippen"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
- <!-- no translation found for alert_windows_notification_channel_name (7443890103456396837) -->
- <skip />
- <!-- no translation found for alert_windows_notification_title (5399998516035621282) -->
- <skip />
- <!-- no translation found for alert_windows_notification_message (2456738662997073459) -->
- <skip />
- <!-- no translation found for alert_windows_notification_turn_off_action (3367294525884949878) -->
- <skip />
+ <string name="alert_windows_notification_channel_name" msgid="7443890103456396837">"<xliff:g id="NAME">%s</xliff:g> wird über anderen Apps eingeblendet"</string>
+ <string name="alert_windows_notification_title" msgid="5399998516035621282">"Die App \"<xliff:g id="NAME">%s</xliff:g>\" wird über anderen Apps angezeigt."</string>
+ <string name="alert_windows_notification_message" msgid="2456738662997073459">"Teile dieser App werden die ganze Zeit eingeblendet. Wenn diese Funktion nicht richtig funktioniert, deaktiviere sie."</string>
+ <string name="alert_windows_notification_turn_off_action" msgid="3367294525884949878">"DEAKTIVIEREN"</string>
<string name="ext_media_checking_notification_title" msgid="5734005953288045806">"<xliff:g id="NAME">%s</xliff:g> wird vorbereitet"</string>
<string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Nach Fehlern wird gesucht"</string>
<string name="ext_media_new_notification_message" msgid="7589986898808506239">"Neue <xliff:g id="NAME">%s</xliff:g> entdeckt"</string>
@@ -1712,4 +1708,18 @@
<string name="time_picker_prompt_label" msgid="7588093983899966783">"Uhrzeit eingeben"</string>
<string name="time_picker_text_input_mode_description" msgid="4148166758173708199">"In den Texteingabemodus wechseln, um die Uhrzeit einzugeben."</string>
<string name="time_picker_radial_mode_description" msgid="4953403779779557198">"In den Uhrzeitmodus wechseln, um die Uhrzeit einzugeben."</string>
+ <!-- no translation found for autofill_save_title (7081244500504163245) -->
+ <skip />
+ <!-- no translation found for autofill_save_title_with_type (4977385733042555659) -->
+ <skip />
+ <!-- no translation found for autofill_save_yes (6398026094049005921) -->
+ <skip />
+ <!-- no translation found for autofill_save_no (2625132258725581787) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_password (5288448918465971568) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_address (4936707762193009542) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_credit_card (7127694776265563071) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml
index 48bd718..cd6c67b 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -1167,14 +1167,10 @@
<string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Πατήστε για να επιλέξετε γλώσσα και διάταξη"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
- <!-- no translation found for alert_windows_notification_channel_name (7443890103456396837) -->
- <skip />
- <!-- no translation found for alert_windows_notification_title (5399998516035621282) -->
- <skip />
- <!-- no translation found for alert_windows_notification_message (2456738662997073459) -->
- <skip />
- <!-- no translation found for alert_windows_notification_turn_off_action (3367294525884949878) -->
- <skip />
+ <string name="alert_windows_notification_channel_name" msgid="7443890103456396837">"Η εφαρμογή <xliff:g id="NAME">%s</xliff:g> επικάλυψε άλλες εφαρμογές"</string>
+ <string name="alert_windows_notification_title" msgid="5399998516035621282">"Η εφαρμογή <xliff:g id="NAME">%s</xliff:g> επικαλύπτει άλλες."</string>
+ <string name="alert_windows_notification_message" msgid="2456738662997073459">"Ορισμένα τμήματα αυτής της εφαρμογής μπορεί να παραμένουν συνεχώς ορατά. Εάν αυτή η λειτουργία δεν εκτελείται σωστά, απενεργοποιήστε την."</string>
+ <string name="alert_windows_notification_turn_off_action" msgid="3367294525884949878">"ΑΠΕΝΕΡΓΟΠΟΙΗΣΗ"</string>
<string name="ext_media_checking_notification_title" msgid="5734005953288045806">"Προετοιμασία <xliff:g id="NAME">%s</xliff:g>"</string>
<string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Έλεγχος για σφάλματα"</string>
<string name="ext_media_new_notification_message" msgid="7589986898808506239">"Εντοπίστηκε νέο μέσο αποθήκευσης <xliff:g id="NAME">%s</xliff:g>"</string>
@@ -1712,4 +1708,18 @@
<string name="time_picker_prompt_label" msgid="7588093983899966783">"Πληκτρολογήστε την ώρα"</string>
<string name="time_picker_text_input_mode_description" msgid="4148166758173708199">"Κάντε εναλλαγή στη λειτουργία εισαγωγής κειμένου, για την εισαγωγή της ώρας."</string>
<string name="time_picker_radial_mode_description" msgid="4953403779779557198">"Κάντε εναλλαγή στη λειτουργία ρολογιού, για την εισαγωγή της ώρας."</string>
+ <!-- no translation found for autofill_save_title (7081244500504163245) -->
+ <skip />
+ <!-- no translation found for autofill_save_title_with_type (4977385733042555659) -->
+ <skip />
+ <!-- no translation found for autofill_save_yes (6398026094049005921) -->
+ <skip />
+ <!-- no translation found for autofill_save_no (2625132258725581787) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_password (5288448918465971568) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_address (4936707762193009542) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_credit_card (7127694776265563071) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-en-rAU/strings.xml b/core/res/res/values-en-rAU/strings.xml
index 08fc5ba..04f9537 100644
--- a/core/res/res/values-en-rAU/strings.xml
+++ b/core/res/res/values-en-rAU/strings.xml
@@ -1167,14 +1167,10 @@
<string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Tap to select language and layout"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
- <!-- no translation found for alert_windows_notification_channel_name (7443890103456396837) -->
- <skip />
- <!-- no translation found for alert_windows_notification_title (5399998516035621282) -->
- <skip />
- <!-- no translation found for alert_windows_notification_message (2456738662997073459) -->
- <skip />
- <!-- no translation found for alert_windows_notification_turn_off_action (3367294525884949878) -->
- <skip />
+ <string name="alert_windows_notification_channel_name" msgid="7443890103456396837">"<xliff:g id="NAME">%s</xliff:g> draw over other apps"</string>
+ <string name="alert_windows_notification_title" msgid="5399998516035621282">"<xliff:g id="NAME">%s</xliff:g> app displaying on top."</string>
+ <string name="alert_windows_notification_message" msgid="2456738662997073459">"Parts of this app may remain visible at all times. If this feature isn\'t working correctly, turn it off."</string>
+ <string name="alert_windows_notification_turn_off_action" msgid="3367294525884949878">"TURN OFF"</string>
<string name="ext_media_checking_notification_title" msgid="5734005953288045806">"Preparing <xliff:g id="NAME">%s</xliff:g>"</string>
<string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Checking for errors"</string>
<string name="ext_media_new_notification_message" msgid="7589986898808506239">"New <xliff:g id="NAME">%s</xliff:g> detected"</string>
@@ -1712,4 +1708,18 @@
<string name="time_picker_prompt_label" msgid="7588093983899966783">"Type in time"</string>
<string name="time_picker_text_input_mode_description" msgid="4148166758173708199">"Switch to text input mode for the time input."</string>
<string name="time_picker_radial_mode_description" msgid="4953403779779557198">"Switch to clock mode for the time input."</string>
+ <!-- no translation found for autofill_save_title (7081244500504163245) -->
+ <skip />
+ <!-- no translation found for autofill_save_title_with_type (4977385733042555659) -->
+ <skip />
+ <!-- no translation found for autofill_save_yes (6398026094049005921) -->
+ <skip />
+ <!-- no translation found for autofill_save_no (2625132258725581787) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_password (5288448918465971568) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_address (4936707762193009542) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_credit_card (7127694776265563071) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml
index 08fc5ba..04f9537 100644
--- a/core/res/res/values-en-rGB/strings.xml
+++ b/core/res/res/values-en-rGB/strings.xml
@@ -1167,14 +1167,10 @@
<string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Tap to select language and layout"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
- <!-- no translation found for alert_windows_notification_channel_name (7443890103456396837) -->
- <skip />
- <!-- no translation found for alert_windows_notification_title (5399998516035621282) -->
- <skip />
- <!-- no translation found for alert_windows_notification_message (2456738662997073459) -->
- <skip />
- <!-- no translation found for alert_windows_notification_turn_off_action (3367294525884949878) -->
- <skip />
+ <string name="alert_windows_notification_channel_name" msgid="7443890103456396837">"<xliff:g id="NAME">%s</xliff:g> draw over other apps"</string>
+ <string name="alert_windows_notification_title" msgid="5399998516035621282">"<xliff:g id="NAME">%s</xliff:g> app displaying on top."</string>
+ <string name="alert_windows_notification_message" msgid="2456738662997073459">"Parts of this app may remain visible at all times. If this feature isn\'t working correctly, turn it off."</string>
+ <string name="alert_windows_notification_turn_off_action" msgid="3367294525884949878">"TURN OFF"</string>
<string name="ext_media_checking_notification_title" msgid="5734005953288045806">"Preparing <xliff:g id="NAME">%s</xliff:g>"</string>
<string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Checking for errors"</string>
<string name="ext_media_new_notification_message" msgid="7589986898808506239">"New <xliff:g id="NAME">%s</xliff:g> detected"</string>
@@ -1712,4 +1708,18 @@
<string name="time_picker_prompt_label" msgid="7588093983899966783">"Type in time"</string>
<string name="time_picker_text_input_mode_description" msgid="4148166758173708199">"Switch to text input mode for the time input."</string>
<string name="time_picker_radial_mode_description" msgid="4953403779779557198">"Switch to clock mode for the time input."</string>
+ <!-- no translation found for autofill_save_title (7081244500504163245) -->
+ <skip />
+ <!-- no translation found for autofill_save_title_with_type (4977385733042555659) -->
+ <skip />
+ <!-- no translation found for autofill_save_yes (6398026094049005921) -->
+ <skip />
+ <!-- no translation found for autofill_save_no (2625132258725581787) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_password (5288448918465971568) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_address (4936707762193009542) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_credit_card (7127694776265563071) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-en-rIN/strings.xml b/core/res/res/values-en-rIN/strings.xml
index 08fc5ba..04f9537 100644
--- a/core/res/res/values-en-rIN/strings.xml
+++ b/core/res/res/values-en-rIN/strings.xml
@@ -1167,14 +1167,10 @@
<string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Tap to select language and layout"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
- <!-- no translation found for alert_windows_notification_channel_name (7443890103456396837) -->
- <skip />
- <!-- no translation found for alert_windows_notification_title (5399998516035621282) -->
- <skip />
- <!-- no translation found for alert_windows_notification_message (2456738662997073459) -->
- <skip />
- <!-- no translation found for alert_windows_notification_turn_off_action (3367294525884949878) -->
- <skip />
+ <string name="alert_windows_notification_channel_name" msgid="7443890103456396837">"<xliff:g id="NAME">%s</xliff:g> draw over other apps"</string>
+ <string name="alert_windows_notification_title" msgid="5399998516035621282">"<xliff:g id="NAME">%s</xliff:g> app displaying on top."</string>
+ <string name="alert_windows_notification_message" msgid="2456738662997073459">"Parts of this app may remain visible at all times. If this feature isn\'t working correctly, turn it off."</string>
+ <string name="alert_windows_notification_turn_off_action" msgid="3367294525884949878">"TURN OFF"</string>
<string name="ext_media_checking_notification_title" msgid="5734005953288045806">"Preparing <xliff:g id="NAME">%s</xliff:g>"</string>
<string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Checking for errors"</string>
<string name="ext_media_new_notification_message" msgid="7589986898808506239">"New <xliff:g id="NAME">%s</xliff:g> detected"</string>
@@ -1712,4 +1708,18 @@
<string name="time_picker_prompt_label" msgid="7588093983899966783">"Type in time"</string>
<string name="time_picker_text_input_mode_description" msgid="4148166758173708199">"Switch to text input mode for the time input."</string>
<string name="time_picker_radial_mode_description" msgid="4953403779779557198">"Switch to clock mode for the time input."</string>
+ <!-- no translation found for autofill_save_title (7081244500504163245) -->
+ <skip />
+ <!-- no translation found for autofill_save_title_with_type (4977385733042555659) -->
+ <skip />
+ <!-- no translation found for autofill_save_yes (6398026094049005921) -->
+ <skip />
+ <!-- no translation found for autofill_save_no (2625132258725581787) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_password (5288448918465971568) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_address (4936707762193009542) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_credit_card (7127694776265563071) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index f294d6f..8aaa2ea 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -1167,14 +1167,10 @@
<string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Presiona para seleccionar el idioma y el diseño"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
- <!-- no translation found for alert_windows_notification_channel_name (7443890103456396837) -->
- <skip />
- <!-- no translation found for alert_windows_notification_title (5399998516035621282) -->
- <skip />
- <!-- no translation found for alert_windows_notification_message (2456738662997073459) -->
- <skip />
- <!-- no translation found for alert_windows_notification_turn_off_action (3367294525884949878) -->
- <skip />
+ <string name="alert_windows_notification_channel_name" msgid="7443890103456396837">"<xliff:g id="NAME">%s</xliff:g> se muestra sobre otras apps"</string>
+ <string name="alert_windows_notification_title" msgid="5399998516035621282">"<xliff:g id="NAME">%s</xliff:g> se muestra sobre otras apps"</string>
+ <string name="alert_windows_notification_message" msgid="2456738662997073459">"Es posible que ciertas partes de esta app permanezcan visibles todo el tiempo. Si esta función tiene problemas, desactívala."</string>
+ <string name="alert_windows_notification_turn_off_action" msgid="3367294525884949878">"DESACTIVAR"</string>
<string name="ext_media_checking_notification_title" msgid="5734005953288045806">"Preparando el medio <xliff:g id="NAME">%s</xliff:g>"</string>
<string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Verificando errores"</string>
<string name="ext_media_new_notification_message" msgid="7589986898808506239">"Se detectó un nuevo medio (<xliff:g id="NAME">%s</xliff:g>)."</string>
@@ -1712,4 +1708,18 @@
<string name="time_picker_prompt_label" msgid="7588093983899966783">"Ingresa la hora"</string>
<string name="time_picker_text_input_mode_description" msgid="4148166758173708199">"Cambia al modo de entrada de texto para ingresar la hora."</string>
<string name="time_picker_radial_mode_description" msgid="4953403779779557198">"Cambia al modo de reloj para ingresar la hora."</string>
+ <!-- no translation found for autofill_save_title (7081244500504163245) -->
+ <skip />
+ <!-- no translation found for autofill_save_title_with_type (4977385733042555659) -->
+ <skip />
+ <!-- no translation found for autofill_save_yes (6398026094049005921) -->
+ <skip />
+ <!-- no translation found for autofill_save_no (2625132258725581787) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_password (5288448918465971568) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_address (4936707762193009542) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_credit_card (7127694776265563071) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index 34aee0d..0ce96e7 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -1167,14 +1167,10 @@
<string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Toca para seleccionar el idioma y el diseño"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
- <!-- no translation found for alert_windows_notification_channel_name (7443890103456396837) -->
- <skip />
- <!-- no translation found for alert_windows_notification_title (5399998516035621282) -->
- <skip />
- <!-- no translation found for alert_windows_notification_message (2456738662997073459) -->
- <skip />
- <!-- no translation found for alert_windows_notification_turn_off_action (3367294525884949878) -->
- <skip />
+ <string name="alert_windows_notification_channel_name" msgid="7443890103456396837">"<xliff:g id="NAME">%s</xliff:g> se muestra sobre otras aplicaciones"</string>
+ <string name="alert_windows_notification_title" msgid="5399998516035621282">"<xliff:g id="NAME">%s</xliff:g> se muestra en primer plano."</string>
+ <string name="alert_windows_notification_message" msgid="2456738662997073459">"Es posible que algunas partes de esta aplicación permanezcan visibles en todo momento. Desactiva esta función si no funciona correctamente."</string>
+ <string name="alert_windows_notification_turn_off_action" msgid="3367294525884949878">"DESACTIVAR"</string>
<string name="ext_media_checking_notification_title" msgid="5734005953288045806">"Preparando <xliff:g id="NAME">%s</xliff:g>"</string>
<string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Comprobando errores"</string>
<string name="ext_media_new_notification_message" msgid="7589986898808506239">"Nueva <xliff:g id="NAME">%s</xliff:g> detectada"</string>
@@ -1712,4 +1708,18 @@
<string name="time_picker_prompt_label" msgid="7588093983899966783">"Escribe la hora"</string>
<string name="time_picker_text_input_mode_description" msgid="4148166758173708199">"Cambia al modo de introducción de texto para escribir la hora."</string>
<string name="time_picker_radial_mode_description" msgid="4953403779779557198">"Cambia al modo de reloj para escribir la hora."</string>
+ <!-- no translation found for autofill_save_title (7081244500504163245) -->
+ <skip />
+ <!-- no translation found for autofill_save_title_with_type (4977385733042555659) -->
+ <skip />
+ <!-- no translation found for autofill_save_yes (6398026094049005921) -->
+ <skip />
+ <!-- no translation found for autofill_save_no (2625132258725581787) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_password (5288448918465971568) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_address (4936707762193009542) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_credit_card (7127694776265563071) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-et/strings.xml b/core/res/res/values-et/strings.xml
index 7acb404..27cd957 100644
--- a/core/res/res/values-et/strings.xml
+++ b/core/res/res/values-et/strings.xml
@@ -1167,14 +1167,10 @@
<string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Puudutage keele ja paigutuse valimiseks"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSŠZŽTUVWÕÄÖÜXY"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSŠZŽTUVWÕÄÖÜXY"</string>
- <!-- no translation found for alert_windows_notification_channel_name (7443890103456396837) -->
- <skip />
- <!-- no translation found for alert_windows_notification_title (5399998516035621282) -->
- <skip />
- <!-- no translation found for alert_windows_notification_message (2456738662997073459) -->
- <skip />
- <!-- no translation found for alert_windows_notification_turn_off_action (3367294525884949878) -->
- <skip />
+ <string name="alert_windows_notification_channel_name" msgid="7443890103456396837">"Rakendus <xliff:g id="NAME">%s</xliff:g> joonistab teiste rakenduste peale"</string>
+ <string name="alert_windows_notification_title" msgid="5399998516035621282">"Rakend. <xliff:g id="NAME">%s</xliff:g> kuvatakse kõige peal."</string>
+ <string name="alert_windows_notification_message" msgid="2456738662997073459">"Selle rakenduse osad võivad alati nähtaval olla. Kui see funktsioon ei tööta korralikult, lülitage see välja."</string>
+ <string name="alert_windows_notification_turn_off_action" msgid="3367294525884949878">"LÜLITA VÄLJA"</string>
<string name="ext_media_checking_notification_title" msgid="5734005953288045806">"Üksuse <xliff:g id="NAME">%s</xliff:g> ettevalmistamine"</string>
<string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Vigade kontrollimine"</string>
<string name="ext_media_new_notification_message" msgid="7589986898808506239">"Tuvastati uus üksus <xliff:g id="NAME">%s</xliff:g>"</string>
@@ -1712,4 +1708,18 @@
<string name="time_picker_prompt_label" msgid="7588093983899966783">"Sisestage kellaaeg"</string>
<string name="time_picker_text_input_mode_description" msgid="4148166758173708199">"Aktiveerige kellaaja sisestamiseks tekstisisestusrežiim."</string>
<string name="time_picker_radial_mode_description" msgid="4953403779779557198">"Aktiveerige kellaaja sisestamiseks kellarežiim."</string>
+ <!-- no translation found for autofill_save_title (7081244500504163245) -->
+ <skip />
+ <!-- no translation found for autofill_save_title_with_type (4977385733042555659) -->
+ <skip />
+ <!-- no translation found for autofill_save_yes (6398026094049005921) -->
+ <skip />
+ <!-- no translation found for autofill_save_no (2625132258725581787) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_password (5288448918465971568) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_address (4936707762193009542) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_credit_card (7127694776265563071) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-eu/strings.xml b/core/res/res/values-eu/strings.xml
index 2fb79ec..5fb9998 100644
--- a/core/res/res/values-eu/strings.xml
+++ b/core/res/res/values-eu/strings.xml
@@ -1168,14 +1168,10 @@
<string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Hizkuntza eta diseinua hautatzeko, sakatu hau"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
- <!-- no translation found for alert_windows_notification_channel_name (7443890103456396837) -->
- <skip />
- <!-- no translation found for alert_windows_notification_title (5399998516035621282) -->
- <skip />
- <!-- no translation found for alert_windows_notification_message (2456738662997073459) -->
- <skip />
- <!-- no translation found for alert_windows_notification_turn_off_action (3367294525884949878) -->
- <skip />
+ <string name="alert_windows_notification_channel_name" msgid="7443890103456396837">"<xliff:g id="NAME">%s</xliff:g> zerbitzuak beste aplikazio batzuk gainjarri ditu pantailan"</string>
+ <string name="alert_windows_notification_title" msgid="5399998516035621282">"<xliff:g id="NAME">%s</xliff:g> gainjarri da pantailan."</string>
+ <string name="alert_windows_notification_message" msgid="2456738662997073459">"Aplikazioaren atal batzuk ikusgai gera litezke uneoro. Eginbideak behar bezala funtzionatzen ez badu, desaktiba ezazu."</string>
+ <string name="alert_windows_notification_turn_off_action" msgid="3367294525884949878">"DESAKTIBATU"</string>
<string name="ext_media_checking_notification_title" msgid="5734005953288045806">"<xliff:g id="NAME">%s</xliff:g> prestatzen"</string>
<string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Errorerik dagoen egiaztatzen"</string>
<string name="ext_media_new_notification_message" msgid="7589986898808506239">"<xliff:g id="NAME">%s</xliff:g> berria hauteman da"</string>
@@ -1713,4 +1709,18 @@
<string name="time_picker_prompt_label" msgid="7588093983899966783">"Idatzi ordua"</string>
<string name="time_picker_text_input_mode_description" msgid="4148166758173708199">"Aldatu testu modura ordua zehazteko."</string>
<string name="time_picker_radial_mode_description" msgid="4953403779779557198">"Aldatu erloju modura ordua zehazteko."</string>
+ <!-- no translation found for autofill_save_title (7081244500504163245) -->
+ <skip />
+ <!-- no translation found for autofill_save_title_with_type (4977385733042555659) -->
+ <skip />
+ <!-- no translation found for autofill_save_yes (6398026094049005921) -->
+ <skip />
+ <!-- no translation found for autofill_save_no (2625132258725581787) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_password (5288448918465971568) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_address (4936707762193009542) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_credit_card (7127694776265563071) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index 81606dd..51eb178 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -1167,14 +1167,10 @@
<string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"برای انتخاب زبان و چیدمان ضربه بزنید"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
- <!-- no translation found for alert_windows_notification_channel_name (7443890103456396837) -->
- <skip />
- <!-- no translation found for alert_windows_notification_title (5399998516035621282) -->
- <skip />
- <!-- no translation found for alert_windows_notification_message (2456738662997073459) -->
- <skip />
- <!-- no translation found for alert_windows_notification_turn_off_action (3367294525884949878) -->
- <skip />
+ <string name="alert_windows_notification_channel_name" msgid="7443890103456396837">"نمایش <xliff:g id="NAME">%s</xliff:g> روی برنامههای دیگر"</string>
+ <string name="alert_windows_notification_title" msgid="5399998516035621282">"نمایش برنامه <xliff:g id="NAME">%s</xliff:g> در بالا."</string>
+ <string name="alert_windows_notification_message" msgid="2456738662997073459">"ممکن است قسمتهایی از این برنامه همیشه قابل مشاهده بمانند. اگر این قابلیت بهدرستی کار نمیکند، آن را خاموش کنید."</string>
+ <string name="alert_windows_notification_turn_off_action" msgid="3367294525884949878">"خاموش کردن"</string>
<string name="ext_media_checking_notification_title" msgid="5734005953288045806">"در حال آمادهسازی <xliff:g id="NAME">%s</xliff:g>"</string>
<string name="ext_media_checking_notification_message" msgid="4747432538578886744">"در حال بررسی برای خطاها"</string>
<string name="ext_media_new_notification_message" msgid="7589986898808506239">"<xliff:g id="NAME">%s</xliff:g> جدید شناسایی شد"</string>
@@ -1712,4 +1708,18 @@
<string name="time_picker_prompt_label" msgid="7588093983899966783">"زمان را تایپ کنید"</string>
<string name="time_picker_text_input_mode_description" msgid="4148166758173708199">"برای وارد کردن زمان، به حالت وارد کردن نوشتار تغییر وضعیت دهید."</string>
<string name="time_picker_radial_mode_description" msgid="4953403779779557198">"برای وارد کردن زمان، به حالت ساعت تغییر وضعیت دهید."</string>
+ <!-- no translation found for autofill_save_title (7081244500504163245) -->
+ <skip />
+ <!-- no translation found for autofill_save_title_with_type (4977385733042555659) -->
+ <skip />
+ <!-- no translation found for autofill_save_yes (6398026094049005921) -->
+ <skip />
+ <!-- no translation found for autofill_save_no (2625132258725581787) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_password (5288448918465971568) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_address (4936707762193009542) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_credit_card (7127694776265563071) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml
index 1169f57..87f3214 100644
--- a/core/res/res/values-fi/strings.xml
+++ b/core/res/res/values-fi/strings.xml
@@ -1167,14 +1167,10 @@
<string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Valitse kieli ja asettelu koskettamalla."</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZÅÄÖ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
- <!-- no translation found for alert_windows_notification_channel_name (7443890103456396837) -->
- <skip />
- <!-- no translation found for alert_windows_notification_title (5399998516035621282) -->
- <skip />
- <!-- no translation found for alert_windows_notification_message (2456738662997073459) -->
- <skip />
- <!-- no translation found for alert_windows_notification_turn_off_action (3367294525884949878) -->
- <skip />
+ <string name="alert_windows_notification_channel_name" msgid="7443890103456396837">"<xliff:g id="NAME">%s</xliff:g> piirtää muiden sovellusten päälle"</string>
+ <string name="alert_windows_notification_title" msgid="5399998516035621282">"Sovellus <xliff:g id="NAME">%s</xliff:g> näkyy päällä"</string>
+ <string name="alert_windows_notification_message" msgid="2456738662997073459">"Osia sovelluksesta voi olla aina näkyvissä. Jos ominaisuus ei toimi oikein, poista se käytöstä."</string>
+ <string name="alert_windows_notification_turn_off_action" msgid="3367294525884949878">"POISTA KÄYTÖSTÄ"</string>
<string name="ext_media_checking_notification_title" msgid="5734005953288045806">"Valmistellaan kohdetta <xliff:g id="NAME">%s</xliff:g>"</string>
<string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Tarkistetaan virheiden varalta."</string>
<string name="ext_media_new_notification_message" msgid="7589986898808506239">"Uusi <xliff:g id="NAME">%s</xliff:g> on havaittu."</string>
@@ -1712,4 +1708,18 @@
<string name="time_picker_prompt_label" msgid="7588093983899966783">"Kirjoita aika"</string>
<string name="time_picker_text_input_mode_description" msgid="4148166758173708199">"Vaihda ajan syöttämiseen tekstitilassa."</string>
<string name="time_picker_radial_mode_description" msgid="4953403779779557198">"Vaihda ajan syöttämiseen kellotilassa."</string>
+ <!-- no translation found for autofill_save_title (7081244500504163245) -->
+ <skip />
+ <!-- no translation found for autofill_save_title_with_type (4977385733042555659) -->
+ <skip />
+ <!-- no translation found for autofill_save_yes (6398026094049005921) -->
+ <skip />
+ <!-- no translation found for autofill_save_no (2625132258725581787) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_password (5288448918465971568) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_address (4936707762193009542) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_credit_card (7127694776265563071) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml
index 43ff0cf..7b05c74 100644
--- a/core/res/res/values-fr-rCA/strings.xml
+++ b/core/res/res/values-fr-rCA/strings.xml
@@ -1167,14 +1167,10 @@
<string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Touchez pour sélectionner la langue et la configuration du clavier"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
- <!-- no translation found for alert_windows_notification_channel_name (7443890103456396837) -->
- <skip />
- <!-- no translation found for alert_windows_notification_title (5399998516035621282) -->
- <skip />
- <!-- no translation found for alert_windows_notification_message (2456738662997073459) -->
- <skip />
- <!-- no translation found for alert_windows_notification_turn_off_action (3367294525884949878) -->
- <skip />
+ <string name="alert_windows_notification_channel_name" msgid="7443890103456396837">"<xliff:g id="NAME">%s</xliff:g> se superpose aux autres applications"</string>
+ <string name="alert_windows_notification_title" msgid="5399998516035621282">"<xliff:g id="NAME">%s</xliff:g> s\'affiche par-dessus les autres"</string>
+ <string name="alert_windows_notification_message" msgid="2456738662997073459">"Certaines parties de cette application restent visibles en tout temps. Si cette option ne fonctionne pas correctement, désactivez-la."</string>
+ <string name="alert_windows_notification_turn_off_action" msgid="3367294525884949878">"DÉSACTIVER"</string>
<string name="ext_media_checking_notification_title" msgid="5734005953288045806">"Préparation de « <xliff:g id="NAME">%s</xliff:g> » en cours"</string>
<string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Recherche d\'erreurs en cours..."</string>
<string name="ext_media_new_notification_message" msgid="7589986898808506239">"Une nouvelle mémoire « <xliff:g id="NAME">%s</xliff:g> » a été détectée"</string>
@@ -1712,4 +1708,18 @@
<string name="time_picker_prompt_label" msgid="7588093983899966783">"Entrez l\'heure"</string>
<string name="time_picker_text_input_mode_description" msgid="4148166758173708199">"Passer au mode Entrée de texte pour entrer l\'heure."</string>
<string name="time_picker_radial_mode_description" msgid="4953403779779557198">"Passer au mode Horloge pour entrer l\'heure."</string>
+ <!-- no translation found for autofill_save_title (7081244500504163245) -->
+ <skip />
+ <!-- no translation found for autofill_save_title_with_type (4977385733042555659) -->
+ <skip />
+ <!-- no translation found for autofill_save_yes (6398026094049005921) -->
+ <skip />
+ <!-- no translation found for autofill_save_no (2625132258725581787) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_password (5288448918465971568) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_address (4936707762193009542) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_credit_card (7127694776265563071) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index 50ee5be..40172d0 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -1167,14 +1167,10 @@
<string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Appuyer pour sélectionner la langue et la disposition"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
- <!-- no translation found for alert_windows_notification_channel_name (7443890103456396837) -->
- <skip />
- <!-- no translation found for alert_windows_notification_title (5399998516035621282) -->
- <skip />
- <!-- no translation found for alert_windows_notification_message (2456738662997073459) -->
- <skip />
- <!-- no translation found for alert_windows_notification_turn_off_action (3367294525884949878) -->
- <skip />
+ <string name="alert_windows_notification_channel_name" msgid="7443890103456396837">"<xliff:g id="NAME">%s</xliff:g> se superpose aux autres applications"</string>
+ <string name="alert_windows_notification_title" msgid="5399998516035621282">"Superposition de l\'application <xliff:g id="NAME">%s</xliff:g>"</string>
+ <string name="alert_windows_notification_message" msgid="2456738662997073459">"Certaines sections de cette application peuvent rester visibles en permanence. Si cette fonctionnalité ne s\'exécute pas correctement, désactivez-la."</string>
+ <string name="alert_windows_notification_turn_off_action" msgid="3367294525884949878">"DÉSACTIVER"</string>
<string name="ext_media_checking_notification_title" msgid="5734005953288045806">"Préparation mémoire \"<xliff:g id="NAME">%s</xliff:g>\" en cours"</string>
<string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Recherche d\'erreurs"</string>
<string name="ext_media_new_notification_message" msgid="7589986898808506239">"Une nouvelle mémoire de stockage \"<xliff:g id="NAME">%s</xliff:g>\" a été détectée."</string>
@@ -1712,4 +1708,18 @@
<string name="time_picker_prompt_label" msgid="7588093983899966783">"Indiquez l\'heure"</string>
<string name="time_picker_text_input_mode_description" msgid="4148166758173708199">"Passer en mode saisie de texte pour la saisie de l\'heure."</string>
<string name="time_picker_radial_mode_description" msgid="4953403779779557198">"Passer en mode horloge pour la saisie de l\'heure."</string>
+ <!-- no translation found for autofill_save_title (7081244500504163245) -->
+ <skip />
+ <!-- no translation found for autofill_save_title_with_type (4977385733042555659) -->
+ <skip />
+ <!-- no translation found for autofill_save_yes (6398026094049005921) -->
+ <skip />
+ <!-- no translation found for autofill_save_no (2625132258725581787) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_password (5288448918465971568) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_address (4936707762193009542) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_credit_card (7127694776265563071) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-gl/strings.xml b/core/res/res/values-gl/strings.xml
index 0ee956a..0e024b4 100644
--- a/core/res/res/values-gl/strings.xml
+++ b/core/res/res/values-gl/strings.xml
@@ -1168,14 +1168,10 @@
<string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Toca para seleccionar o idioma e o deseño"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNÑOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNÑOPQRSTUVWXYZ"</string>
- <!-- no translation found for alert_windows_notification_channel_name (7443890103456396837) -->
- <skip />
- <!-- no translation found for alert_windows_notification_title (5399998516035621282) -->
- <skip />
- <!-- no translation found for alert_windows_notification_message (2456738662997073459) -->
- <skip />
- <!-- no translation found for alert_windows_notification_turn_off_action (3367294525884949878) -->
- <skip />
+ <string name="alert_windows_notification_channel_name" msgid="7443890103456396837">"<xliff:g id="NAME">%s</xliff:g> superponse a outras aplicacións"</string>
+ <string name="alert_windows_notification_title" msgid="5399998516035621282">"A aplicación <xliff:g id="NAME">%s</xliff:g> móstrase enriba."</string>
+ <string name="alert_windows_notification_message" msgid="2456738662997073459">"Partes desta aplicación poden permanecer visibles en todo momento. Se esta función non traballa correctamente, desactívaa."</string>
+ <string name="alert_windows_notification_turn_off_action" msgid="3367294525884949878">"DESACTIVAR"</string>
<string name="ext_media_checking_notification_title" msgid="5734005953288045806">"Preparando a <xliff:g id="NAME">%s</xliff:g>"</string>
<string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Comprobando se hai erros"</string>
<string name="ext_media_new_notification_message" msgid="7589986898808506239">"Detectouse unha <xliff:g id="NAME">%s</xliff:g> nova"</string>
@@ -1713,4 +1709,18 @@
<string name="time_picker_prompt_label" msgid="7588093983899966783">"Escribe a hora"</string>
<string name="time_picker_text_input_mode_description" msgid="4148166758173708199">"Cambia ao modo de entrada de texto para introducir a hora."</string>
<string name="time_picker_radial_mode_description" msgid="4953403779779557198">"Cambiar ao modo de reloxo para introducir a hora."</string>
+ <!-- no translation found for autofill_save_title (7081244500504163245) -->
+ <skip />
+ <!-- no translation found for autofill_save_title_with_type (4977385733042555659) -->
+ <skip />
+ <!-- no translation found for autofill_save_yes (6398026094049005921) -->
+ <skip />
+ <!-- no translation found for autofill_save_no (2625132258725581787) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_password (5288448918465971568) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_address (4936707762193009542) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_credit_card (7127694776265563071) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-gu/strings.xml b/core/res/res/values-gu/strings.xml
index 1693c32..511a843 100644
--- a/core/res/res/values-gu/strings.xml
+++ b/core/res/res/values-gu/strings.xml
@@ -1168,14 +1168,10 @@
<string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"ભાષા અને લેઆઉટ પસંદ કરવા માટે ટૅપ કરો"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
- <!-- no translation found for alert_windows_notification_channel_name (7443890103456396837) -->
- <skip />
- <!-- no translation found for alert_windows_notification_title (5399998516035621282) -->
- <skip />
- <!-- no translation found for alert_windows_notification_message (2456738662997073459) -->
- <skip />
- <!-- no translation found for alert_windows_notification_turn_off_action (3367294525884949878) -->
- <skip />
+ <string name="alert_windows_notification_channel_name" msgid="7443890103456396837">"<xliff:g id="NAME">%s</xliff:g> અન્ય ઍપ્લિકેશનો પર ડ્રો કરે છે"</string>
+ <string name="alert_windows_notification_title" msgid="5399998516035621282">"<xliff:g id="NAME">%s</xliff:g> ઍપ્લિકેશન સૌથી ઉપર દેખાઈ રહી છે."</string>
+ <string name="alert_windows_notification_message" msgid="2456738662997073459">"આ ઍપ્લિકેશનના ભાગ હંમેશાં દૃશ્યક્ષમ રહી શકે છે. જો આ સુવિધા યોગ્ય રીતે કાર્ય કરી રહી ન હોય, તો તેને બંધ કરો."</string>
+ <string name="alert_windows_notification_turn_off_action" msgid="3367294525884949878">"બંધ કરો"</string>
<string name="ext_media_checking_notification_title" msgid="5734005953288045806">"<xliff:g id="NAME">%s</xliff:g> ને તૈયાર કરી રહ્યું છે"</string>
<string name="ext_media_checking_notification_message" msgid="4747432538578886744">"ભૂલો માટે તપાસી રહ્યું છે"</string>
<string name="ext_media_new_notification_message" msgid="7589986898808506239">"નવું <xliff:g id="NAME">%s</xliff:g> મળ્યું"</string>
@@ -1713,4 +1709,18 @@
<string name="time_picker_prompt_label" msgid="7588093983899966783">"સમય લખો"</string>
<string name="time_picker_text_input_mode_description" msgid="4148166758173708199">"સમય દાખલ કરવા માટે ટેક્સ્ટ ઇનપુટ મોડમાં સ્વિચ કરો."</string>
<string name="time_picker_radial_mode_description" msgid="4953403779779557198">"સમય દાખલ કરવા માટે ઘડિયાળ મોડમાં સ્વિચ કરો."</string>
+ <!-- no translation found for autofill_save_title (7081244500504163245) -->
+ <skip />
+ <!-- no translation found for autofill_save_title_with_type (4977385733042555659) -->
+ <skip />
+ <!-- no translation found for autofill_save_yes (6398026094049005921) -->
+ <skip />
+ <!-- no translation found for autofill_save_no (2625132258725581787) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_password (5288448918465971568) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_address (4936707762193009542) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_credit_card (7127694776265563071) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index fbf2eaf..0a5d130 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -148,7 +148,7 @@
<string name="fcComplete" msgid="3118848230966886575">"सुविधा कोड पूर्ण."</string>
<string name="fcError" msgid="3327560126588500777">"कनेक्शन समस्या या अमान्य सुविधा कोड."</string>
<string name="httpErrorOk" msgid="1191919378083472204">"ठीक है"</string>
- <string name="httpError" msgid="7956392511146698522">"कोई नेटवर्क त्रुटि हुई थी."</string>
+ <string name="httpError" msgid="7956392511146698522">"कोई नेटवर्क गड़बड़ी हुई थी."</string>
<string name="httpErrorLookup" msgid="4711687456111963163">"URL नहीं मिल सका."</string>
<string name="httpErrorUnsupportedAuthScheme" msgid="6299980280442076799">"साइट प्रमाणीकरण योजना समर्थित नहीं है."</string>
<string name="httpErrorAuth" msgid="1435065629438044534">"प्रमाणीकृत नहीं किया जा सका."</string>
@@ -163,7 +163,7 @@
<string name="httpErrorFile" msgid="2170788515052558676">"फ़ाइल पर नहीं पहुंचा जा सका."</string>
<string name="httpErrorFileNotFound" msgid="6203856612042655084">"अनुरोधित फ़ाइल नहीं मिल सकी."</string>
<string name="httpErrorTooManyRequests" msgid="1235396927087188253">"बहुत सारे अनुरोधों का संसाधन हो रहा है. बाद में पुन: प्रयास करें."</string>
- <string name="notification_title" msgid="8967710025036163822">"<xliff:g id="ACCOUNT">%1$s</xliff:g> के लिए प्रवेश त्रुटि"</string>
+ <string name="notification_title" msgid="8967710025036163822">"<xliff:g id="ACCOUNT">%1$s</xliff:g> के लिए प्रवेश गड़बड़ी"</string>
<string name="contentServiceSync" msgid="8353523060269335667">"समन्वयन"</string>
<string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"समन्वयन"</string>
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"बहुत से <xliff:g id="CONTENT_TYPE">%s</xliff:g> हटाए जाते हैं."</string>
@@ -1167,14 +1167,10 @@
<string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"भाषा और लेआउट चुनने के लिए टैप करें"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
- <!-- no translation found for alert_windows_notification_channel_name (7443890103456396837) -->
- <skip />
- <!-- no translation found for alert_windows_notification_title (5399998516035621282) -->
- <skip />
- <!-- no translation found for alert_windows_notification_message (2456738662997073459) -->
- <skip />
- <!-- no translation found for alert_windows_notification_turn_off_action (3367294525884949878) -->
- <skip />
+ <string name="alert_windows_notification_channel_name" msgid="7443890103456396837">"<xliff:g id="NAME">%s</xliff:g> दूसरे ऐप पर आरेखण करते हैं"</string>
+ <string name="alert_windows_notification_title" msgid="5399998516035621282">"<xliff:g id="NAME">%s</xliff:g> ऐप ऊपर दिखा रहा है."</string>
+ <string name="alert_windows_notification_message" msgid="2456738662997073459">"हो सकता है कि इस ऐप के कुछ हिस्से हर समय दृश्यमान रहें. अगर यह सुविधा ठीक तरह से काम नहीं कर रही है, तो इसे बंद कर दें."</string>
+ <string name="alert_windows_notification_turn_off_action" msgid="3367294525884949878">"बंद करें"</string>
<string name="ext_media_checking_notification_title" msgid="5734005953288045806">"<xliff:g id="NAME">%s</xliff:g> को तैयार किया जा रहा है"</string>
<string name="ext_media_checking_notification_message" msgid="4747432538578886744">"त्रुटियों की जांच कर रहा है"</string>
<string name="ext_media_new_notification_message" msgid="7589986898808506239">"नए <xliff:g id="NAME">%s</xliff:g> का पता लगा"</string>
@@ -1258,7 +1254,7 @@
<string name="vpn_lockdown_connecting" msgid="6443438964440960745">"हमेशा-चालू VPN कनेक्ट हो रहा है…"</string>
<string name="vpn_lockdown_connected" msgid="8202679674819213931">"हमेशा-चालू VPN कनेक्ट है"</string>
<string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"हमेशा-चालू VPN डिस्कनेक्ट है"</string>
- <string name="vpn_lockdown_error" msgid="6009249814034708175">"हमेशा-चालू VPN त्रुटि"</string>
+ <string name="vpn_lockdown_error" msgid="6009249814034708175">"हमेशा-चालू VPN गड़बड़ी"</string>
<string name="vpn_lockdown_config" msgid="5099330695245008680">"सेट करने के लिए टैप करें"</string>
<string name="upload_file" msgid="2897957172366730416">"फ़ाइल चुनें"</string>
<string name="no_file_chosen" msgid="6363648562170759465">"कोई फ़ाइल चुनी नहीं गई"</string>
@@ -1454,7 +1450,7 @@
<string name="user_switching_message" msgid="2871009331809089783">"<xliff:g id="NAME">%1$s</xliff:g> पर स्विच किया जा रहा है…"</string>
<string name="user_logging_out_message" msgid="8939524935808875155">"<xliff:g id="NAME">%1$s</xliff:g> द्वारा प्रस्थान किया जा रहा है…"</string>
<string name="owner_name" msgid="2716755460376028154">"स्वामी"</string>
- <string name="error_message_title" msgid="4510373083082500195">"त्रुटि"</string>
+ <string name="error_message_title" msgid="4510373083082500195">"गड़बड़ी"</string>
<string name="error_message_change_not_allowed" msgid="1347282344200417578">"यह बदलाव आपके व्यवस्थापक द्वारा अनुमत नहीं है"</string>
<string name="app_not_found" msgid="3429141853498927379">"इस कार्यवाही को प्रबंधित करने के लिए कोई ऐप्स नहीं मिला"</string>
<string name="revoke" msgid="5404479185228271586">"निरस्त करें"</string>
@@ -1542,7 +1538,7 @@
<string name="mediasize_unknown_portrait" msgid="3088043641616409762">"अज्ञात पोर्ट्रेट"</string>
<string name="mediasize_unknown_landscape" msgid="4876995327029361552">"अज्ञात लैंडस्केप"</string>
<string name="write_fail_reason_cancelled" msgid="7091258378121627624">"रद्द कर दी गई"</string>
- <string name="write_fail_reason_cannot_write" msgid="8132505417935337724">"सामग्री लिखने में त्रुटि"</string>
+ <string name="write_fail_reason_cannot_write" msgid="8132505417935337724">"सामग्री लिखने में गड़बड़ी"</string>
<string name="reason_unknown" msgid="6048913880184628119">"अज्ञात"</string>
<string name="reason_service_unavailable" msgid="7824008732243903268">"प्रिंट सेवा सक्षम नहीं है"</string>
<string name="print_service_installed_title" msgid="2246317169444081628">"<xliff:g id="NAME">%s</xliff:g> सेवा इंस्टॉल की गई"</string>
@@ -1633,8 +1629,8 @@
<string name="zen_mode_default_weekends_name" msgid="2786495801019345244">"सप्ताहांत"</string>
<string name="zen_mode_default_events_name" msgid="8158334939013085363">"इवेंट"</string>
<string name="muted_by" msgid="6147073845094180001">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g> द्वारा म्यूट किया गया"</string>
- <string name="system_error_wipe_data" msgid="6608165524785354962">"आपके डिवाइस के साथ कोई आंतरिक त्रुटि हुई और यह तब तक अस्थिर रह सकता है, जब तक आप फ़ैक्टरी डेटा रीसेट नहीं करते हैं."</string>
- <string name="system_error_manufacturer" msgid="8086872414744210668">"आपके डिवाइस के साथ कोई आंतरिक त्रुटि हुई. विवरणों के लिए अपने निर्माता से संपर्क करें."</string>
+ <string name="system_error_wipe_data" msgid="6608165524785354962">"आपके डिवाइस के साथ कोई आंतरिक गड़बड़ी हुई और यह तब तक अस्थिर रह सकता है, जब तक आप फ़ैक्टरी डेटा रीसेट नहीं करते हैं."</string>
+ <string name="system_error_manufacturer" msgid="8086872414744210668">"आपके डिवाइस के साथ कोई आंतरिक गड़बड़ी हुई. विवरणों के लिए अपने निर्माता से संपर्क करें."</string>
<string name="stk_cc_ussd_to_dial" msgid="5202342984749947872">"USSD अनुरोध को DIAL अनुरोध में बदल दिया गया है."</string>
<string name="stk_cc_ussd_to_ss" msgid="2345360594181405482">"USSD अनुरोध को SS अनुरोध में बदल दिया गया है."</string>
<string name="stk_cc_ussd_to_ussd" msgid="7466087659967191653">"USSD अनुरोध को नए USSD अनुरोध में बदल दिया गया है."</string>
@@ -1712,4 +1708,18 @@
<string name="time_picker_prompt_label" msgid="7588093983899966783">"समय लिखें"</string>
<string name="time_picker_text_input_mode_description" msgid="4148166758173708199">"समय इनपुट के लिए लेख इनपुट मोड पर जाएं."</string>
<string name="time_picker_radial_mode_description" msgid="4953403779779557198">"समय इनपुट के लिए घड़ी मोड पर जाएं."</string>
+ <!-- no translation found for autofill_save_title (7081244500504163245) -->
+ <skip />
+ <!-- no translation found for autofill_save_title_with_type (4977385733042555659) -->
+ <skip />
+ <!-- no translation found for autofill_save_yes (6398026094049005921) -->
+ <skip />
+ <!-- no translation found for autofill_save_no (2625132258725581787) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_password (5288448918465971568) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_address (4936707762193009542) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_credit_card (7127694776265563071) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
index 1b97a4e..89058a5 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -1187,14 +1187,10 @@
<string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Dodirnite da biste odabrali jezik i raspored"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
- <!-- no translation found for alert_windows_notification_channel_name (7443890103456396837) -->
- <skip />
- <!-- no translation found for alert_windows_notification_title (5399998516035621282) -->
- <skip />
- <!-- no translation found for alert_windows_notification_message (2456738662997073459) -->
- <skip />
- <!-- no translation found for alert_windows_notification_turn_off_action (3367294525884949878) -->
- <skip />
+ <string name="alert_windows_notification_channel_name" msgid="7443890103456396837">"Aplikacija <xliff:g id="NAME">%s</xliff:g> prikazuje se preko drugih aplikacija"</string>
+ <string name="alert_windows_notification_title" msgid="5399998516035621282">"Aplikacija <xliff:g id="NAME">%s</xliff:g> prikazuje se gore."</string>
+ <string name="alert_windows_notification_message" msgid="2456738662997073459">"Dijelovi ove aplikacije mogu ostati vidljivi cijelo vrijeme. Ako ta značajka ne funkcionira pravilno, isključite je."</string>
+ <string name="alert_windows_notification_turn_off_action" msgid="3367294525884949878">"ISKLJUČI"</string>
<string name="ext_media_checking_notification_title" msgid="5734005953288045806">"Priprema uređaja <xliff:g id="NAME">%s</xliff:g>"</string>
<string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Traženje pogrešaka"</string>
<string name="ext_media_new_notification_message" msgid="7589986898808506239">"Otkriven je novi uređaj <xliff:g id="NAME">%s</xliff:g>"</string>
@@ -1743,4 +1739,18 @@
<string name="time_picker_prompt_label" msgid="7588093983899966783">"Unesite vrijeme"</string>
<string name="time_picker_text_input_mode_description" msgid="4148166758173708199">"Prijeđite na način unosa teksta da biste unijeli vrijeme."</string>
<string name="time_picker_radial_mode_description" msgid="4953403779779557198">"Prijeđite na način rada sata da biste unijeli vrijeme."</string>
+ <!-- no translation found for autofill_save_title (7081244500504163245) -->
+ <skip />
+ <!-- no translation found for autofill_save_title_with_type (4977385733042555659) -->
+ <skip />
+ <!-- no translation found for autofill_save_yes (6398026094049005921) -->
+ <skip />
+ <!-- no translation found for autofill_save_no (2625132258725581787) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_password (5288448918465971568) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_address (4936707762193009542) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_credit_card (7127694776265563071) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml
index b67b29f..a4028ee 100644
--- a/core/res/res/values-hu/strings.xml
+++ b/core/res/res/values-hu/strings.xml
@@ -1167,14 +1167,10 @@
<string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Koppintson a nyelv és a billentyűzetkiosztás kiválasztásához"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
- <!-- no translation found for alert_windows_notification_channel_name (7443890103456396837) -->
- <skip />
- <!-- no translation found for alert_windows_notification_title (5399998516035621282) -->
- <skip />
- <!-- no translation found for alert_windows_notification_message (2456738662997073459) -->
- <skip />
- <!-- no translation found for alert_windows_notification_turn_off_action (3367294525884949878) -->
- <skip />
+ <string name="alert_windows_notification_channel_name" msgid="7443890103456396837">"A(z) <xliff:g id="NAME">%s</xliff:g> a többi alkalmazás felett jelenik meg"</string>
+ <string name="alert_windows_notification_title" msgid="5399998516035621282">"A(z) <xliff:g id="NAME">%s</xliff:g> legfelül jelenik meg."</string>
+ <string name="alert_windows_notification_message" msgid="2456738662997073459">"Előfordulhat, hogy ezen alkalmazás egyes részei mindig láthatók maradnak. Ha ez a funkció nem működik megfelelően, kapcsolja ki."</string>
+ <string name="alert_windows_notification_turn_off_action" msgid="3367294525884949878">"KIKAPCSOLÁS"</string>
<string name="ext_media_checking_notification_title" msgid="5734005953288045806">"<xliff:g id="NAME">%s</xliff:g> előkészítése"</string>
<string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Hibák keresése"</string>
<string name="ext_media_new_notification_message" msgid="7589986898808506239">"Új <xliff:g id="NAME">%s</xliff:g> észlelve"</string>
@@ -1712,4 +1708,18 @@
<string name="time_picker_prompt_label" msgid="7588093983899966783">"Adja meg az időt"</string>
<string name="time_picker_text_input_mode_description" msgid="4148166758173708199">"Időbevitelhez váltson szövegbeviteli módba."</string>
<string name="time_picker_radial_mode_description" msgid="4953403779779557198">"Időbevitelhez váltson óramódba."</string>
+ <!-- no translation found for autofill_save_title (7081244500504163245) -->
+ <skip />
+ <!-- no translation found for autofill_save_title_with_type (4977385733042555659) -->
+ <skip />
+ <!-- no translation found for autofill_save_yes (6398026094049005921) -->
+ <skip />
+ <!-- no translation found for autofill_save_no (2625132258725581787) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_password (5288448918465971568) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_address (4936707762193009542) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_credit_card (7127694776265563071) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-hy/strings.xml b/core/res/res/values-hy/strings.xml
index fa332b0..ad375eb 100644
--- a/core/res/res/values-hy/strings.xml
+++ b/core/res/res/values-hy/strings.xml
@@ -1167,14 +1167,10 @@
<string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Հպեք՝ լեզուն և դասավորությունն ընտրելու համար"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ԱԲԳԴԵԶԷԸԹԺԻԼԽԾԿՀՁՂՃՄՅՆՇՈՉՊՋՌՍՎՏՐՑՈՒՓՔԵւՕՖ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
- <!-- no translation found for alert_windows_notification_channel_name (7443890103456396837) -->
- <skip />
- <!-- no translation found for alert_windows_notification_title (5399998516035621282) -->
- <skip />
- <!-- no translation found for alert_windows_notification_message (2456738662997073459) -->
- <skip />
- <!-- no translation found for alert_windows_notification_turn_off_action (3367294525884949878) -->
- <skip />
+ <string name="alert_windows_notification_channel_name" msgid="7443890103456396837">"<xliff:g id="NAME">%s</xliff:g> ցուցադրել այլ հավելվածների վերևում"</string>
+ <string name="alert_windows_notification_title" msgid="5399998516035621282">"<xliff:g id="NAME">%s</xliff:g> հավելվածը ցուցադրվում է վերևում։"</string>
+ <string name="alert_windows_notification_message" msgid="2456738662997073459">"Այս հավելվածի որոշ հատվածներ կարող են միշտ տեսանելի լինել։ Եթե այս գործառույթն ինչպես հարկն է չի աշխատում, անջատեք այն։"</string>
+ <string name="alert_windows_notification_turn_off_action" msgid="3367294525884949878">"ԱՆՋԱՏԵԼ"</string>
<string name="ext_media_checking_notification_title" msgid="5734005953288045806">"<xliff:g id="NAME">%s</xliff:g>-ի նախապատրաստում"</string>
<string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Սխալների ստուգում"</string>
<string name="ext_media_new_notification_message" msgid="7589986898808506239">"Հայտնաբերվել է նոր <xliff:g id="NAME">%s</xliff:g>"</string>
@@ -1712,4 +1708,18 @@
<string name="time_picker_prompt_label" msgid="7588093983899966783">"Մուտքագրեք ժամը"</string>
<string name="time_picker_text_input_mode_description" msgid="4148166758173708199">"Ժամը մուտքագրելու համար միացրեք տեքստի մուտքագրման ռեժիմը:"</string>
<string name="time_picker_radial_mode_description" msgid="4953403779779557198">"Ժամը մուտքագրելու համար միացրեք ժամացույցի ռեժիմը:"</string>
+ <!-- no translation found for autofill_save_title (7081244500504163245) -->
+ <skip />
+ <!-- no translation found for autofill_save_title_with_type (4977385733042555659) -->
+ <skip />
+ <!-- no translation found for autofill_save_yes (6398026094049005921) -->
+ <skip />
+ <!-- no translation found for autofill_save_no (2625132258725581787) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_password (5288448918465971568) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_address (4936707762193009542) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_credit_card (7127694776265563071) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index ac898e4..ab32838 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -1167,14 +1167,10 @@
<string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Ketuk untuk memilih bahasa dan tata letak"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
- <!-- no translation found for alert_windows_notification_channel_name (7443890103456396837) -->
- <skip />
- <!-- no translation found for alert_windows_notification_title (5399998516035621282) -->
- <skip />
- <!-- no translation found for alert_windows_notification_message (2456738662997073459) -->
- <skip />
- <!-- no translation found for alert_windows_notification_turn_off_action (3367294525884949878) -->
- <skip />
+ <string name="alert_windows_notification_channel_name" msgid="7443890103456396837">"<xliff:g id="NAME">%s</xliff:g> muncul di atas aplikasi lain"</string>
+ <string name="alert_windows_notification_title" msgid="5399998516035621282">"Aplikasi <xliff:g id="NAME">%s</xliff:g> muncul di atas."</string>
+ <string name="alert_windows_notification_message" msgid="2456738662997073459">"Sebagian aplikasi ini mungkin selalu terlihat. Jika fitur ini tidak berfungsi dengan baik, nonaktifkan."</string>
+ <string name="alert_windows_notification_turn_off_action" msgid="3367294525884949878">"NONAKTIFKAN"</string>
<string name="ext_media_checking_notification_title" msgid="5734005953288045806">"Menyiapkan <xliff:g id="NAME">%s</xliff:g>"</string>
<string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Memeriksa kesalahan"</string>
<string name="ext_media_new_notification_message" msgid="7589986898808506239">"<xliff:g id="NAME">%s</xliff:g> baru terdeteksi"</string>
@@ -1712,4 +1708,18 @@
<string name="time_picker_prompt_label" msgid="7588093983899966783">"Ketik waktu"</string>
<string name="time_picker_text_input_mode_description" msgid="4148166758173708199">"Beralih ke mode masukan teks untuk masukan waktu."</string>
<string name="time_picker_radial_mode_description" msgid="4953403779779557198">"Beralih ke mode jam untuk masukan waktu."</string>
+ <!-- no translation found for autofill_save_title (7081244500504163245) -->
+ <skip />
+ <!-- no translation found for autofill_save_title_with_type (4977385733042555659) -->
+ <skip />
+ <!-- no translation found for autofill_save_yes (6398026094049005921) -->
+ <skip />
+ <!-- no translation found for autofill_save_no (2625132258725581787) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_password (5288448918465971568) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_address (4936707762193009542) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_credit_card (7127694776265563071) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-is/strings.xml b/core/res/res/values-is/strings.xml
index a1b2be8..3cbc17e 100644
--- a/core/res/res/values-is/strings.xml
+++ b/core/res/res/values-is/strings.xml
@@ -1168,14 +1168,10 @@
<string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Ýttu til að velja tungumál og útlit"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" AÁBCDÐEÉFGHIÍJKLMNOÓPQRSTUÚVWXYÝZÞÆÖ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789AÁBCDÐEÉFGHIÍJKLMNOÓPQRSTUÚVWXYÝZÞÆÖ"</string>
- <!-- no translation found for alert_windows_notification_channel_name (7443890103456396837) -->
- <skip />
- <!-- no translation found for alert_windows_notification_title (5399998516035621282) -->
- <skip />
- <!-- no translation found for alert_windows_notification_message (2456738662997073459) -->
- <skip />
- <!-- no translation found for alert_windows_notification_turn_off_action (3367294525884949878) -->
- <skip />
+ <string name="alert_windows_notification_channel_name" msgid="7443890103456396837">"<xliff:g id="NAME">%s</xliff:g> teiknar yfir önnur forrit"</string>
+ <string name="alert_windows_notification_title" msgid="5399998516035621282">"<xliff:g id="NAME">%s</xliff:g> forritið birtist efst."</string>
+ <string name="alert_windows_notification_message" msgid="2456738662997073459">"Hluti af þessu forriti gæti verið ávallt sýnilegur. Ef þessi eiginleiki virkar ekki sem skyldi skaltu slökkva á honum."</string>
+ <string name="alert_windows_notification_turn_off_action" msgid="3367294525884949878">"SLÖKKVA"</string>
<string name="ext_media_checking_notification_title" msgid="5734005953288045806">"Undirbýr <xliff:g id="NAME">%s</xliff:g>"</string>
<string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Leitar að villum"</string>
<string name="ext_media_new_notification_message" msgid="7589986898808506239">"Nýtt <xliff:g id="NAME">%s</xliff:g> fannst"</string>
@@ -1713,4 +1709,18 @@
<string name="time_picker_prompt_label" msgid="7588093983899966783">"Færðu inn tíma"</string>
<string name="time_picker_text_input_mode_description" msgid="4148166758173708199">"Skipta yfir í textastillingu til að færa inn tíma."</string>
<string name="time_picker_radial_mode_description" msgid="4953403779779557198">"Skipta yfir í klukkustillingu til að færa inn tíma."</string>
+ <!-- no translation found for autofill_save_title (7081244500504163245) -->
+ <skip />
+ <!-- no translation found for autofill_save_title_with_type (4977385733042555659) -->
+ <skip />
+ <!-- no translation found for autofill_save_yes (6398026094049005921) -->
+ <skip />
+ <!-- no translation found for autofill_save_no (2625132258725581787) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_password (5288448918465971568) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_address (4936707762193009542) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_credit_card (7127694776265563071) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index f5aab8e..89b0113 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -1167,14 +1167,10 @@
<string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Tocca per selezionare la lingua e il layout"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
- <!-- no translation found for alert_windows_notification_channel_name (7443890103456396837) -->
- <skip />
- <!-- no translation found for alert_windows_notification_title (5399998516035621282) -->
- <skip />
- <!-- no translation found for alert_windows_notification_message (2456738662997073459) -->
- <skip />
- <!-- no translation found for alert_windows_notification_turn_off_action (3367294525884949878) -->
- <skip />
+ <string name="alert_windows_notification_channel_name" msgid="7443890103456396837">"<xliff:g id="NAME">%s</xliff:g> visualizzata sopra altre app"</string>
+ <string name="alert_windows_notification_title" msgid="5399998516035621282">"App <xliff:g id="NAME">%s</xliff:g> visualizzata sulle altre."</string>
+ <string name="alert_windows_notification_message" msgid="2456738662997073459">"Alcune parti di questa app possono rimanere sempre visibili. Disattiva la funzione qualora non funzionasse correttamente."</string>
+ <string name="alert_windows_notification_turn_off_action" msgid="3367294525884949878">"DISATTIVA"</string>
<string name="ext_media_checking_notification_title" msgid="5734005953288045806">"Preparazione della <xliff:g id="NAME">%s</xliff:g>"</string>
<string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Ricerca errori"</string>
<string name="ext_media_new_notification_message" msgid="7589986898808506239">"Nuova <xliff:g id="NAME">%s</xliff:g> rilevata"</string>
@@ -1712,4 +1708,18 @@
<string name="time_picker_prompt_label" msgid="7588093983899966783">"Digita l\'ora"</string>
<string name="time_picker_text_input_mode_description" msgid="4148166758173708199">"Passa alla modalità di immissione testo per inserire l\'ora."</string>
<string name="time_picker_radial_mode_description" msgid="4953403779779557198">"Passa alla modalità orologio per inserire l\'ora."</string>
+ <!-- no translation found for autofill_save_title (7081244500504163245) -->
+ <skip />
+ <!-- no translation found for autofill_save_title_with_type (4977385733042555659) -->
+ <skip />
+ <!-- no translation found for autofill_save_yes (6398026094049005921) -->
+ <skip />
+ <!-- no translation found for autofill_save_no (2625132258725581787) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_password (5288448918465971568) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_address (4936707762193009542) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_credit_card (7127694776265563071) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml
index 9f90a38..c6e02d2 100644
--- a/core/res/res/values-iw/strings.xml
+++ b/core/res/res/values-iw/strings.xml
@@ -1207,14 +1207,10 @@
<string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"הקש כדי לבחור שפה ופריסה"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
- <!-- no translation found for alert_windows_notification_channel_name (7443890103456396837) -->
- <skip />
- <!-- no translation found for alert_windows_notification_title (5399998516035621282) -->
- <skip />
- <!-- no translation found for alert_windows_notification_message (2456738662997073459) -->
- <skip />
- <!-- no translation found for alert_windows_notification_turn_off_action (3367294525884949878) -->
- <skip />
+ <string name="alert_windows_notification_channel_name" msgid="7443890103456396837">"<xliff:g id="NAME">%s</xliff:g> יכולה להופיע מעל אפליקציות אחרות"</string>
+ <string name="alert_windows_notification_title" msgid="5399998516035621282">"<xliff:g id="NAME">%s</xliff:g> מופיעה מעל אפליקציות אחרות."</string>
+ <string name="alert_windows_notification_message" msgid="2456738662997073459">"חלקים באפליקציה הזו עשויים להופיע במסך כל הזמן. כבה את התכונה הזו אם היא לא עובדת כראוי."</string>
+ <string name="alert_windows_notification_turn_off_action" msgid="3367294525884949878">"כבה"</string>
<string name="ext_media_checking_notification_title" msgid="5734005953288045806">"הכנת <xliff:g id="NAME">%s</xliff:g>"</string>
<string name="ext_media_checking_notification_message" msgid="4747432538578886744">"בודק אם יש שגיאות"</string>
<string name="ext_media_new_notification_message" msgid="7589986898808506239">"זוהה <xliff:g id="NAME">%s</xliff:g> חדש"</string>
@@ -1774,4 +1770,18 @@
<string name="time_picker_prompt_label" msgid="7588093983899966783">"הקלד את השעה"</string>
<string name="time_picker_text_input_mode_description" msgid="4148166758173708199">"העבר למצב קלט טקסט לצורך הזנת השעה"</string>
<string name="time_picker_radial_mode_description" msgid="4953403779779557198">"העבר למצב שעון לצורך הזנת השעה"</string>
+ <!-- no translation found for autofill_save_title (7081244500504163245) -->
+ <skip />
+ <!-- no translation found for autofill_save_title_with_type (4977385733042555659) -->
+ <skip />
+ <!-- no translation found for autofill_save_yes (6398026094049005921) -->
+ <skip />
+ <!-- no translation found for autofill_save_no (2625132258725581787) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_password (5288448918465971568) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_address (4936707762193009542) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_credit_card (7127694776265563071) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index b4d2d83..857999f 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -296,8 +296,8 @@
<string name="permdesc_receiveSms" msgid="6424387754228766939">"SMSメッセージの受信と処理をアプリに許可します。これにより、アプリが端末に届いたメッセージを表示することなく監視または削除できるようになります。"</string>
<string name="permlab_receiveMms" msgid="1821317344668257098">"テキストメッセージ(MMS)の受信"</string>
<string name="permdesc_receiveMms" msgid="533019437263212260">"MMSメッセージの受信と処理をアプリに許可します。これにより、アプリが端末に届いたメッセージを表示することなく監視または削除できるようになります。"</string>
- <string name="permlab_readCellBroadcasts" msgid="1598328843619646166">"緊急警報SMSの読み取り"</string>
- <string name="permdesc_readCellBroadcasts" msgid="6361972776080458979">"端末で受信した緊急警報SMSの読み取りをアプリに許可します。緊急警報は、緊急事態を警告する目的で一部の地域に配信されます。緊急警報の受信時に、悪意のあるアプリによって端末の動作や処理が妨害される恐れがあります。"</string>
+ <string name="permlab_readCellBroadcasts" msgid="1598328843619646166">"緊急速報メール SMS の読み取り"</string>
+ <string name="permdesc_readCellBroadcasts" msgid="6361972776080458979">"端末で受信した緊急速報メール SMS の読み取りをアプリに許可します。緊急速報メールは、緊急事態を警告する目的で一部の地域に配信されます。緊急速報メールの受信時に、悪意のあるアプリによって端末の動作や処理が妨害される恐れがあります。"</string>
<string name="permlab_subscribedFeedsRead" msgid="4756609637053353318">"登録したフィードの読み取り"</string>
<string name="permdesc_subscribedFeedsRead" msgid="5557058907906144505">"現在同期されているフィードの詳細を取得することをアプリに許可します。"</string>
<string name="permlab_sendSms" msgid="7544599214260982981">"SMSメッセージの送信と表示"</string>
@@ -1167,14 +1167,10 @@
<string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"タップして言語とレイアウトを選択してください"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
- <!-- no translation found for alert_windows_notification_channel_name (7443890103456396837) -->
- <skip />
- <!-- no translation found for alert_windows_notification_title (5399998516035621282) -->
- <skip />
- <!-- no translation found for alert_windows_notification_message (2456738662997073459) -->
- <skip />
- <!-- no translation found for alert_windows_notification_turn_off_action (3367294525884949878) -->
- <skip />
+ <string name="alert_windows_notification_channel_name" msgid="7443890103456396837">"<xliff:g id="NAME">%s</xliff:g>を他のアプリの上に重ねて表示"</string>
+ <string name="alert_windows_notification_title" msgid="5399998516035621282">"<xliff:g id="NAME">%s</xliff:g>を重ねて表示中"</string>
+ <string name="alert_windows_notification_message" msgid="2456738662997073459">"このアプリの一部は常に表示され続けます。この機能が正常に動作しない場合は OFF にしてください。"</string>
+ <string name="alert_windows_notification_turn_off_action" msgid="3367294525884949878">"OFF にする"</string>
<string name="ext_media_checking_notification_title" msgid="5734005953288045806">"<xliff:g id="NAME">%s</xliff:g>を準備中"</string>
<string name="ext_media_checking_notification_message" msgid="4747432538578886744">"エラーを確認中"</string>
<string name="ext_media_new_notification_message" msgid="7589986898808506239">"新しい<xliff:g id="NAME">%s</xliff:g>が検出されました"</string>
@@ -1712,4 +1708,18 @@
<string name="time_picker_prompt_label" msgid="7588093983899966783">"時刻を入力"</string>
<string name="time_picker_text_input_mode_description" msgid="4148166758173708199">"時刻をテキストで入力するモードに切り替えます。"</string>
<string name="time_picker_radial_mode_description" msgid="4953403779779557198">"時刻を時計で入力するモードに切り替えます。"</string>
+ <!-- no translation found for autofill_save_title (7081244500504163245) -->
+ <skip />
+ <!-- no translation found for autofill_save_title_with_type (4977385733042555659) -->
+ <skip />
+ <!-- no translation found for autofill_save_yes (6398026094049005921) -->
+ <skip />
+ <!-- no translation found for autofill_save_no (2625132258725581787) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_password (5288448918465971568) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_address (4936707762193009542) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_credit_card (7127694776265563071) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-ka/strings.xml b/core/res/res/values-ka/strings.xml
index 80c9dec..5d970b6 100644
--- a/core/res/res/values-ka/strings.xml
+++ b/core/res/res/values-ka/strings.xml
@@ -1167,14 +1167,10 @@
<string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"შეეხეთ ენისა და განლაგების ასარჩევად"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
- <!-- no translation found for alert_windows_notification_channel_name (7443890103456396837) -->
- <skip />
- <!-- no translation found for alert_windows_notification_title (5399998516035621282) -->
- <skip />
- <!-- no translation found for alert_windows_notification_message (2456738662997073459) -->
- <skip />
- <!-- no translation found for alert_windows_notification_turn_off_action (3367294525884949878) -->
- <skip />
+ <string name="alert_windows_notification_channel_name" msgid="7443890103456396837">"<xliff:g id="NAME">%s</xliff:g>-ის სხვა აპების ინტერფეისზე გადაწერა"</string>
+ <string name="alert_windows_notification_title" msgid="5399998516035621282">"<xliff:g id="NAME">%s</xliff:g> აპის მიერ ზემოდან ჩვენება."</string>
+ <string name="alert_windows_notification_message" msgid="2456738662997073459">"აპის გარკვეული ნაწილები შესაძლოა ყოველთვის ხილული იყოს. თუ ეს ფუნქცია გამართულად არ მუშაობს, გამორთეთ."</string>
+ <string name="alert_windows_notification_turn_off_action" msgid="3367294525884949878">"გამორთვა"</string>
<string name="ext_media_checking_notification_title" msgid="5734005953288045806">"<xliff:g id="NAME">%s</xliff:g>-ის მომზადება"</string>
<string name="ext_media_checking_notification_message" msgid="4747432538578886744">"შეცდომების შემოწმება"</string>
<string name="ext_media_new_notification_message" msgid="7589986898808506239">"აღმოჩენილია ახალი <xliff:g id="NAME">%s</xliff:g>"</string>
@@ -1712,4 +1708,18 @@
<string name="time_picker_prompt_label" msgid="7588093983899966783">"აკრიფეთ დრო"</string>
<string name="time_picker_text_input_mode_description" msgid="4148166758173708199">"დროის შეყვანისთვის ტექსტის შეყვანის რეჟიმზე გადართვა."</string>
<string name="time_picker_radial_mode_description" msgid="4953403779779557198">"დროის შეყვანისთვის საათის რეჟიმზე გადართვა."</string>
+ <!-- no translation found for autofill_save_title (7081244500504163245) -->
+ <skip />
+ <!-- no translation found for autofill_save_title_with_type (4977385733042555659) -->
+ <skip />
+ <!-- no translation found for autofill_save_yes (6398026094049005921) -->
+ <skip />
+ <!-- no translation found for autofill_save_no (2625132258725581787) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_password (5288448918465971568) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_address (4936707762193009542) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_credit_card (7127694776265563071) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-kk/strings.xml b/core/res/res/values-kk/strings.xml
index 6732ca3..3e77e9c 100644
--- a/core/res/res/values-kk/strings.xml
+++ b/core/res/res/values-kk/strings.xml
@@ -1168,14 +1168,10 @@
<string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Тіл мен пернетақта схемасын таңдау үшін түртіңіз"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
- <!-- no translation found for alert_windows_notification_channel_name (7443890103456396837) -->
- <skip />
- <!-- no translation found for alert_windows_notification_title (5399998516035621282) -->
- <skip />
- <!-- no translation found for alert_windows_notification_message (2456738662997073459) -->
- <skip />
- <!-- no translation found for alert_windows_notification_turn_off_action (3367294525884949878) -->
- <skip />
+ <string name="alert_windows_notification_channel_name" msgid="7443890103456396837">"<xliff:g id="NAME">%s</xliff:g> басқа қолданбалардың үстінен көрсетіледі"</string>
+ <string name="alert_windows_notification_title" msgid="5399998516035621282">"<xliff:g id="NAME">%s</xliff:g> қолданбасы жоғарғы жағында көрсетіледі."</string>
+ <string name="alert_windows_notification_message" msgid="2456738662997073459">"Бұл қолданбаның бір бөлігі үнемі көрініп тұруы мүмкін. Егер бұл функция дұрыс жұмыс істемесе, оны өшіріңіз."</string>
+ <string name="alert_windows_notification_turn_off_action" msgid="3367294525884949878">"ӨШІРУ"</string>
<string name="ext_media_checking_notification_title" msgid="5734005953288045806">"<xliff:g id="NAME">%s</xliff:g> дайындалуда"</string>
<string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Қателер тексерілуде"</string>
<string name="ext_media_new_notification_message" msgid="7589986898808506239">"Жаңа <xliff:g id="NAME">%s</xliff:g> анықталды"</string>
@@ -1713,4 +1709,18 @@
<string name="time_picker_prompt_label" msgid="7588093983899966783">"Уақытты енгізіңіз"</string>
<string name="time_picker_text_input_mode_description" msgid="4148166758173708199">"Уақытты енгізу үшін мәтін енгізу режиміне өтіңіз."</string>
<string name="time_picker_radial_mode_description" msgid="4953403779779557198">"Уақытты енгізу үшін сағат режиміне өтіңіз."</string>
+ <!-- no translation found for autofill_save_title (7081244500504163245) -->
+ <skip />
+ <!-- no translation found for autofill_save_title_with_type (4977385733042555659) -->
+ <skip />
+ <!-- no translation found for autofill_save_yes (6398026094049005921) -->
+ <skip />
+ <!-- no translation found for autofill_save_no (2625132258725581787) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_password (5288448918465971568) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_address (4936707762193009542) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_credit_card (7127694776265563071) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-km/strings.xml b/core/res/res/values-km/strings.xml
index e906c45..e07bc41 100644
--- a/core/res/res/values-km/strings.xml
+++ b/core/res/res/values-km/strings.xml
@@ -1169,14 +1169,10 @@
<string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"ប៉ះដើម្បីជ្រើសភាសា និងប្លង់"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
- <!-- no translation found for alert_windows_notification_channel_name (7443890103456396837) -->
- <skip />
- <!-- no translation found for alert_windows_notification_title (5399998516035621282) -->
- <skip />
- <!-- no translation found for alert_windows_notification_message (2456738662997073459) -->
- <skip />
- <!-- no translation found for alert_windows_notification_turn_off_action (3367294525884949878) -->
- <skip />
+ <string name="alert_windows_notification_channel_name" msgid="7443890103456396837">"<xliff:g id="NAME">%s</xliff:g> គូរពីលើកម្មវិធីផ្សេងទៀត"</string>
+ <string name="alert_windows_notification_title" msgid="5399998516035621282">"កម្មវិធី <xliff:g id="NAME">%s</xliff:g> បង្ហាញនៅលើគេ។"</string>
+ <string name="alert_windows_notification_message" msgid="2456738662997073459">"ផ្នែកខ្លះនៃកម្មវិធីនេះនឹងនៅតែអាចមើលឃើញបានគ្រប់ពេល។ ប្រសិនបើមុខងារនេះដំណើរការមិនប្រក្រតីទេ សូមបិទវា។"</string>
+ <string name="alert_windows_notification_turn_off_action" msgid="3367294525884949878">"បិទ"</string>
<string name="ext_media_checking_notification_title" msgid="5734005953288045806">"កំពុងរៀបចំ <xliff:g id="NAME">%s</xliff:g>"</string>
<string name="ext_media_checking_notification_message" msgid="4747432538578886744">"កំពុងពិនិត្យរកកំហុស"</string>
<string name="ext_media_new_notification_message" msgid="7589986898808506239">"បានរកឃើញ <xliff:g id="NAME">%s</xliff:g> ថ្មី"</string>
@@ -1714,4 +1710,18 @@
<string name="time_picker_prompt_label" msgid="7588093983899966783">"វាយបញ្ចូលម៉ោង"</string>
<string name="time_picker_text_input_mode_description" msgid="4148166758173708199">"ប្តូរទៅមុខងារបញ្ចូលអក្សរសម្រាប់ការបញ្ចូលម៉ោង។"</string>
<string name="time_picker_radial_mode_description" msgid="4953403779779557198">"ប្តូរទៅមុខងារនាឡិកាសម្រាប់ការបញ្ចូលម៉ោង។"</string>
+ <!-- no translation found for autofill_save_title (7081244500504163245) -->
+ <skip />
+ <!-- no translation found for autofill_save_title_with_type (4977385733042555659) -->
+ <skip />
+ <!-- no translation found for autofill_save_yes (6398026094049005921) -->
+ <skip />
+ <!-- no translation found for autofill_save_no (2625132258725581787) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_password (5288448918465971568) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_address (4936707762193009542) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_credit_card (7127694776265563071) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-kn/strings.xml b/core/res/res/values-kn/strings.xml
index 6cccbc2..2fedb79 100644
--- a/core/res/res/values-kn/strings.xml
+++ b/core/res/res/values-kn/strings.xml
@@ -1168,14 +1168,10 @@
<string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"ಭಾಷೆ ಮತ್ತು ವಿನ್ಯಾಸವನ್ನು ಆಯ್ಕೆ ಮಾಡಲು ಟ್ಯಾಪ್ ಮಾಡಿ"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
- <!-- no translation found for alert_windows_notification_channel_name (7443890103456396837) -->
- <skip />
- <!-- no translation found for alert_windows_notification_title (5399998516035621282) -->
- <skip />
- <!-- no translation found for alert_windows_notification_message (2456738662997073459) -->
- <skip />
- <!-- no translation found for alert_windows_notification_turn_off_action (3367294525884949878) -->
- <skip />
+ <string name="alert_windows_notification_channel_name" msgid="7443890103456396837">"ಇತರ ಅಪ್ಲಿಕೇಶನ್ಗಳ ಮೇಲೆ <xliff:g id="NAME">%s</xliff:g> ಎಳೆಯಿರಿ"</string>
+ <string name="alert_windows_notification_title" msgid="5399998516035621282">"<xliff:g id="NAME">%s</xliff:g> ಅಪ್ಲಿಕೇಶನ್ ಮೇಲೆ ಕಾಣಿಸುತ್ತಿದೆ."</string>
+ <string name="alert_windows_notification_message" msgid="2456738662997073459">"ಈ ಅಪ್ಲಿಕೇಶನ್ನ ಭಾಗಗಳು ಎಲ್ಲ ಸಮಯದಲ್ಲೂ ಕಾಣುತ್ತಿರುತ್ತದೆ. ಈ ವೈಶಿಷ್ಟ್ಯವು ಸರಿಯಾಗಿ ಕೆಲಸ ಮಾಡದಿದ್ದರೆ, ಆಫ್ ಮಾಡಿ."</string>
+ <string name="alert_windows_notification_turn_off_action" msgid="3367294525884949878">"ಆಫ್ ಮಾಡಿ"</string>
<string name="ext_media_checking_notification_title" msgid="5734005953288045806">"<xliff:g id="NAME">%s</xliff:g> ಅನ್ನು ಸಿದ್ಧಪಡಿಸಲಾಗುತ್ತಿದೆ"</string>
<string name="ext_media_checking_notification_message" msgid="4747432538578886744">"ದೋಷಗಳನ್ನು ಪರಿಶೀಲಿಸಲಾಗುತ್ತಿದೆ"</string>
<string name="ext_media_new_notification_message" msgid="7589986898808506239">"ಹೊಸ <xliff:g id="NAME">%s</xliff:g> ಪತ್ತೆಯಾಗಿದೆ"</string>
@@ -1713,4 +1709,18 @@
<string name="time_picker_prompt_label" msgid="7588093983899966783">"ಸಮಯದಲ್ಲಿ ಟೈಪ್ ಮಾಡಿ"</string>
<string name="time_picker_text_input_mode_description" msgid="4148166758173708199">"ಸಮಯವನ್ನು ನಮೂದಿಸಲು ಪಠ್ಯದ ನಮೂನೆಗೆ ಬದಲಿಸಿ."</string>
<string name="time_picker_radial_mode_description" msgid="4953403779779557198">"ಸಮಯವನ್ನು ನಮೂದಿಸಲು ಗಡಿಯಾರದ ನಮೂನೆಗೆ ಬದಲಿಸಿ."</string>
+ <!-- no translation found for autofill_save_title (7081244500504163245) -->
+ <skip />
+ <!-- no translation found for autofill_save_title_with_type (4977385733042555659) -->
+ <skip />
+ <!-- no translation found for autofill_save_yes (6398026094049005921) -->
+ <skip />
+ <!-- no translation found for autofill_save_no (2625132258725581787) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_password (5288448918465971568) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_address (4936707762193009542) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_credit_card (7127694776265563071) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index cf1289c..22d6dc6 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -1167,14 +1167,10 @@
<string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"탭하여 언어와 레이아웃을 선택하세요."</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
- <!-- no translation found for alert_windows_notification_channel_name (7443890103456396837) -->
- <skip />
- <!-- no translation found for alert_windows_notification_title (5399998516035621282) -->
- <skip />
- <!-- no translation found for alert_windows_notification_message (2456738662997073459) -->
- <skip />
- <!-- no translation found for alert_windows_notification_turn_off_action (3367294525884949878) -->
- <skip />
+ <string name="alert_windows_notification_channel_name" msgid="7443890103456396837">"<xliff:g id="NAME">%s</xliff:g>이(가) 다른 앱 위에 표시됨"</string>
+ <string name="alert_windows_notification_title" msgid="5399998516035621282">"<xliff:g id="NAME">%s</xliff:g> 앱이 상단에 표시됨"</string>
+ <string name="alert_windows_notification_message" msgid="2456738662997073459">"이 앱의 일부는 항상 표시될 수도 있습니다. 기능이 제대로 작동되지 않으면 사용 중지하세요."</string>
+ <string name="alert_windows_notification_turn_off_action" msgid="3367294525884949878">"사용 중지"</string>
<string name="ext_media_checking_notification_title" msgid="5734005953288045806">"<xliff:g id="NAME">%s</xliff:g> 준비 중"</string>
<string name="ext_media_checking_notification_message" msgid="4747432538578886744">"오류 확인 중"</string>
<string name="ext_media_new_notification_message" msgid="7589986898808506239">"새로운 <xliff:g id="NAME">%s</xliff:g> 감지됨"</string>
@@ -1712,4 +1708,18 @@
<string name="time_picker_prompt_label" msgid="7588093983899966783">"시간 입력"</string>
<string name="time_picker_text_input_mode_description" msgid="4148166758173708199">"시간 입력을 위해 텍스트 입력 모드로 전환합니다."</string>
<string name="time_picker_radial_mode_description" msgid="4953403779779557198">"시간 입력을 위해 시계 모드로 전환합니다."</string>
+ <!-- no translation found for autofill_save_title (7081244500504163245) -->
+ <skip />
+ <!-- no translation found for autofill_save_title_with_type (4977385733042555659) -->
+ <skip />
+ <!-- no translation found for autofill_save_yes (6398026094049005921) -->
+ <skip />
+ <!-- no translation found for autofill_save_no (2625132258725581787) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_password (5288448918465971568) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_address (4936707762193009542) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_credit_card (7127694776265563071) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-ky/strings.xml b/core/res/res/values-ky/strings.xml
index 33f72db..99d0ffd 100644
--- a/core/res/res/values-ky/strings.xml
+++ b/core/res/res/values-ky/strings.xml
@@ -1168,14 +1168,10 @@
<string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Тил жана калып тандоо үчүн таптап коюңуз"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
- <!-- no translation found for alert_windows_notification_channel_name (7443890103456396837) -->
- <skip />
- <!-- no translation found for alert_windows_notification_title (5399998516035621282) -->
- <skip />
- <!-- no translation found for alert_windows_notification_message (2456738662997073459) -->
- <skip />
- <!-- no translation found for alert_windows_notification_turn_off_action (3367294525884949878) -->
- <skip />
+ <string name="alert_windows_notification_channel_name" msgid="7443890103456396837">"<xliff:g id="NAME">%s</xliff:g> колдонмосун башка терезелердин үстүнөн көрсөтүү"</string>
+ <string name="alert_windows_notification_title" msgid="5399998516035621282">"<xliff:g id="NAME">%s</xliff:g> колд-сун эң үстүндө көрсөтүү"</string>
+ <string name="alert_windows_notification_message" msgid="2456738662997073459">"Бул колдонмонун бөлүктөрү дайыма көрүнүп турушу мүмкүн. Эгер бул функция туура иштебесе, аны өчүрүп коюңуз."</string>
+ <string name="alert_windows_notification_turn_off_action" msgid="3367294525884949878">"ӨЧҮРҮҮ"</string>
<string name="ext_media_checking_notification_title" msgid="5734005953288045806">"<xliff:g id="NAME">%s</xliff:g> даярдалууда"</string>
<string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Каталар текшерилүүдө"</string>
<string name="ext_media_new_notification_message" msgid="7589986898808506239">"Жаңы <xliff:g id="NAME">%s</xliff:g> аныкталды"</string>
@@ -1713,4 +1709,18 @@
<string name="time_picker_prompt_label" msgid="7588093983899966783">"Убакытты жазыңыз"</string>
<string name="time_picker_text_input_mode_description" msgid="4148166758173708199">"Убакытты текст киргизүү режиминде киргизиңиз."</string>
<string name="time_picker_radial_mode_description" msgid="4953403779779557198">"Убакытты дубал саатынын режиминде киргизиңиз."</string>
+ <!-- no translation found for autofill_save_title (7081244500504163245) -->
+ <skip />
+ <!-- no translation found for autofill_save_title_with_type (4977385733042555659) -->
+ <skip />
+ <!-- no translation found for autofill_save_yes (6398026094049005921) -->
+ <skip />
+ <!-- no translation found for autofill_save_no (2625132258725581787) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_password (5288448918465971568) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_address (4936707762193009542) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_credit_card (7127694776265563071) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-lo/strings.xml b/core/res/res/values-lo/strings.xml
index ba71473..654d8e6 100644
--- a/core/res/res/values-lo/strings.xml
+++ b/core/res/res/values-lo/strings.xml
@@ -1167,14 +1167,10 @@
<string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"ແຕະເພື່ອເລືອກພາສາ ແລະ ໂຄງແປ້ນພິມ"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
- <!-- no translation found for alert_windows_notification_channel_name (7443890103456396837) -->
- <skip />
- <!-- no translation found for alert_windows_notification_title (5399998516035621282) -->
- <skip />
- <!-- no translation found for alert_windows_notification_message (2456738662997073459) -->
- <skip />
- <!-- no translation found for alert_windows_notification_turn_off_action (3367294525884949878) -->
- <skip />
+ <string name="alert_windows_notification_channel_name" msgid="7443890103456396837">"<xliff:g id="NAME">%s</xliff:g> ແຕ້ມທັບແອັບອື່ນ"</string>
+ <string name="alert_windows_notification_title" msgid="5399998516035621282">"ແອັບ <xliff:g id="NAME">%s</xliff:g> ກຳລັງສະແດງຢູ່ໜ້າສຸດ."</string>
+ <string name="alert_windows_notification_message" msgid="2456738662997073459">"ບາງພາກສ່ວນຂອງແອັບນີ້ຈະປາກົດຢູ່ຕະຫຼອດເວລາ. ຫາກຄຸນສົມບັດນີ້ໃຊ້ໄດ້ບໍ່ດີ, ໃຫ້ປິດມັນໄວ້."</string>
+ <string name="alert_windows_notification_turn_off_action" msgid="3367294525884949878">"ປິດໄວ້"</string>
<string name="ext_media_checking_notification_title" msgid="5734005953288045806">"ກຳລັງກຽມ <xliff:g id="NAME">%s</xliff:g>"</string>
<string name="ext_media_checking_notification_message" msgid="4747432538578886744">"ກຳລັງກວດຫາຂໍ້ຜິດພາດ"</string>
<string name="ext_media_new_notification_message" msgid="7589986898808506239">"ກວດພົບ <xliff:g id="NAME">%s</xliff:g> ໃໝ່ແລ້ວ"</string>
@@ -1712,4 +1708,18 @@
<string name="time_picker_prompt_label" msgid="7588093983899966783">"ພິມເວລາໃສ່"</string>
<string name="time_picker_text_input_mode_description" msgid="4148166758173708199">"ສະຫຼັບໄປໃຊ້ໂໝດປ້ອນຂໍ້ຄວາມສຳລັບການປ້ອນເວລາ."</string>
<string name="time_picker_radial_mode_description" msgid="4953403779779557198">"ສະຫຼັບໄປໃຊ້ໂໝດໂມງສຳລັບການປ້ອນເວລາ."</string>
+ <!-- no translation found for autofill_save_title (7081244500504163245) -->
+ <skip />
+ <!-- no translation found for autofill_save_title_with_type (4977385733042555659) -->
+ <skip />
+ <!-- no translation found for autofill_save_yes (6398026094049005921) -->
+ <skip />
+ <!-- no translation found for autofill_save_no (2625132258725581787) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_password (5288448918465971568) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_address (4936707762193009542) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_credit_card (7127694776265563071) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml
index 07e730c..f808a99 100644
--- a/core/res/res/values-lt/strings.xml
+++ b/core/res/res/values-lt/strings.xml
@@ -1207,14 +1207,10 @@
<string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Palieskite, kad pasirinktumėte kalbą ir išdėstymą"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" AĄBCČDEĘĖFGHIĮYJKLMNOPRSŠTUŲŪVZŽ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789AĄBCČDEĘĖFGHIĮYJKLMNOPRSŠTUŲŪVZŽ"</string>
- <!-- no translation found for alert_windows_notification_channel_name (7443890103456396837) -->
- <skip />
- <!-- no translation found for alert_windows_notification_title (5399998516035621282) -->
- <skip />
- <!-- no translation found for alert_windows_notification_message (2456738662997073459) -->
- <skip />
- <!-- no translation found for alert_windows_notification_turn_off_action (3367294525884949878) -->
- <skip />
+ <string name="alert_windows_notification_channel_name" msgid="7443890103456396837">"<xliff:g id="NAME">%s</xliff:g> programa rodoma virš kitų programų"</string>
+ <string name="alert_windows_notification_title" msgid="5399998516035621282">"<xliff:g id="NAME">%s</xliff:g> programa rodoma virš kitų."</string>
+ <string name="alert_windows_notification_message" msgid="2456738662997073459">"Šios programos dalys gali likti matomos visą laiką. Jei ši funkcija tinkamai neveikia, išjunkite ją."</string>
+ <string name="alert_windows_notification_turn_off_action" msgid="3367294525884949878">"IŠJUNGTI"</string>
<string name="ext_media_checking_notification_title" msgid="5734005953288045806">"Ruošiama <xliff:g id="NAME">%s</xliff:g>"</string>
<string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Tikrinama, ar nėra klaidų"</string>
<string name="ext_media_new_notification_message" msgid="7589986898808506239">"Aptikta nauja <xliff:g id="NAME">%s</xliff:g>"</string>
@@ -1774,4 +1770,18 @@
<string name="time_picker_prompt_label" msgid="7588093983899966783">"Įveskite laiką"</string>
<string name="time_picker_text_input_mode_description" msgid="4148166758173708199">"Laiko įvestį pateikti perjungus į teksto įvesties režimą."</string>
<string name="time_picker_radial_mode_description" msgid="4953403779779557198">"Laiko įvestį pateikti perjungus į laikrodžio režimą."</string>
+ <!-- no translation found for autofill_save_title (7081244500504163245) -->
+ <skip />
+ <!-- no translation found for autofill_save_title_with_type (4977385733042555659) -->
+ <skip />
+ <!-- no translation found for autofill_save_yes (6398026094049005921) -->
+ <skip />
+ <!-- no translation found for autofill_save_no (2625132258725581787) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_password (5288448918465971568) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_address (4936707762193009542) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_credit_card (7127694776265563071) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml
index 06bcd6b..e7b4800 100644
--- a/core/res/res/values-lv/strings.xml
+++ b/core/res/res/values-lv/strings.xml
@@ -1187,14 +1187,10 @@
<string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Pieskarieties, lai atlasītu valodu un izkārtojumu"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" AĀBCČDEĒFGĢHIĪJKĶLĻMNŅOPRSŠTUŪVZŽ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789AĀBCČDEĒFGĢHIĪJKĶLĻMNŅOPRSŠTUŪVZŽ"</string>
- <!-- no translation found for alert_windows_notification_channel_name (7443890103456396837) -->
- <skip />
- <!-- no translation found for alert_windows_notification_title (5399998516035621282) -->
- <skip />
- <!-- no translation found for alert_windows_notification_message (2456738662997073459) -->
- <skip />
- <!-- no translation found for alert_windows_notification_turn_off_action (3367294525884949878) -->
- <skip />
+ <string name="alert_windows_notification_channel_name" msgid="7443890103456396837">"Lietotne <xliff:g id="NAME">%s</xliff:g> tiek rādīta pāri citām lietotnēm"</string>
+ <string name="alert_windows_notification_title" msgid="5399998516035621282">"Lietotne <xliff:g id="NAME">%s</xliff:g> ir redzama virspusē."</string>
+ <string name="alert_windows_notification_message" msgid="2456738662997073459">"Šīs lietotnes daļas joprojām var būt redzamas visu laiku. Ja šī funkcija nedarbojas pareizi, izslēdziet to."</string>
+ <string name="alert_windows_notification_turn_off_action" msgid="3367294525884949878">"IZSLĒGT"</string>
<string name="ext_media_checking_notification_title" msgid="5734005953288045806">"Notiek <xliff:g id="NAME">%s</xliff:g> sagatavošana"</string>
<string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Tiek meklētas kļūdas"</string>
<string name="ext_media_new_notification_message" msgid="7589986898808506239">"Tika atrasta jauna <xliff:g id="NAME">%s</xliff:g>."</string>
@@ -1743,4 +1739,18 @@
<string name="time_picker_prompt_label" msgid="7588093983899966783">"Ierakstiet laiku"</string>
<string name="time_picker_text_input_mode_description" msgid="4148166758173708199">"Lai ievadītu laiku, ieslēdziet teksta ievades režīmu."</string>
<string name="time_picker_radial_mode_description" msgid="4953403779779557198">"Lai ievadītu laiku, ieslēdziet pulksteņa režīmu."</string>
+ <!-- no translation found for autofill_save_title (7081244500504163245) -->
+ <skip />
+ <!-- no translation found for autofill_save_title_with_type (4977385733042555659) -->
+ <skip />
+ <!-- no translation found for autofill_save_yes (6398026094049005921) -->
+ <skip />
+ <!-- no translation found for autofill_save_no (2625132258725581787) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_password (5288448918465971568) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_address (4936707762193009542) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_credit_card (7127694776265563071) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-mk/strings.xml b/core/res/res/values-mk/strings.xml
index efb339b..8dae798 100644
--- a/core/res/res/values-mk/strings.xml
+++ b/core/res/res/values-mk/strings.xml
@@ -83,10 +83,10 @@
<string name="RuacMmi" msgid="7827887459138308886">"Одбивање несакани вознемирувачки повици"</string>
<string name="CndMmi" msgid="3116446237081575808">"Испорака на повикувачки број"</string>
<string name="DndMmi" msgid="1265478932418334331">"Не вознемирувај"</string>
- <string name="CLIRDefaultOnNextCallOn" msgid="429415409145781923">"Стандардно, повикувачот со овој ИД е ограничен. Следен повик: ограничен"</string>
- <string name="CLIRDefaultOnNextCallOff" msgid="3092918006077864624">"Стандардно, повикувачот со овој ИД е ограничен. Следен повик: не е ограничен"</string>
- <string name="CLIRDefaultOffNextCallOn" msgid="6179425182856418465">"Стандардно, повикувачот со овој ИД не е ограничен. Следен повик: ограничен"</string>
- <string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"Стандардно, повикувачот со овој ИД не е ограничен. Следен повик: не е ограничен"</string>
+ <string name="CLIRDefaultOnNextCallOn" msgid="429415409145781923">"Стандардно, повикувачот со овој ID е ограничен. Следен повик: ограничен"</string>
+ <string name="CLIRDefaultOnNextCallOff" msgid="3092918006077864624">"Стандардно, повикувачот со овој ID е ограничен. Следен повик: не е ограничен"</string>
+ <string name="CLIRDefaultOffNextCallOn" msgid="6179425182856418465">"Стандардно, повикувачот со овој ID не е ограничен. Следен повик: ограничен"</string>
+ <string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"Стандардно, повикувачот со овој ID не е ограничен. Следен повик: не е ограничен"</string>
<string name="serviceNotProvisioned" msgid="8614830180508686666">"Услугата не е предвидена."</string>
<string name="CLIRPermanent" msgid="3377371145926835671">"Не може да го промените поставувањето за ID на повикувач."</string>
<string name="RestrictedOnData" msgid="8653794784690065540">"Услугата за податоци е блокирана."</string>
@@ -1168,14 +1168,10 @@
<string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Допрете за избирање јазик и распоред"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
- <!-- no translation found for alert_windows_notification_channel_name (7443890103456396837) -->
- <skip />
- <!-- no translation found for alert_windows_notification_title (5399998516035621282) -->
- <skip />
- <!-- no translation found for alert_windows_notification_message (2456738662997073459) -->
- <skip />
- <!-- no translation found for alert_windows_notification_turn_off_action (3367294525884949878) -->
- <skip />
+ <string name="alert_windows_notification_channel_name" msgid="7443890103456396837">"<xliff:g id="NAME">%s</xliff:g> пишува врз други апликации"</string>
+ <string name="alert_windows_notification_title" msgid="5399998516035621282">"Апликацијата <xliff:g id="NAME">%s</xliff:g> е одозгора."</string>
+ <string name="alert_windows_notification_message" msgid="2456738662997073459">"Делови од апликацијава може да бидат видливи цело време. Ако функцијава не работи правилно, исклучете ја."</string>
+ <string name="alert_windows_notification_turn_off_action" msgid="3367294525884949878">"ИСКЛУЧИ"</string>
<string name="ext_media_checking_notification_title" msgid="5734005953288045806">"Се подготвува <xliff:g id="NAME">%s</xliff:g>"</string>
<string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Се проверува за грешки"</string>
<string name="ext_media_new_notification_message" msgid="7589986898808506239">"Откриена е нова <xliff:g id="NAME">%s</xliff:g>"</string>
@@ -1715,4 +1711,18 @@
<string name="time_picker_prompt_label" msgid="7588093983899966783">"Внесете време"</string>
<string name="time_picker_text_input_mode_description" msgid="4148166758173708199">"Префрлете се на режимот за внесување текст за да внесете време."</string>
<string name="time_picker_radial_mode_description" msgid="4953403779779557198">"Префрлете се на режимот за часовник за да внесете време."</string>
+ <!-- no translation found for autofill_save_title (7081244500504163245) -->
+ <skip />
+ <!-- no translation found for autofill_save_title_with_type (4977385733042555659) -->
+ <skip />
+ <!-- no translation found for autofill_save_yes (6398026094049005921) -->
+ <skip />
+ <!-- no translation found for autofill_save_no (2625132258725581787) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_password (5288448918465971568) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_address (4936707762193009542) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_credit_card (7127694776265563071) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-ml/strings.xml b/core/res/res/values-ml/strings.xml
index 13a2c6b..0226a85 100644
--- a/core/res/res/values-ml/strings.xml
+++ b/core/res/res/values-ml/strings.xml
@@ -1168,14 +1168,10 @@
<string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"ഭാഷയും ലേഔട്ടും തിരഞ്ഞെടുക്കുന്നതിന് ടാപ്പുചെയ്യുക"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
- <!-- no translation found for alert_windows_notification_channel_name (7443890103456396837) -->
- <skip />
- <!-- no translation found for alert_windows_notification_title (5399998516035621282) -->
- <skip />
- <!-- no translation found for alert_windows_notification_message (2456738662997073459) -->
- <skip />
- <!-- no translation found for alert_windows_notification_turn_off_action (3367294525884949878) -->
- <skip />
+ <string name="alert_windows_notification_channel_name" msgid="7443890103456396837">"<xliff:g id="NAME">%s</xliff:g> മറ്റ് ആപ്പുകൾക്ക് മുകളിൽ പ്രവർത്തിക്കും"</string>
+ <string name="alert_windows_notification_title" msgid="5399998516035621282">"<xliff:g id="NAME">%s</xliff:g> മുകളിൽ ദൃശ്യമാകുന്നു."</string>
+ <string name="alert_windows_notification_message" msgid="2456738662997073459">"ഈ ആപ്പിന്റെ ഭാഗങ്ങൾ തുടർന്നും ദൃശ്യമായേക്കാം. ഈ ഫീച്ചർ ശരിയായി പ്രവർത്തിക്കുന്നില്ലെങ്കിൽ അത് ഓഫ് ചെയ്യുക."</string>
+ <string name="alert_windows_notification_turn_off_action" msgid="3367294525884949878">"ഓഫാക്കുക"</string>
<string name="ext_media_checking_notification_title" msgid="5734005953288045806">"<xliff:g id="NAME">%s</xliff:g> തയ്യാറാകുന്നു"</string>
<string name="ext_media_checking_notification_message" msgid="4747432538578886744">"പിശകുകളുണ്ടോയെന്നു പരിശോധിക്കുന്നു"</string>
<string name="ext_media_new_notification_message" msgid="7589986898808506239">"പുതിയ <xliff:g id="NAME">%s</xliff:g> എന്നതിനെ തിരിച്ചറിഞ്ഞു"</string>
@@ -1713,4 +1709,18 @@
<string name="time_picker_prompt_label" msgid="7588093983899966783">"സമയത്തിൽ ടൈപ്പുചെയ്യുക"</string>
<string name="time_picker_text_input_mode_description" msgid="4148166758173708199">"സമയം നൽകുന്നതിന് ടെക്സ്റ്റ് ഇൻപുട്ട് മോഡിലേക്ക് മാറുക."</string>
<string name="time_picker_radial_mode_description" msgid="4953403779779557198">"സമയം നൽകുന്നതിന് ക്ലോക്ക് മോഡിലേക്ക് മാറുക."</string>
+ <!-- no translation found for autofill_save_title (7081244500504163245) -->
+ <skip />
+ <!-- no translation found for autofill_save_title_with_type (4977385733042555659) -->
+ <skip />
+ <!-- no translation found for autofill_save_yes (6398026094049005921) -->
+ <skip />
+ <!-- no translation found for autofill_save_no (2625132258725581787) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_password (5288448918465971568) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_address (4936707762193009542) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_credit_card (7127694776265563071) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-mn/strings.xml b/core/res/res/values-mn/strings.xml
index 7131be3f..2af2a21 100644
--- a/core/res/res/values-mn/strings.xml
+++ b/core/res/res/values-mn/strings.xml
@@ -1167,14 +1167,10 @@
<string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Хэл болон бүдүүвчийг сонгохын тулд дарна уу"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
- <!-- no translation found for alert_windows_notification_channel_name (7443890103456396837) -->
- <skip />
- <!-- no translation found for alert_windows_notification_title (5399998516035621282) -->
- <skip />
- <!-- no translation found for alert_windows_notification_message (2456738662997073459) -->
- <skip />
- <!-- no translation found for alert_windows_notification_turn_off_action (3367294525884949878) -->
- <skip />
+ <string name="alert_windows_notification_channel_name" msgid="7443890103456396837">"<xliff:g id="NAME">%s</xliff:g> бусад аппын дээр гарч ирсэн"</string>
+ <string name="alert_windows_notification_title" msgid="5399998516035621282">"<xliff:g id="NAME">%s</xliff:g> апп дээр харагдаж байна."</string>
+ <string name="alert_windows_notification_message" msgid="2456738662997073459">"Энэ аппын зарим хэсэг нь тогтмол харагдана. Энэ онцлог буруу ажиллаж байвал унтраана уу."</string>
+ <string name="alert_windows_notification_turn_off_action" msgid="3367294525884949878">"УНТРААХ"</string>
<string name="ext_media_checking_notification_title" msgid="5734005953288045806">"<xliff:g id="NAME">%s</xliff:g>-ыг бэлдэж байна"</string>
<string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Алдааг шалгаж байна"</string>
<string name="ext_media_new_notification_message" msgid="7589986898808506239">"Шинэ <xliff:g id="NAME">%s</xliff:g> илэрлээ"</string>
@@ -1710,4 +1706,18 @@
<string name="time_picker_prompt_label" msgid="7588093983899966783">"Хугацааг бичнэ үү"</string>
<string name="time_picker_text_input_mode_description" msgid="4148166758173708199">"Цагийг оруулахын тулд текст оруулах горимд шилжүүлнэ үү."</string>
<string name="time_picker_radial_mode_description" msgid="4953403779779557198">"Цагийг оруулахын тулд цагийн горимд шилжүүлнэ үү."</string>
+ <!-- no translation found for autofill_save_title (7081244500504163245) -->
+ <skip />
+ <!-- no translation found for autofill_save_title_with_type (4977385733042555659) -->
+ <skip />
+ <!-- no translation found for autofill_save_yes (6398026094049005921) -->
+ <skip />
+ <!-- no translation found for autofill_save_no (2625132258725581787) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_password (5288448918465971568) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_address (4936707762193009542) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_credit_card (7127694776265563071) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-mr/strings.xml b/core/res/res/values-mr/strings.xml
index 370564d..de3bed5 100644
--- a/core/res/res/values-mr/strings.xml
+++ b/core/res/res/values-mr/strings.xml
@@ -515,8 +515,8 @@
<string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"होल्डरला वाहकद्वारे-प्रदान केलेल्या कॉन्फिगरेशन अॅपची विनंती करण्याची अनुमती देते. सामान्य अॅप्ससाठी कधीही आवश्यक नसावे."</string>
<string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"नेटवर्क स्थितींवरील निरीक्षणांसाठी ऐका"</string>
<string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"अनु्प्रयोगाला नेटवर्क स्थितींवरील निरीक्षणे ऐकण्यासाठी अनुमती देते. सामान्य अॅप्ससाठी कधीही आवश्यक नसावे."</string>
- <string name="permlab_setInputCalibration" msgid="4902620118878467615">"इनपुट डिव्हाइस अंशांकन बदला"</string>
- <string name="permdesc_setInputCalibration" msgid="4527511047549456929">"स्पर्श स्क्रीनची मापन प्राचले सुधारित करण्यासाठी अॅप ला अनुमती देते. सामान्य अॅप्स साठी कधीही आवश्यक नसते."</string>
+ <string name="permlab_setInputCalibration" msgid="4902620118878467615">"इनपुट डिव्हाइस कॅलिब्रेशन बदला"</string>
+ <string name="permdesc_setInputCalibration" msgid="4527511047549456929">"स्पर्श स्क्रीनची कॅलिब्रेशन प्राचले सुधारित करण्यासाठी अॅप ला अनुमती देते. सामान्य अॅप्स साठी कधीही आवश्यक नसते."</string>
<string name="permlab_accessDrmCertificates" msgid="7436886640723203615">"DRM प्रमाणपत्रांवर प्रवेश करा"</string>
<string name="permdesc_accessDrmCertificates" msgid="8073288354426159089">"DRM प्रमाणपत्रांची तरतूद करण्यासाठी आणि वापरण्यासाठी अनुप्रयोगास अनुमती देते. सामान्य अॅप्सकरिता कधीही आवश्यकता नसते."</string>
<string name="permlab_handoverStatus" msgid="7820353257219300883">"Android बीम स्थानांतरण स्थिती प्राप्त करा"</string>
@@ -1168,14 +1168,10 @@
<string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"भाषा आणि लेआउट निवडण्यासाठी टॅप करा"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
- <!-- no translation found for alert_windows_notification_channel_name (7443890103456396837) -->
- <skip />
- <!-- no translation found for alert_windows_notification_title (5399998516035621282) -->
- <skip />
- <!-- no translation found for alert_windows_notification_message (2456738662997073459) -->
- <skip />
- <!-- no translation found for alert_windows_notification_turn_off_action (3367294525884949878) -->
- <skip />
+ <string name="alert_windows_notification_channel_name" msgid="7443890103456396837">"<xliff:g id="NAME">%s</xliff:g> इतर अॅप्सवर काढा"</string>
+ <string name="alert_windows_notification_title" msgid="5399998516035621282">"<xliff:g id="NAME">%s</xliff:g> अॅप शीर्षस्थानी प्रदर्शित होत आहे"</string>
+ <string name="alert_windows_notification_message" msgid="2456738662997073459">"या अॅपचे भाग सर्व वेळी दृश्यमान असू शकतात. हे वैशिष्ट्य बरोबर काम करत नसल्यास, ते बंद करा."</string>
+ <string name="alert_windows_notification_turn_off_action" msgid="3367294525884949878">"बंद करा"</string>
<string name="ext_media_checking_notification_title" msgid="5734005953288045806">"<xliff:g id="NAME">%s</xliff:g> तयार करीत आहे"</string>
<string name="ext_media_checking_notification_message" msgid="4747432538578886744">"त्रुटींसाठी तपासत आहे"</string>
<string name="ext_media_new_notification_message" msgid="7589986898808506239">"नवीन <xliff:g id="NAME">%s</xliff:g> आढळले"</string>
@@ -1713,4 +1709,18 @@
<string name="time_picker_prompt_label" msgid="7588093983899966783">"वेळ टाइप करा"</string>
<string name="time_picker_text_input_mode_description" msgid="4148166758173708199">"वेळ इनपुटसाठी मजकूर इनपुट मोडवर स्विच करा."</string>
<string name="time_picker_radial_mode_description" msgid="4953403779779557198">"वेळ इनपुटसाठी घड्याळ मोडवर स्विच करा."</string>
+ <!-- no translation found for autofill_save_title (7081244500504163245) -->
+ <skip />
+ <!-- no translation found for autofill_save_title_with_type (4977385733042555659) -->
+ <skip />
+ <!-- no translation found for autofill_save_yes (6398026094049005921) -->
+ <skip />
+ <!-- no translation found for autofill_save_no (2625132258725581787) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_password (5288448918465971568) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_address (4936707762193009542) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_credit_card (7127694776265563071) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-ms/strings.xml b/core/res/res/values-ms/strings.xml
index 39c950a..171a02a 100644
--- a/core/res/res/values-ms/strings.xml
+++ b/core/res/res/values-ms/strings.xml
@@ -1167,14 +1167,10 @@
<string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Ketik untuk memilih bahasa dan susun atur"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
- <!-- no translation found for alert_windows_notification_channel_name (7443890103456396837) -->
- <skip />
- <!-- no translation found for alert_windows_notification_title (5399998516035621282) -->
- <skip />
- <!-- no translation found for alert_windows_notification_message (2456738662997073459) -->
- <skip />
- <!-- no translation found for alert_windows_notification_turn_off_action (3367294525884949878) -->
- <skip />
+ <string name="alert_windows_notification_channel_name" msgid="7443890103456396837">"<xliff:g id="NAME">%s</xliff:g> melukis di atas apl lain"</string>
+ <string name="alert_windows_notification_title" msgid="5399998516035621282">"Apl <xliff:g id="NAME">%s</xliff:g> dipaparkan di bahagian atas."</string>
+ <string name="alert_windows_notification_message" msgid="2456738662997073459">"Sebahagian daripada apl ini mungkin kekal kelihatan pada sepanjang masa. Jika ciri ini tidak berfungsi dengan betul, matikan ciri ini."</string>
+ <string name="alert_windows_notification_turn_off_action" msgid="3367294525884949878">"MATIKAN"</string>
<string name="ext_media_checking_notification_title" msgid="5734005953288045806">"Menyediakan <xliff:g id="NAME">%s</xliff:g>"</string>
<string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Menyemak untuk mengesan ralat"</string>
<string name="ext_media_new_notification_message" msgid="7589986898808506239">"<xliff:g id="NAME">%s</xliff:g> baharu dikesan"</string>
@@ -1712,4 +1708,18 @@
<string name="time_picker_prompt_label" msgid="7588093983899966783">"Taipkan masa"</string>
<string name="time_picker_text_input_mode_description" msgid="4148166758173708199">"Beralih ke mod input teks untuk input masa."</string>
<string name="time_picker_radial_mode_description" msgid="4953403779779557198">"Beralih ke mod jam untuk input masa."</string>
+ <!-- no translation found for autofill_save_title (7081244500504163245) -->
+ <skip />
+ <!-- no translation found for autofill_save_title_with_type (4977385733042555659) -->
+ <skip />
+ <!-- no translation found for autofill_save_yes (6398026094049005921) -->
+ <skip />
+ <!-- no translation found for autofill_save_no (2625132258725581787) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_password (5288448918465971568) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_address (4936707762193009542) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_credit_card (7127694776265563071) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-my/strings.xml b/core/res/res/values-my/strings.xml
index b9269af..9bd2602 100644
--- a/core/res/res/values-my/strings.xml
+++ b/core/res/res/values-my/strings.xml
@@ -1168,14 +1168,10 @@
<string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"ဘာသာစကားနှင့် အသွင်အပြင်ရွေးချယ်ရန် တို့ပါ"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
- <!-- no translation found for alert_windows_notification_channel_name (7443890103456396837) -->
- <skip />
- <!-- no translation found for alert_windows_notification_title (5399998516035621282) -->
- <skip />
- <!-- no translation found for alert_windows_notification_message (2456738662997073459) -->
- <skip />
- <!-- no translation found for alert_windows_notification_turn_off_action (3367294525884949878) -->
- <skip />
+ <string name="alert_windows_notification_channel_name" msgid="7443890103456396837">"<xliff:g id="NAME">%s</xliff:g> သည် အခြားအက်ပ်များအပေါ်တွင် ပေါ်ပါမည်"</string>
+ <string name="alert_windows_notification_title" msgid="5399998516035621282">"<xliff:g id="NAME">%s</xliff:g> အက်ပ်ကို အပေါ်ဆုံးတွင် ပြမည်။"</string>
+ <string name="alert_windows_notification_message" msgid="2456738662997073459">"ဤအက်ပ်၏ တစ်စိတ်တစ်ဒေသကို အမြဲမြင်တွေ့နိုင်ပါမည်။ အကယ်၍ ဤဝန်ဆောင်မှုသည် မှန်မှန်ကန်ကန် အလုပ်မလုပ်လျှင် ၎င်းကို ပိတ်လိုက်ပါ။"</string>
+ <string name="alert_windows_notification_turn_off_action" msgid="3367294525884949878">"ပိတ်ပါ"</string>
<string name="ext_media_checking_notification_title" msgid="5734005953288045806">"<xliff:g id="NAME">%s</xliff:g> ပြင်ဆင်နေသည်"</string>
<string name="ext_media_checking_notification_message" msgid="4747432538578886744">"အမှားအယွင်းများ စစ်ဆေးနေသည်"</string>
<string name="ext_media_new_notification_message" msgid="7589986898808506239">"<xliff:g id="NAME">%s</xliff:g> အသစ်တွေ့ရှိပါသည်"</string>
@@ -1713,4 +1709,18 @@
<string name="time_picker_prompt_label" msgid="7588093983899966783">"အချိန်ကို ရိုက်ရန်"</string>
<string name="time_picker_text_input_mode_description" msgid="4148166758173708199">"အချိန်ထည့်သွင်းရန် စာသားထည့်သွင်းမှုမုဒ်သို့ ပြောင်းပါ။"</string>
<string name="time_picker_radial_mode_description" msgid="4953403779779557198">"အချိန်ထည့်သွင်းမှုအတွက် နာရီမုဒ်သို့ ပြောင်းပါ။"</string>
+ <!-- no translation found for autofill_save_title (7081244500504163245) -->
+ <skip />
+ <!-- no translation found for autofill_save_title_with_type (4977385733042555659) -->
+ <skip />
+ <!-- no translation found for autofill_save_yes (6398026094049005921) -->
+ <skip />
+ <!-- no translation found for autofill_save_no (2625132258725581787) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_password (5288448918465971568) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_address (4936707762193009542) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_credit_card (7127694776265563071) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index 090cb9e..8643a2e 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -1167,14 +1167,10 @@
<string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Trykk for å velge språk og layout"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZÆØÅ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZÆØÅ"</string>
- <!-- no translation found for alert_windows_notification_channel_name (7443890103456396837) -->
- <skip />
- <!-- no translation found for alert_windows_notification_title (5399998516035621282) -->
- <skip />
- <!-- no translation found for alert_windows_notification_message (2456738662997073459) -->
- <skip />
- <!-- no translation found for alert_windows_notification_turn_off_action (3367294525884949878) -->
- <skip />
+ <string name="alert_windows_notification_channel_name" msgid="7443890103456396837">"<xliff:g id="NAME">%s</xliff:g> ligger over andre apper"</string>
+ <string name="alert_windows_notification_title" msgid="5399998516035621282">"<xliff:g id="NAME">%s</xliff:g>-appen vises øverst."</string>
+ <string name="alert_windows_notification_message" msgid="2456738662997073459">"Deler av denne appen kan være synlige til enhver tid. Slå denne funksjonen av hvis den ikke fungerer som den skal."</string>
+ <string name="alert_windows_notification_turn_off_action" msgid="3367294525884949878">"SLÅ AV"</string>
<string name="ext_media_checking_notification_title" msgid="5734005953288045806">"Forbereder <xliff:g id="NAME">%s</xliff:g>"</string>
<string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Sjekker for feil"</string>
<string name="ext_media_new_notification_message" msgid="7589986898808506239">"<xliff:g id="NAME">%s</xliff:g> ble oppdaget"</string>
@@ -1712,4 +1708,18 @@
<string name="time_picker_prompt_label" msgid="7588093983899966783">"Skriv inn klokkeslett"</string>
<string name="time_picker_text_input_mode_description" msgid="4148166758173708199">"Bytt til tekstinndatamodus for tidsinndata."</string>
<string name="time_picker_radial_mode_description" msgid="4953403779779557198">"Bytt til klokkemodus for tidsinndata."</string>
+ <!-- no translation found for autofill_save_title (7081244500504163245) -->
+ <skip />
+ <!-- no translation found for autofill_save_title_with_type (4977385733042555659) -->
+ <skip />
+ <!-- no translation found for autofill_save_yes (6398026094049005921) -->
+ <skip />
+ <!-- no translation found for autofill_save_no (2625132258725581787) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_password (5288448918465971568) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_address (4936707762193009542) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_credit_card (7127694776265563071) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-ne/strings.xml b/core/res/res/values-ne/strings.xml
index 0b028a2..f41269a 100644
--- a/core/res/res/values-ne/strings.xml
+++ b/core/res/res/values-ne/strings.xml
@@ -1173,14 +1173,10 @@
<string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"भाषा र लेआउट चयन गर्न ट्याप गर्नुहोस्"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
- <!-- no translation found for alert_windows_notification_channel_name (7443890103456396837) -->
- <skip />
- <!-- no translation found for alert_windows_notification_title (5399998516035621282) -->
- <skip />
- <!-- no translation found for alert_windows_notification_message (2456738662997073459) -->
- <skip />
- <!-- no translation found for alert_windows_notification_turn_off_action (3367294525884949878) -->
- <skip />
+ <string name="alert_windows_notification_channel_name" msgid="7443890103456396837">"<xliff:g id="NAME">%s</xliff:g> लाई अन्य अनुप्रयोगहरूमा देखिन दिनुहोस्"</string>
+ <string name="alert_windows_notification_title" msgid="5399998516035621282">"<xliff:g id="NAME">%s</xliff:g> अनुप्रयोग शीर्षमा देखाउँदै।"</string>
+ <string name="alert_windows_notification_message" msgid="2456738662997073459">"यो अनुप्रयोगका केही अंशहरू सधैँ देखिरहन सक्छन्। यो सुविधाले सही ढंगले काम गरिरहेको छैन भने, यसलाई बन्द गर्नुहोस्।"</string>
+ <string name="alert_windows_notification_turn_off_action" msgid="3367294525884949878">"निष्क्रिय पार्नुहोस्"</string>
<string name="ext_media_checking_notification_title" msgid="5734005953288045806">"तयारी गर्दै <xliff:g id="NAME">%s</xliff:g>"</string>
<string name="ext_media_checking_notification_message" msgid="4747432538578886744">"त्रुटिहरूको लागि जाँच गर्दै"</string>
<string name="ext_media_new_notification_message" msgid="7589986898808506239">"नयाँ <xliff:g id="NAME">%s</xliff:g> भेटियो"</string>
@@ -1718,4 +1714,18 @@
<string name="time_picker_prompt_label" msgid="7588093983899966783">"समय टाइप गर्नुहोस्"</string>
<string name="time_picker_text_input_mode_description" msgid="4148166758173708199">"समय इनपुट गर्न पाठ इनपुट मोडमा स्विच गर्नुहोस्।"</string>
<string name="time_picker_radial_mode_description" msgid="4953403779779557198">"समय इनपुट गर्न घडी मोडमा स्विच गर्नुहोस्।"</string>
+ <!-- no translation found for autofill_save_title (7081244500504163245) -->
+ <skip />
+ <!-- no translation found for autofill_save_title_with_type (4977385733042555659) -->
+ <skip />
+ <!-- no translation found for autofill_save_yes (6398026094049005921) -->
+ <skip />
+ <!-- no translation found for autofill_save_no (2625132258725581787) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_password (5288448918465971568) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_address (4936707762193009542) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_credit_card (7127694776265563071) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index 1c707f9..60f3363 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -1167,14 +1167,10 @@
<string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Tik om een taal en indeling te selecteren"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
- <!-- no translation found for alert_windows_notification_channel_name (7443890103456396837) -->
- <skip />
- <!-- no translation found for alert_windows_notification_title (5399998516035621282) -->
- <skip />
- <!-- no translation found for alert_windows_notification_message (2456738662997073459) -->
- <skip />
- <!-- no translation found for alert_windows_notification_turn_off_action (3367294525884949878) -->
- <skip />
+ <string name="alert_windows_notification_channel_name" msgid="7443890103456396837">"<xliff:g id="NAME">%s</xliff:g> wordt weergegeven over andere apps"</string>
+ <string name="alert_windows_notification_title" msgid="5399998516035621282">"<xliff:g id="NAME">%s</xliff:g>-app bovenop weergeven."</string>
+ <string name="alert_windows_notification_message" msgid="2456738662997073459">"Delen van deze app blijven altijd zichtbaar. Als deze functie niet correct werkt, schakel je deze uit."</string>
+ <string name="alert_windows_notification_turn_off_action" msgid="3367294525884949878">"UITSCHAKELEN"</string>
<string name="ext_media_checking_notification_title" msgid="5734005953288045806">"<xliff:g id="NAME">%s</xliff:g> voorbereiden"</string>
<string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Controleren op fouten"</string>
<string name="ext_media_new_notification_message" msgid="7589986898808506239">"Nieuwe <xliff:g id="NAME">%s</xliff:g> gedetecteerd"</string>
@@ -1712,4 +1708,18 @@
<string name="time_picker_prompt_label" msgid="7588093983899966783">"Typ een tijd"</string>
<string name="time_picker_text_input_mode_description" msgid="4148166758173708199">"Schakel naar de tekstinvoermodus om de tijd in te voeren."</string>
<string name="time_picker_radial_mode_description" msgid="4953403779779557198">"Schakel naar de klokmodus om de tijd in te voeren."</string>
+ <!-- no translation found for autofill_save_title (7081244500504163245) -->
+ <skip />
+ <!-- no translation found for autofill_save_title_with_type (4977385733042555659) -->
+ <skip />
+ <!-- no translation found for autofill_save_yes (6398026094049005921) -->
+ <skip />
+ <!-- no translation found for autofill_save_no (2625132258725581787) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_password (5288448918465971568) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_address (4936707762193009542) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_credit_card (7127694776265563071) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-pa/strings.xml b/core/res/res/values-pa/strings.xml
index 182b3a5..34c0396 100644
--- a/core/res/res/values-pa/strings.xml
+++ b/core/res/res/values-pa/strings.xml
@@ -1168,14 +1168,10 @@
<string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"ਭਾਸ਼ਾ ਅਤੇ ਖਾਕਾ ਚੁਣਨ ਲਈ ਟੈਪ ਕਰੋ"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
- <!-- no translation found for alert_windows_notification_channel_name (7443890103456396837) -->
- <skip />
- <!-- no translation found for alert_windows_notification_title (5399998516035621282) -->
- <skip />
- <!-- no translation found for alert_windows_notification_message (2456738662997073459) -->
- <skip />
- <!-- no translation found for alert_windows_notification_turn_off_action (3367294525884949878) -->
- <skip />
+ <string name="alert_windows_notification_channel_name" msgid="7443890103456396837">"<xliff:g id="NAME">%s</xliff:g> ਹੋਰਾਂ ਐਪਾਂ ਉੱਤੇ ਪਸਰ ਸਕਦੀ ਹੈ"</string>
+ <string name="alert_windows_notification_title" msgid="5399998516035621282">"<xliff:g id="NAME">%s</xliff:g> ਐਪ ਹੋਰ ਐਪਾਂ ਉੱਤੇ ਪਸਰੀ ਦਿਸ ਰਹੀ ਹੈ।"</string>
+ <string name="alert_windows_notification_message" msgid="2456738662997073459">"ਹੋ ਸਕਦਾ ਹੈ ਕਿ ਇਸ ਐਪ ਦੇ ਕੁਝ ਹਿੱਸੇ ਹਰ ਸਮੇਂ ਵਿਖਾਈ ਦੇਣ। ਜੇਕਰ ਇਹ ਵਿਸ਼ੇਸ਼ਤਾ ਸਹੀ ਢੰਗ ਨਾਲ ਕੰਮ ਨਹੀਂ ਕਰ ਰਹੀ ਹੈ, ਤਾਂ ਇਸਨੂੰ ਬੰਦ ਕਰੋ।"</string>
+ <string name="alert_windows_notification_turn_off_action" msgid="3367294525884949878">"ਬੰਦ ਕਰੋ"</string>
<string name="ext_media_checking_notification_title" msgid="5734005953288045806">"<xliff:g id="NAME">%s</xliff:g> ਤਿਆਰ ਹੋ ਰਿਹਾ ਹੈ"</string>
<string name="ext_media_checking_notification_message" msgid="4747432538578886744">"ਤਰੁੱਟੀਆਂ ਦੀ ਜਾਂਚ ਕਰ ਰਿਹਾ ਹੈ"</string>
<string name="ext_media_new_notification_message" msgid="7589986898808506239">"ਨਵੇਂ <xliff:g id="NAME">%s</xliff:g> ਦਾ ਪਤਾ ਲਗਾਇਆ ਗਿਆ"</string>
@@ -1713,4 +1709,18 @@
<string name="time_picker_prompt_label" msgid="7588093983899966783">"ਸਮਾਂ ਟਾਈਪ ਕਰੋ"</string>
<string name="time_picker_text_input_mode_description" msgid="4148166758173708199">"ਸਮਾਂ ਇਨਪੁੱਟ ਕਰਨ ਲਈ ਲਿਖਤ ਇਨਪੁੱਟ ਮੋਡ \'ਤੇ ਬਦਲੀ ਕਰੋ।"</string>
<string name="time_picker_radial_mode_description" msgid="4953403779779557198">"ਸਮਾਂ ਇਨਪੁੱਟ ਕਰਨ ਲਈ ਘੜੀ ਮੋਡ \'ਤੇ ਬਦਲੀ ਕਰੋ।"</string>
+ <!-- no translation found for autofill_save_title (7081244500504163245) -->
+ <skip />
+ <!-- no translation found for autofill_save_title_with_type (4977385733042555659) -->
+ <skip />
+ <!-- no translation found for autofill_save_yes (6398026094049005921) -->
+ <skip />
+ <!-- no translation found for autofill_save_no (2625132258725581787) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_password (5288448918465971568) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_address (4936707762193009542) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_credit_card (7127694776265563071) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index 29c91b6..9ce2f69 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -1207,14 +1207,10 @@
<string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Kliknij, by wybrać język i układ"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" AĄBCĆDEĘFGHIJKLŁMNŃOÓPQRSŚTUVWXYZŹŻ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
- <!-- no translation found for alert_windows_notification_channel_name (7443890103456396837) -->
- <skip />
- <!-- no translation found for alert_windows_notification_title (5399998516035621282) -->
- <skip />
- <!-- no translation found for alert_windows_notification_message (2456738662997073459) -->
- <skip />
- <!-- no translation found for alert_windows_notification_turn_off_action (3367294525884949878) -->
- <skip />
+ <string name="alert_windows_notification_channel_name" msgid="7443890103456396837">"Aplikacja <xliff:g id="NAME">%s</xliff:g> wyświetla się nad innymi"</string>
+ <string name="alert_windows_notification_title" msgid="5399998516035621282">"Aplikacja <xliff:g id="NAME">%s</xliff:g> jest nad innymi."</string>
+ <string name="alert_windows_notification_message" msgid="2456738662997073459">"Fragmenty tej aplikacji mogą być widoczne przez cały czas. Jeśli ta funkcja nie działa prawidłowo, wyłącz ją."</string>
+ <string name="alert_windows_notification_turn_off_action" msgid="3367294525884949878">"WYŁĄCZ"</string>
<string name="ext_media_checking_notification_title" msgid="5734005953288045806">"Przygotowuję: <xliff:g id="NAME">%s</xliff:g>"</string>
<string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Sprawdzanie w poszukiwaniu błędów"</string>
<string name="ext_media_new_notification_message" msgid="7589986898808506239">"Wykryto nowy nośnik: <xliff:g id="NAME">%s</xliff:g>"</string>
@@ -1774,4 +1770,18 @@
<string name="time_picker_prompt_label" msgid="7588093983899966783">"Podaj czas"</string>
<string name="time_picker_text_input_mode_description" msgid="4148166758173708199">"Aby wprowadzić czas, włącz tryb wprowadzania tekstu."</string>
<string name="time_picker_radial_mode_description" msgid="4953403779779557198">"Aby wprowadzić czas, włącz tryb zegara."</string>
+ <!-- no translation found for autofill_save_title (7081244500504163245) -->
+ <skip />
+ <!-- no translation found for autofill_save_title_with_type (4977385733042555659) -->
+ <skip />
+ <!-- no translation found for autofill_save_yes (6398026094049005921) -->
+ <skip />
+ <!-- no translation found for autofill_save_no (2625132258725581787) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_password (5288448918465971568) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_address (4936707762193009542) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_credit_card (7127694776265563071) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-pt-rBR/strings.xml b/core/res/res/values-pt-rBR/strings.xml
index f66df7d..92dcc90b 100644
--- a/core/res/res/values-pt-rBR/strings.xml
+++ b/core/res/res/values-pt-rBR/strings.xml
@@ -1167,14 +1167,10 @@
<string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Toque para selecionar o idioma e o layout"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
- <!-- no translation found for alert_windows_notification_channel_name (7443890103456396837) -->
- <skip />
- <!-- no translation found for alert_windows_notification_title (5399998516035621282) -->
- <skip />
- <!-- no translation found for alert_windows_notification_message (2456738662997073459) -->
- <skip />
- <!-- no translation found for alert_windows_notification_turn_off_action (3367294525884949878) -->
- <skip />
+ <string name="alert_windows_notification_channel_name" msgid="7443890103456396837">"Sobreposição do <xliff:g id="NAME">%s</xliff:g> a outros apps"</string>
+ <string name="alert_windows_notification_title" msgid="5399998516035621282">"<xliff:g id="NAME">%s</xliff:g> exibido na parte superior da tela."</string>
+ <string name="alert_windows_notification_message" msgid="2456738662997073459">"Partes desse app podem ficar sempre visíveis. Se esse recurso não estiver funcionando corretamente, desative-o."</string>
+ <string name="alert_windows_notification_turn_off_action" msgid="3367294525884949878">"DESATIVAR"</string>
<string name="ext_media_checking_notification_title" msgid="5734005953288045806">"Preparando <xliff:g id="NAME">%s</xliff:g>"</string>
<string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Procurando erros"</string>
<string name="ext_media_new_notification_message" msgid="7589986898808506239">"Novo <xliff:g id="NAME">%s</xliff:g> detectado"</string>
@@ -1712,4 +1708,18 @@
<string name="time_picker_prompt_label" msgid="7588093983899966783">"Digite o horário"</string>
<string name="time_picker_text_input_mode_description" msgid="4148166758173708199">"Alterne para o modo de entrada de texto para informar o horário."</string>
<string name="time_picker_radial_mode_description" msgid="4953403779779557198">"Alterne para o modo de relógio para informar o horário."</string>
+ <!-- no translation found for autofill_save_title (7081244500504163245) -->
+ <skip />
+ <!-- no translation found for autofill_save_title_with_type (4977385733042555659) -->
+ <skip />
+ <!-- no translation found for autofill_save_yes (6398026094049005921) -->
+ <skip />
+ <!-- no translation found for autofill_save_no (2625132258725581787) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_password (5288448918465971568) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_address (4936707762193009542) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_credit_card (7127694776265563071) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index c4e0fbc..dfc64d3 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -1167,14 +1167,10 @@
<string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Toque para selecionar o idioma e o esquema"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
- <!-- no translation found for alert_windows_notification_channel_name (7443890103456396837) -->
- <skip />
- <!-- no translation found for alert_windows_notification_title (5399998516035621282) -->
- <skip />
- <!-- no translation found for alert_windows_notification_message (2456738662997073459) -->
- <skip />
- <!-- no translation found for alert_windows_notification_turn_off_action (3367294525884949878) -->
- <skip />
+ <string name="alert_windows_notification_channel_name" msgid="7443890103456396837">"Sobrepor a aplicação <xliff:g id="NAME">%s</xliff:g> a outras aplicações"</string>
+ <string name="alert_windows_notification_title" msgid="5399998516035621282">"Aplic. <xliff:g id="NAME">%s</xliff:g> apresentada por cima."</string>
+ <string name="alert_windows_notification_message" msgid="2456738662997073459">"É possível que partes desta aplicação permaneçam sempre visíveis. Se esta funcionalidade não estiver a funcionar corretamente, desative-a."</string>
+ <string name="alert_windows_notification_turn_off_action" msgid="3367294525884949878">"DESATIVAR"</string>
<string name="ext_media_checking_notification_title" msgid="5734005953288045806">"A preparar o <xliff:g id="NAME">%s</xliff:g>"</string>
<string name="ext_media_checking_notification_message" msgid="4747432538578886744">"A verificar a presença de erros"</string>
<string name="ext_media_new_notification_message" msgid="7589986898808506239">"Novo <xliff:g id="NAME">%s</xliff:g> detetado"</string>
@@ -1712,4 +1708,18 @@
<string name="time_picker_prompt_label" msgid="7588093983899966783">"Introduza a hora"</string>
<string name="time_picker_text_input_mode_description" msgid="4148166758173708199">"Mude para o modo de introdução de texto para a introdução da hora."</string>
<string name="time_picker_radial_mode_description" msgid="4953403779779557198">"Mude para o modo de relógio para a introdução da hora."</string>
+ <!-- no translation found for autofill_save_title (7081244500504163245) -->
+ <skip />
+ <!-- no translation found for autofill_save_title_with_type (4977385733042555659) -->
+ <skip />
+ <!-- no translation found for autofill_save_yes (6398026094049005921) -->
+ <skip />
+ <!-- no translation found for autofill_save_no (2625132258725581787) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_password (5288448918465971568) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_address (4936707762193009542) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_credit_card (7127694776265563071) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index f66df7d..92dcc90b 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -1167,14 +1167,10 @@
<string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Toque para selecionar o idioma e o layout"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
- <!-- no translation found for alert_windows_notification_channel_name (7443890103456396837) -->
- <skip />
- <!-- no translation found for alert_windows_notification_title (5399998516035621282) -->
- <skip />
- <!-- no translation found for alert_windows_notification_message (2456738662997073459) -->
- <skip />
- <!-- no translation found for alert_windows_notification_turn_off_action (3367294525884949878) -->
- <skip />
+ <string name="alert_windows_notification_channel_name" msgid="7443890103456396837">"Sobreposição do <xliff:g id="NAME">%s</xliff:g> a outros apps"</string>
+ <string name="alert_windows_notification_title" msgid="5399998516035621282">"<xliff:g id="NAME">%s</xliff:g> exibido na parte superior da tela."</string>
+ <string name="alert_windows_notification_message" msgid="2456738662997073459">"Partes desse app podem ficar sempre visíveis. Se esse recurso não estiver funcionando corretamente, desative-o."</string>
+ <string name="alert_windows_notification_turn_off_action" msgid="3367294525884949878">"DESATIVAR"</string>
<string name="ext_media_checking_notification_title" msgid="5734005953288045806">"Preparando <xliff:g id="NAME">%s</xliff:g>"</string>
<string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Procurando erros"</string>
<string name="ext_media_new_notification_message" msgid="7589986898808506239">"Novo <xliff:g id="NAME">%s</xliff:g> detectado"</string>
@@ -1712,4 +1708,18 @@
<string name="time_picker_prompt_label" msgid="7588093983899966783">"Digite o horário"</string>
<string name="time_picker_text_input_mode_description" msgid="4148166758173708199">"Alterne para o modo de entrada de texto para informar o horário."</string>
<string name="time_picker_radial_mode_description" msgid="4953403779779557198">"Alterne para o modo de relógio para informar o horário."</string>
+ <!-- no translation found for autofill_save_title (7081244500504163245) -->
+ <skip />
+ <!-- no translation found for autofill_save_title_with_type (4977385733042555659) -->
+ <skip />
+ <!-- no translation found for autofill_save_yes (6398026094049005921) -->
+ <skip />
+ <!-- no translation found for autofill_save_no (2625132258725581787) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_password (5288448918465971568) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_address (4936707762193009542) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_credit_card (7127694776265563071) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index c4416f8..d95e715 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -1187,14 +1187,10 @@
<string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Atingeți pentru a selecta limba și aspectul"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
- <!-- no translation found for alert_windows_notification_channel_name (7443890103456396837) -->
- <skip />
- <!-- no translation found for alert_windows_notification_title (5399998516035621282) -->
- <skip />
- <!-- no translation found for alert_windows_notification_message (2456738662997073459) -->
- <skip />
- <!-- no translation found for alert_windows_notification_turn_off_action (3367294525884949878) -->
- <skip />
+ <string name="alert_windows_notification_channel_name" msgid="7443890103456396837">"<xliff:g id="NAME">%s</xliff:g> afișează deasupra altor aplicații"</string>
+ <string name="alert_windows_notification_title" msgid="5399998516035621282">"<xliff:g id="NAME">%s</xliff:g> se afișează deasupra."</string>
+ <string name="alert_windows_notification_message" msgid="2456738662997073459">"Este posibil ca unele părți ale acestei aplicații să rămână vizibile permanent. Dacă această caracteristică nu funcționează corect, dezactivați-o."</string>
+ <string name="alert_windows_notification_turn_off_action" msgid="3367294525884949878">"DEZACTIVAȚI"</string>
<string name="ext_media_checking_notification_title" msgid="5734005953288045806">"Se pregătește <xliff:g id="NAME">%s</xliff:g>"</string>
<string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Se verifică dacă există erori"</string>
<string name="ext_media_new_notification_message" msgid="7589986898808506239">"A fost detectat un nou <xliff:g id="NAME">%s</xliff:g>"</string>
@@ -1743,4 +1739,18 @@
<string name="time_picker_prompt_label" msgid="7588093983899966783">"Introduceți ora"</string>
<string name="time_picker_text_input_mode_description" msgid="4148166758173708199">"Pentru a introduce ora, comutați la modul de introducere a textului."</string>
<string name="time_picker_radial_mode_description" msgid="4953403779779557198">"Pentru a introduce ora, comutați la modul ceas."</string>
+ <!-- no translation found for autofill_save_title (7081244500504163245) -->
+ <skip />
+ <!-- no translation found for autofill_save_title_with_type (4977385733042555659) -->
+ <skip />
+ <!-- no translation found for autofill_save_yes (6398026094049005921) -->
+ <skip />
+ <!-- no translation found for autofill_save_no (2625132258725581787) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_password (5288448918465971568) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_address (4936707762193009542) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_credit_card (7127694776265563071) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index 518023d..97c7b987 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -1207,14 +1207,10 @@
<string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Нажмите, чтобы выбрать язык и раскладку"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
- <!-- no translation found for alert_windows_notification_channel_name (7443890103456396837) -->
- <skip />
- <!-- no translation found for alert_windows_notification_title (5399998516035621282) -->
- <skip />
- <!-- no translation found for alert_windows_notification_message (2456738662997073459) -->
- <skip />
- <!-- no translation found for alert_windows_notification_turn_off_action (3367294525884949878) -->
- <skip />
+ <string name="alert_windows_notification_channel_name" msgid="7443890103456396837">"Интерфейс этих приложений показывается поверх других окон: <xliff:g id="NAME">%s</xliff:g>"</string>
+ <string name="alert_windows_notification_title" msgid="5399998516035621282">"<xliff:g id="NAME">%s</xliff:g>: показ поверх других окон"</string>
+ <string name="alert_windows_notification_message" msgid="2456738662997073459">"Некоторые элементы интерфейса этого приложения могут всегда находиться поверх других окон. Если функция работает некорректно, отключите ее."</string>
+ <string name="alert_windows_notification_turn_off_action" msgid="3367294525884949878">"ОТКЛЮЧИТЬ"</string>
<string name="ext_media_checking_notification_title" msgid="5734005953288045806">"Подготовка карты \"<xliff:g id="NAME">%s</xliff:g>\"…"</string>
<string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Поиск ошибок"</string>
<string name="ext_media_new_notification_message" msgid="7589986898808506239">"Обнаружена новая карта \"<xliff:g id="NAME">%s</xliff:g>\""</string>
@@ -1774,4 +1770,18 @@
<string name="time_picker_prompt_label" msgid="7588093983899966783">"Введите время"</string>
<string name="time_picker_text_input_mode_description" msgid="4148166758173708199">"Чтобы ввести время, перейдите в режим ввода текста."</string>
<string name="time_picker_radial_mode_description" msgid="4953403779779557198">"Чтобы ввести время, перейдите в режим часов."</string>
+ <!-- no translation found for autofill_save_title (7081244500504163245) -->
+ <skip />
+ <!-- no translation found for autofill_save_title_with_type (4977385733042555659) -->
+ <skip />
+ <!-- no translation found for autofill_save_yes (6398026094049005921) -->
+ <skip />
+ <!-- no translation found for autofill_save_no (2625132258725581787) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_password (5288448918465971568) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_address (4936707762193009542) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_credit_card (7127694776265563071) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-si/strings.xml b/core/res/res/values-si/strings.xml
index a8f6713..ff0c7d5 100644
--- a/core/res/res/values-si/strings.xml
+++ b/core/res/res/values-si/strings.xml
@@ -1169,14 +1169,10 @@
<string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"භාෂාව හා පිරිසැලසුම තේරීමට තට්ටු කරන්න"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
- <!-- no translation found for alert_windows_notification_channel_name (7443890103456396837) -->
- <skip />
- <!-- no translation found for alert_windows_notification_title (5399998516035621282) -->
- <skip />
- <!-- no translation found for alert_windows_notification_message (2456738662997073459) -->
- <skip />
- <!-- no translation found for alert_windows_notification_turn_off_action (3367294525884949878) -->
- <skip />
+ <string name="alert_windows_notification_channel_name" msgid="7443890103456396837">"අනෙක් යෙදුම්වලට උඩින් <xliff:g id="NAME">%s</xliff:g> අදින්න"</string>
+ <string name="alert_windows_notification_title" msgid="5399998516035621282">"<xliff:g id="NAME">%s</xliff:g> යෙදුම ඉහළින්ම සංදර්ශනය වේ."</string>
+ <string name="alert_windows_notification_message" msgid="2456738662997073459">"මෙම යෙදුමෙහි කොටස් සැම විටම දෘශ්යමානව පවතිනු ඇත. මෙම විශේෂාංගය නිවැරදිව ක්රියා නොකරන්නේ නම්, එය ක්රියාවිරහිත කරන්න."</string>
+ <string name="alert_windows_notification_turn_off_action" msgid="3367294525884949878">"ක්රියා විරහිත කරන්න"</string>
<string name="ext_media_checking_notification_title" msgid="5734005953288045806">"<xliff:g id="NAME">%s</xliff:g> සූදානම් කරමින්"</string>
<string name="ext_media_checking_notification_message" msgid="4747432538578886744">"වැරදි සඳහා පරීක්ෂා කරමින්"</string>
<string name="ext_media_new_notification_message" msgid="7589986898808506239">"නව <xliff:g id="NAME">%s</xliff:g> අනාවරණය කරන ලදි"</string>
@@ -1714,4 +1710,18 @@
<string name="time_picker_prompt_label" msgid="7588093983899966783">"වේලාව ටයිප් කරන්න"</string>
<string name="time_picker_text_input_mode_description" msgid="4148166758173708199">"වේලා ආදානය සඳහා ආදාන ප්රකාරය වෙත මාරු වෙන්න."</string>
<string name="time_picker_radial_mode_description" msgid="4953403779779557198">"වේලා ආදානය සඳහා ඔරලෝසු ප්රකාරය වෙත මාරු වෙන්න."</string>
+ <!-- no translation found for autofill_save_title (7081244500504163245) -->
+ <skip />
+ <!-- no translation found for autofill_save_title_with_type (4977385733042555659) -->
+ <skip />
+ <!-- no translation found for autofill_save_yes (6398026094049005921) -->
+ <skip />
+ <!-- no translation found for autofill_save_no (2625132258725581787) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_password (5288448918465971568) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_address (4936707762193009542) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_credit_card (7127694776265563071) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
index 20fcda5..660a256 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -1207,14 +1207,10 @@
<string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Klepnutím vyberte jazyk a rozloženie"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" AÁÄBCČDĎDZDŽEÉFGHCHIÍJKLĽMNŇOÓÔPRŔSŠTŤUÚVWXYÝZŽ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
- <!-- no translation found for alert_windows_notification_channel_name (7443890103456396837) -->
- <skip />
- <!-- no translation found for alert_windows_notification_title (5399998516035621282) -->
- <skip />
- <!-- no translation found for alert_windows_notification_message (2456738662997073459) -->
- <skip />
- <!-- no translation found for alert_windows_notification_turn_off_action (3367294525884949878) -->
- <skip />
+ <string name="alert_windows_notification_channel_name" msgid="7443890103456396837">"Aplikácia <xliff:g id="NAME">%s</xliff:g> sa vykreslí nad ostatnými aplikáciami"</string>
+ <string name="alert_windows_notification_title" msgid="5399998516035621282">"Apl. <xliff:g id="NAME">%s</xliff:g> sa zobrazuje navrchu."</string>
+ <string name="alert_windows_notification_message" msgid="2456738662997073459">"Časti tejto aplikácie môžu zostať neustále viditeľné. Ak táto funkcia nepracuje správne, vypnite ju."</string>
+ <string name="alert_windows_notification_turn_off_action" msgid="3367294525884949878">"VYPNÚŤ"</string>
<string name="ext_media_checking_notification_title" msgid="5734005953288045806">"Pripravuje sa úložisko <xliff:g id="NAME">%s</xliff:g>"</string>
<string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Prebieha kontrola chýb"</string>
<string name="ext_media_new_notification_message" msgid="7589986898808506239">"Bolo zistené nové úložisko <xliff:g id="NAME">%s</xliff:g>"</string>
@@ -1774,4 +1770,18 @@
<string name="time_picker_prompt_label" msgid="7588093983899966783">"Zadajte čas"</string>
<string name="time_picker_text_input_mode_description" msgid="4148166758173708199">"Ak chcete zadať čas, prepnite na textový režim vstupu"</string>
<string name="time_picker_radial_mode_description" msgid="4953403779779557198">"Ak chcete zadať čas, prepnite na režim hodín."</string>
+ <!-- no translation found for autofill_save_title (7081244500504163245) -->
+ <skip />
+ <!-- no translation found for autofill_save_title_with_type (4977385733042555659) -->
+ <skip />
+ <!-- no translation found for autofill_save_yes (6398026094049005921) -->
+ <skip />
+ <!-- no translation found for autofill_save_no (2625132258725581787) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_password (5288448918465971568) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_address (4936707762193009542) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_credit_card (7127694776265563071) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
index eca5c21..0abd212 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -1207,14 +1207,10 @@
<string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Dotaknite se, če želite izbrati jezik in postavitev."</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
- <!-- no translation found for alert_windows_notification_channel_name (7443890103456396837) -->
- <skip />
- <!-- no translation found for alert_windows_notification_title (5399998516035621282) -->
- <skip />
- <!-- no translation found for alert_windows_notification_message (2456738662997073459) -->
- <skip />
- <!-- no translation found for alert_windows_notification_turn_off_action (3367294525884949878) -->
- <skip />
+ <string name="alert_windows_notification_channel_name" msgid="7443890103456396837">"Aplikacija <xliff:g id="NAME">%s</xliff:g> riše čez druge aplikacije"</string>
+ <string name="alert_windows_notification_title" msgid="5399998516035621282">"Apl. <xliff:g id="NAME">%s</xliff:g> se prikazuje čez druge."</string>
+ <string name="alert_windows_notification_message" msgid="2456738662997073459">"Deli te aplikacije lahko ostanejo vseskozi vidni. Če ta funkcija ne deluje pravilno, jo izklopite."</string>
+ <string name="alert_windows_notification_turn_off_action" msgid="3367294525884949878">"IZKLOP"</string>
<string name="ext_media_checking_notification_title" msgid="5734005953288045806">"Pripravljanje shrambe <xliff:g id="NAME">%s</xliff:g>"</string>
<string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Iskanje napak"</string>
<string name="ext_media_new_notification_message" msgid="7589986898808506239">"Zaznana je bila nova shramba <xliff:g id="NAME">%s</xliff:g>"</string>
@@ -1774,4 +1770,18 @@
<string name="time_picker_prompt_label" msgid="7588093983899966783">"Vnesite uro"</string>
<string name="time_picker_text_input_mode_description" msgid="4148166758173708199">"Preklopite na način za vnašanje besedila, da vnesete čas."</string>
<string name="time_picker_radial_mode_description" msgid="4953403779779557198">"Preklopite na način ure, da vnesete čas."</string>
+ <!-- no translation found for autofill_save_title (7081244500504163245) -->
+ <skip />
+ <!-- no translation found for autofill_save_title_with_type (4977385733042555659) -->
+ <skip />
+ <!-- no translation found for autofill_save_yes (6398026094049005921) -->
+ <skip />
+ <!-- no translation found for autofill_save_no (2625132258725581787) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_password (5288448918465971568) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_address (4936707762193009542) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_credit_card (7127694776265563071) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-sq/strings.xml b/core/res/res/values-sq/strings.xml
index 25905d5..cc740a6 100644
--- a/core/res/res/values-sq/strings.xml
+++ b/core/res/res/values-sq/strings.xml
@@ -1168,14 +1168,10 @@
<string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Trokit për të zgjedhur gjuhën dhe strukturën"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
- <!-- no translation found for alert_windows_notification_channel_name (7443890103456396837) -->
- <skip />
- <!-- no translation found for alert_windows_notification_title (5399998516035621282) -->
- <skip />
- <!-- no translation found for alert_windows_notification_message (2456738662997073459) -->
- <skip />
- <!-- no translation found for alert_windows_notification_turn_off_action (3367294525884949878) -->
- <skip />
+ <string name="alert_windows_notification_channel_name" msgid="7443890103456396837">"<xliff:g id="NAME">%s</xliff:g> mbivendoset mbi aplikacionet e tjera"</string>
+ <string name="alert_windows_notification_title" msgid="5399998516035621282">"Aplikacioni <xliff:g id="NAME">%s</xliff:g> po shfaqet në krye."</string>
+ <string name="alert_windows_notification_message" msgid="2456738662997073459">"Disa pjesë të këtij aplikacioni mund të mbeten të dukshme gjatë të gjithë kohës. Nëse ky funksion nuk po funksionon si duhet, çaktivizoje atë."</string>
+ <string name="alert_windows_notification_turn_off_action" msgid="3367294525884949878">"ÇAKTIVIZO"</string>
<string name="ext_media_checking_notification_title" msgid="5734005953288045806">"Po përgatit <xliff:g id="NAME">%s</xliff:g>"</string>
<string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Po kontrollon për gabime"</string>
<string name="ext_media_new_notification_message" msgid="7589986898808506239">"U zbulua karta e re <xliff:g id="NAME">%s</xliff:g>"</string>
@@ -1713,4 +1709,18 @@
<string name="time_picker_prompt_label" msgid="7588093983899966783">"Shkruaj kohën"</string>
<string name="time_picker_text_input_mode_description" msgid="4148166758173708199">"Kalo te modaliteti i hyrjes së tekstit për hyrjen e kohës."</string>
<string name="time_picker_radial_mode_description" msgid="4953403779779557198">"Kalo te modaliteti i orës për hyrjen e kohës."</string>
+ <!-- no translation found for autofill_save_title (7081244500504163245) -->
+ <skip />
+ <!-- no translation found for autofill_save_title_with_type (4977385733042555659) -->
+ <skip />
+ <!-- no translation found for autofill_save_yes (6398026094049005921) -->
+ <skip />
+ <!-- no translation found for autofill_save_no (2625132258725581787) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_password (5288448918465971568) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_address (4936707762193009542) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_credit_card (7127694776265563071) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index e81f074..27f780a 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -1187,14 +1187,10 @@
<string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Додирните да бисте изабрали језик и распоред"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
- <!-- no translation found for alert_windows_notification_channel_name (7443890103456396837) -->
- <skip />
- <!-- no translation found for alert_windows_notification_title (5399998516035621282) -->
- <skip />
- <!-- no translation found for alert_windows_notification_message (2456738662997073459) -->
- <skip />
- <!-- no translation found for alert_windows_notification_turn_off_action (3367294525884949878) -->
- <skip />
+ <string name="alert_windows_notification_channel_name" msgid="7443890103456396837">"Апликација <xliff:g id="NAME">%s</xliff:g> се приказује преко других апликација"</string>
+ <string name="alert_windows_notification_title" msgid="5399998516035621282">"Апликација <xliff:g id="NAME">%s</xliff:g> се приказује преко."</string>
+ <string name="alert_windows_notification_message" msgid="2456738662997073459">"Делови ове апликације могу да остану видљиви у сваком тренутку. Ако ова функција не ради исправно, искључите је."</string>
+ <string name="alert_windows_notification_turn_off_action" msgid="3367294525884949878">"ИСКЉУЧИ"</string>
<string name="ext_media_checking_notification_title" msgid="5734005953288045806">"<xliff:g id="NAME">%s</xliff:g> се припрема"</string>
<string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Проверава се да ли постоје грешке"</string>
<string name="ext_media_new_notification_message" msgid="7589986898808506239">"Нови уређај <xliff:g id="NAME">%s</xliff:g> је откривен"</string>
@@ -1743,4 +1739,18 @@
<string name="time_picker_prompt_label" msgid="7588093983899966783">"Унесите време"</string>
<string name="time_picker_text_input_mode_description" msgid="4148166758173708199">"Пређите у режим уноса текста ради уноса времена."</string>
<string name="time_picker_radial_mode_description" msgid="4953403779779557198">"Пређите у режим сата ради уноса времена."</string>
+ <!-- no translation found for autofill_save_title (7081244500504163245) -->
+ <skip />
+ <!-- no translation found for autofill_save_title_with_type (4977385733042555659) -->
+ <skip />
+ <!-- no translation found for autofill_save_yes (6398026094049005921) -->
+ <skip />
+ <!-- no translation found for autofill_save_no (2625132258725581787) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_password (5288448918465971568) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_address (4936707762193009542) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_credit_card (7127694776265563071) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index 4562231..7410322 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -1167,14 +1167,10 @@
<string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Tryck om du vill välja språk och layout"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
- <!-- no translation found for alert_windows_notification_channel_name (7443890103456396837) -->
- <skip />
- <!-- no translation found for alert_windows_notification_title (5399998516035621282) -->
- <skip />
- <!-- no translation found for alert_windows_notification_message (2456738662997073459) -->
- <skip />
- <!-- no translation found for alert_windows_notification_turn_off_action (3367294525884949878) -->
- <skip />
+ <string name="alert_windows_notification_channel_name" msgid="7443890103456396837">"<xliff:g id="NAME">%s</xliff:g> gör överlagringar på andra appar"</string>
+ <string name="alert_windows_notification_title" msgid="5399998516035621282">"Appen <xliff:g id="NAME">%s</xliff:g> visas ovanpå."</string>
+ <string name="alert_windows_notification_message" msgid="2456738662997073459">"Delar av den här appen kanske alltid är synliga. Inaktivera funktionen om den inte fungerar som den ska."</string>
+ <string name="alert_windows_notification_turn_off_action" msgid="3367294525884949878">"INAKTIVERA"</string>
<string name="ext_media_checking_notification_title" msgid="5734005953288045806">"Förbereder ditt <xliff:g id="NAME">%s</xliff:g>"</string>
<string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Söker efter fel"</string>
<string name="ext_media_new_notification_message" msgid="7589986898808506239">"Nytt <xliff:g id="NAME">%s</xliff:g> har hittats"</string>
@@ -1712,4 +1708,18 @@
<string name="time_picker_prompt_label" msgid="7588093983899966783">"Ange tid"</string>
<string name="time_picker_text_input_mode_description" msgid="4148166758173708199">"Byt till textinmatningsläget och ange tid."</string>
<string name="time_picker_radial_mode_description" msgid="4953403779779557198">"Byt till klockläget och ange tid."</string>
+ <!-- no translation found for autofill_save_title (7081244500504163245) -->
+ <skip />
+ <!-- no translation found for autofill_save_title_with_type (4977385733042555659) -->
+ <skip />
+ <!-- no translation found for autofill_save_yes (6398026094049005921) -->
+ <skip />
+ <!-- no translation found for autofill_save_no (2625132258725581787) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_password (5288448918465971568) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_address (4936707762193009542) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_credit_card (7127694776265563071) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml
index a85d1dc..f266496 100644
--- a/core/res/res/values-sw/strings.xml
+++ b/core/res/res/values-sw/strings.xml
@@ -1165,14 +1165,10 @@
<string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Gonga ili uchague lugha na muundo"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
- <!-- no translation found for alert_windows_notification_channel_name (7443890103456396837) -->
- <skip />
- <!-- no translation found for alert_windows_notification_title (5399998516035621282) -->
- <skip />
- <!-- no translation found for alert_windows_notification_message (2456738662997073459) -->
- <skip />
- <!-- no translation found for alert_windows_notification_turn_off_action (3367294525884949878) -->
- <skip />
+ <string name="alert_windows_notification_channel_name" msgid="7443890103456396837">"<xliff:g id="NAME">%s</xliff:g> huchomoza kwenye programu zingine"</string>
+ <string name="alert_windows_notification_title" msgid="5399998516035621282">"Programu ya <xliff:g id="NAME">%s</xliff:g> inaonekana juu ya zingine."</string>
+ <string name="alert_windows_notification_message" msgid="2456738662997073459">"Huenda sehemu za programu hii zikaendelea kuonekana kila wakati. Zima kipengele hiki kama hakifanyi kazi vizuri."</string>
+ <string name="alert_windows_notification_turn_off_action" msgid="3367294525884949878">"ZIMA"</string>
<string name="ext_media_checking_notification_title" msgid="5734005953288045806">"Inaandaa <xliff:g id="NAME">%s</xliff:g>"</string>
<string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Inakagua hitilafu"</string>
<string name="ext_media_new_notification_message" msgid="7589986898808506239">"<xliff:g id="NAME">%s</xliff:g> mpya imegunduliwa"</string>
@@ -1710,4 +1706,18 @@
<string name="time_picker_prompt_label" msgid="7588093983899966783">"Andika wakati"</string>
<string name="time_picker_text_input_mode_description" msgid="4148166758173708199">"Badilisha iwe katika hali ya maandishi wakati wa kuweka muda."</string>
<string name="time_picker_radial_mode_description" msgid="4953403779779557198">"Badilisha umbo liwe la saa ya mishale wakati wa kuweka muda."</string>
+ <!-- no translation found for autofill_save_title (7081244500504163245) -->
+ <skip />
+ <!-- no translation found for autofill_save_title_with_type (4977385733042555659) -->
+ <skip />
+ <!-- no translation found for autofill_save_yes (6398026094049005921) -->
+ <skip />
+ <!-- no translation found for autofill_save_no (2625132258725581787) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_password (5288448918465971568) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_address (4936707762193009542) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_credit_card (7127694776265563071) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-ta/strings.xml b/core/res/res/values-ta/strings.xml
index 4c97780..7ab8c79 100644
--- a/core/res/res/values-ta/strings.xml
+++ b/core/res/res/values-ta/strings.xml
@@ -1168,14 +1168,10 @@
<string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"மொழியையும் தளவமைப்பையும் தேர்ந்தெடுக்க, தட்டவும்"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
- <!-- no translation found for alert_windows_notification_channel_name (7443890103456396837) -->
- <skip />
- <!-- no translation found for alert_windows_notification_title (5399998516035621282) -->
- <skip />
- <!-- no translation found for alert_windows_notification_message (2456738662997073459) -->
- <skip />
- <!-- no translation found for alert_windows_notification_turn_off_action (3367294525884949878) -->
- <skip />
+ <string name="alert_windows_notification_channel_name" msgid="7443890103456396837">"பிற பயன்பாடுகளின் மேல் <xliff:g id="NAME">%s</xliff:g> செயல்படும்"</string>
+ <string name="alert_windows_notification_title" msgid="5399998516035621282">"பிற பயன்பாடுகளின் மேலே <xliff:g id="NAME">%s</xliff:g> பயன்பாடு காட்டப்படுகிறது."</string>
+ <string name="alert_windows_notification_message" msgid="2456738662997073459">"இந்தப் பயன்பாட்டின் பகுதிகள், எல்லா நேரமும் காட்டப்படக்கூடும். இந்த அம்சம் சரியாகச் செயல்படவில்லை எனில், அதை முடக்கவும்."</string>
+ <string name="alert_windows_notification_turn_off_action" msgid="3367294525884949878">"முடக்கு"</string>
<string name="ext_media_checking_notification_title" msgid="5734005953288045806">"<xliff:g id="NAME">%s</xliff:g> தயாராகிறது"</string>
<string name="ext_media_checking_notification_message" msgid="4747432538578886744">"பிழைகள் உள்ளதா எனப் பார்க்கிறது"</string>
<string name="ext_media_new_notification_message" msgid="7589986898808506239">"புதிய <xliff:g id="NAME">%s</xliff:g> கண்டறியப்பட்டது"</string>
@@ -1713,4 +1709,18 @@
<string name="time_picker_prompt_label" msgid="7588093983899966783">"நேரத்தை உள்ளிடவும்"</string>
<string name="time_picker_text_input_mode_description" msgid="4148166758173708199">"உரை உள்ளீட்டிற்காக, கடிகாரப் பயன்முறைக்கு மாற்றும்."</string>
<string name="time_picker_radial_mode_description" msgid="4953403779779557198">"நேர உள்ளீட்டிற்காக, கடிகாரப் பயன்முறைக்கு மாற்றும்."</string>
+ <!-- no translation found for autofill_save_title (7081244500504163245) -->
+ <skip />
+ <!-- no translation found for autofill_save_title_with_type (4977385733042555659) -->
+ <skip />
+ <!-- no translation found for autofill_save_yes (6398026094049005921) -->
+ <skip />
+ <!-- no translation found for autofill_save_no (2625132258725581787) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_password (5288448918465971568) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_address (4936707762193009542) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_credit_card (7127694776265563071) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-te/strings.xml b/core/res/res/values-te/strings.xml
index 090b43c..905ccbe 100644
--- a/core/res/res/values-te/strings.xml
+++ b/core/res/res/values-te/strings.xml
@@ -1168,14 +1168,10 @@
<string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"భాష మరియు లేఅవుట్ను ఎంచుకోవడానికి నొక్కండి"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
- <!-- no translation found for alert_windows_notification_channel_name (7443890103456396837) -->
- <skip />
- <!-- no translation found for alert_windows_notification_title (5399998516035621282) -->
- <skip />
- <!-- no translation found for alert_windows_notification_message (2456738662997073459) -->
- <skip />
- <!-- no translation found for alert_windows_notification_turn_off_action (3367294525884949878) -->
- <skip />
+ <string name="alert_windows_notification_channel_name" msgid="7443890103456396837">"<xliff:g id="NAME">%s</xliff:g>ని ఇతర అనువర్తనాలలో చూపండి"</string>
+ <string name="alert_windows_notification_title" msgid="5399998516035621282">"ఎగువన <xliff:g id="NAME">%s</xliff:g> అనువర్తనం కనిపిస్తోంది."</string>
+ <string name="alert_windows_notification_message" msgid="2456738662997073459">"ఈ అనువర్తనంలోని భాగాలు అన్ని సమయాల్లో కనిపిస్తూ ఉండవచ్చు. ఈ లక్షణం సరిగ్గా పని చేయకపోతే, దీన్ని ఆఫ్ చేయండి."</string>
+ <string name="alert_windows_notification_turn_off_action" msgid="3367294525884949878">"ఆఫ్ చేయి"</string>
<string name="ext_media_checking_notification_title" msgid="5734005953288045806">"<xliff:g id="NAME">%s</xliff:g>ని సిద్ధం చేస్తోంది"</string>
<string name="ext_media_checking_notification_message" msgid="4747432538578886744">"లోపాల కోసం తనిఖీ చేస్తోంది"</string>
<string name="ext_media_new_notification_message" msgid="7589986898808506239">"కొత్త <xliff:g id="NAME">%s</xliff:g> గుర్తించబడింది"</string>
@@ -1713,4 +1709,18 @@
<string name="time_picker_prompt_label" msgid="7588093983899966783">"సమయంలో టైప్ చేయండి"</string>
<string name="time_picker_text_input_mode_description" msgid="4148166758173708199">"సమయాన్ని నమోదు చేయడం కోసం వచన నమోదు మోడ్కి మారండి."</string>
<string name="time_picker_radial_mode_description" msgid="4953403779779557198">"సమయాన్ని నమోదు చేయడం కోసం గడియారం మోడ్కు మారండి."</string>
+ <!-- no translation found for autofill_save_title (7081244500504163245) -->
+ <skip />
+ <!-- no translation found for autofill_save_title_with_type (4977385733042555659) -->
+ <skip />
+ <!-- no translation found for autofill_save_yes (6398026094049005921) -->
+ <skip />
+ <!-- no translation found for autofill_save_no (2625132258725581787) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_password (5288448918465971568) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_address (4936707762193009542) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_credit_card (7127694776265563071) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index 992944a..bb893fb 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -322,8 +322,8 @@
<string name="permdesc_systemAlertWindow" msgid="2393776099672266188">"แอปนี้สามารถปรากฏเหนือแอปอื่นๆ หรือส่วนอื่นของหน้าจอ ซึ่งอาจรบกวนการใช้งานตามปกติของแอปและทำให้ลักษณะการแสดงแอปอื่นๆ เปลี่ยนไป"</string>
<string name="permlab_runInBackground" msgid="7365290743781858803">"ทำงานในพื้นหลัง"</string>
<string name="permdesc_runInBackground" msgid="7370142232209999824">"แอปนี้สามารถทำงานในพื้นหลัง ซึ่งอาจทำให้แบตเตอรี่หมดเร็วขึ้น"</string>
- <string name="permlab_useDataInBackground" msgid="8694951340794341809">"ใช้เน็ตมือถือในพื้นหลัง"</string>
- <string name="permdesc_useDataInBackground" msgid="6049514223791806027">"แอปนี้สามารถใช้เน็ตมือถือในพื้นหลัง ซึ่งอาจเพิ่มปริมาณการใช้อินเทอร์เน็ต"</string>
+ <string name="permlab_useDataInBackground" msgid="8694951340794341809">"ใช้เน็ตในพื้นหลัง"</string>
+ <string name="permdesc_useDataInBackground" msgid="6049514223791806027">"แอปนี้สามารถใช้เน็ตในพื้นหลัง ซึ่งอาจเพิ่มปริมาณการใช้อินเทอร์เน็ต"</string>
<string name="permlab_persistentActivity" msgid="8841113627955563938">"ทำให้แอปพลิเคชันทำงานเสมอ"</string>
<string name="permdesc_persistentActivity" product="tablet" msgid="8525189272329086137">"อนุญาตให้แอปพลิเคชันทำให้ส่วนหนึ่งของตัวเองคงอยู่ถาวรในหน่วยความจำ ซึ่งจะจำกัดพื้นที่หน่วยความจำที่ใช้งานได้ของแอปพลิเคชันอื่นๆ และทำให้แท็บเล็ตทำงานช้าลง"</string>
<string name="permdesc_persistentActivity" product="tv" msgid="5086862529499103587">"อนุญาตให้แอปทำให้บางส่วนของแอปนั้นอยู่ในหน่วยความจำเสมอ ซึ่งอาจจำกัดพื้นที่หน่วยความจำสำหรับแอปอื่นและทำให้ทีวีช้าลง"</string>
@@ -1167,14 +1167,10 @@
<string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"แตะเพื่อเลือกภาษาและรูปแบบ"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" กขฃคฅฆงจฉชซฌญฎฏฐฑฒณดตถทธนบปผฝพฟภมยรลวศษสหฬอฮ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" กขฃคฅฆงจฉชซฌญฎฏฐฑฒณดตถทธนบปผฝพฟภมยรลวศษสหฬอฮ"</string>
- <!-- no translation found for alert_windows_notification_channel_name (7443890103456396837) -->
- <skip />
- <!-- no translation found for alert_windows_notification_title (5399998516035621282) -->
- <skip />
- <!-- no translation found for alert_windows_notification_message (2456738662997073459) -->
- <skip />
- <!-- no translation found for alert_windows_notification_turn_off_action (3367294525884949878) -->
- <skip />
+ <string name="alert_windows_notification_channel_name" msgid="7443890103456396837">"<xliff:g id="NAME">%s</xliff:g> แสดงทับแอปอื่น"</string>
+ <string name="alert_windows_notification_title" msgid="5399998516035621282">"แอป <xliff:g id="NAME">%s</xliff:g> แสดงอยู่ด้านบนสุด"</string>
+ <string name="alert_windows_notification_message" msgid="2456738662997073459">"ส่วนต่างๆ ของแอปนี้อาจปรากฏอยู่ตลอดเวลา หากคุณลักษณะนี้ไม่ทำงานอย่างถูกต้อง ให้ปิดแอป"</string>
+ <string name="alert_windows_notification_turn_off_action" msgid="3367294525884949878">"ปิด"</string>
<string name="ext_media_checking_notification_title" msgid="5734005953288045806">"กำลังเตรียม <xliff:g id="NAME">%s</xliff:g>"</string>
<string name="ext_media_checking_notification_message" msgid="4747432538578886744">"กำลังตรวจหาข้อผิดพลาด"</string>
<string name="ext_media_new_notification_message" msgid="7589986898808506239">"ตรวจพบ <xliff:g id="NAME">%s</xliff:g> ใหม่"</string>
@@ -1712,4 +1708,18 @@
<string name="time_picker_prompt_label" msgid="7588093983899966783">"พิมพ์เวลา"</string>
<string name="time_picker_text_input_mode_description" msgid="4148166758173708199">"สลับไปโหมดป้อนข้อความเพื่อป้อนเวลา"</string>
<string name="time_picker_radial_mode_description" msgid="4953403779779557198">"สลับไปโหมดนาฬิกาเพื่อป้อนเวลา"</string>
+ <!-- no translation found for autofill_save_title (7081244500504163245) -->
+ <skip />
+ <!-- no translation found for autofill_save_title_with_type (4977385733042555659) -->
+ <skip />
+ <!-- no translation found for autofill_save_yes (6398026094049005921) -->
+ <skip />
+ <!-- no translation found for autofill_save_no (2625132258725581787) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_password (5288448918465971568) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_address (4936707762193009542) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_credit_card (7127694776265563071) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml
index 4ec0d13..05ae6bf 100644
--- a/core/res/res/values-tl/strings.xml
+++ b/core/res/res/values-tl/strings.xml
@@ -1167,14 +1167,10 @@
<string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"I-tap upang pumili ng wika at layout"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
- <!-- no translation found for alert_windows_notification_channel_name (7443890103456396837) -->
- <skip />
- <!-- no translation found for alert_windows_notification_title (5399998516035621282) -->
- <skip />
- <!-- no translation found for alert_windows_notification_message (2456738662997073459) -->
- <skip />
- <!-- no translation found for alert_windows_notification_turn_off_action (3367294525884949878) -->
- <skip />
+ <string name="alert_windows_notification_channel_name" msgid="7443890103456396837">"I-draw over ang <xliff:g id="NAME">%s</xliff:g> sa iba pang app"</string>
+ <string name="alert_windows_notification_title" msgid="5399998516035621282">"Ipinapakita ang <xliff:g id="NAME">%s</xliff:g> app sa itaas."</string>
+ <string name="alert_windows_notification_message" msgid="2456738662997073459">"Maaaring manatiling nakikita ang mga bahagi ng app na ito sa lahat ng oras. Kung hindi gumagana nang tama ang feature na ito, i-off ito."</string>
+ <string name="alert_windows_notification_turn_off_action" msgid="3367294525884949878">"I-OFF"</string>
<string name="ext_media_checking_notification_title" msgid="5734005953288045806">"Inihahanda ang <xliff:g id="NAME">%s</xliff:g>"</string>
<string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Sinusuri para sa mga error"</string>
<string name="ext_media_new_notification_message" msgid="7589986898808506239">"Na-detect ang bagong <xliff:g id="NAME">%s</xliff:g>"</string>
@@ -1712,4 +1708,18 @@
<string name="time_picker_prompt_label" msgid="7588093983899966783">"I-type ang oras"</string>
<string name="time_picker_text_input_mode_description" msgid="4148166758173708199">"Lumipat sa pamamaraan ng pag-input ng text para sa input na oras."</string>
<string name="time_picker_radial_mode_description" msgid="4953403779779557198">"Lumipat sa mode ng orasan para sa input na oras."</string>
+ <!-- no translation found for autofill_save_title (7081244500504163245) -->
+ <skip />
+ <!-- no translation found for autofill_save_title_with_type (4977385733042555659) -->
+ <skip />
+ <!-- no translation found for autofill_save_yes (6398026094049005921) -->
+ <skip />
+ <!-- no translation found for autofill_save_no (2625132258725581787) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_password (5288448918465971568) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_address (4936707762193009542) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_credit_card (7127694776265563071) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index f9cd837..b56d466 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -1167,14 +1167,10 @@
<string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Dili ve düzeni seçmek için hafifçe dokunun"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
- <!-- no translation found for alert_windows_notification_channel_name (7443890103456396837) -->
- <skip />
- <!-- no translation found for alert_windows_notification_title (5399998516035621282) -->
- <skip />
- <!-- no translation found for alert_windows_notification_message (2456738662997073459) -->
- <skip />
- <!-- no translation found for alert_windows_notification_turn_off_action (3367294525884949878) -->
- <skip />
+ <string name="alert_windows_notification_channel_name" msgid="7443890103456396837">"<xliff:g id="NAME">%s</xliff:g> diğer uygulamaların üzerinde görüntüleniyor"</string>
+ <string name="alert_windows_notification_title" msgid="5399998516035621282">"<xliff:g id="NAME">%s</xliff:g> üstte gösteriliyor."</string>
+ <string name="alert_windows_notification_message" msgid="2456738662997073459">"Bu uygulamanın bazı bölümleri her zaman görünür durumda kalabilir. Bu özellik düzgün çalışmıyorsa kapatın."</string>
+ <string name="alert_windows_notification_turn_off_action" msgid="3367294525884949878">"KAPAT"</string>
<string name="ext_media_checking_notification_title" msgid="5734005953288045806">"<xliff:g id="NAME">%s</xliff:g> hazırlanıyor"</string>
<string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Hatalar denetleniyor"</string>
<string name="ext_media_new_notification_message" msgid="7589986898808506239">"Yeni <xliff:g id="NAME">%s</xliff:g> algılandı"</string>
@@ -1712,4 +1708,18 @@
<string name="time_picker_prompt_label" msgid="7588093983899966783">"Zamanı yazın"</string>
<string name="time_picker_text_input_mode_description" msgid="4148166758173708199">"Zaman girişi için metin girişi moduna geçin."</string>
<string name="time_picker_radial_mode_description" msgid="4953403779779557198">"Zaman girişi için saat moduna geçin."</string>
+ <!-- no translation found for autofill_save_title (7081244500504163245) -->
+ <skip />
+ <!-- no translation found for autofill_save_title_with_type (4977385733042555659) -->
+ <skip />
+ <!-- no translation found for autofill_save_yes (6398026094049005921) -->
+ <skip />
+ <!-- no translation found for autofill_save_no (2625132258725581787) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_password (5288448918465971568) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_address (4936707762193009542) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_credit_card (7127694776265563071) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
index acf6614..e99d88b 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -1207,14 +1207,10 @@
<string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Торкніться, щоб вибрати мову та розкладку"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" АБВГҐДЕЄЖЗИІЇЙКЛМНОПРСТУФХЦЧШЩЬЮЯ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789АБВГҐДЕЄЖЗИІЇЙКЛМНОПРСТУФХЦЧШЩЬЮЯ"</string>
- <!-- no translation found for alert_windows_notification_channel_name (7443890103456396837) -->
- <skip />
- <!-- no translation found for alert_windows_notification_title (5399998516035621282) -->
- <skip />
- <!-- no translation found for alert_windows_notification_message (2456738662997073459) -->
- <skip />
- <!-- no translation found for alert_windows_notification_turn_off_action (3367294525884949878) -->
- <skip />
+ <string name="alert_windows_notification_channel_name" msgid="7443890103456396837">"<xliff:g id="NAME">%s</xliff:g> відображається поверх інших додатків"</string>
+ <string name="alert_windows_notification_title" msgid="5399998516035621282">"<xliff:g id="NAME">%s</xliff:g> відображається поверх."</string>
+ <string name="alert_windows_notification_message" msgid="2456738662997073459">"Частина цього додатка може постійно залишатися видимою. Якщо ця функція працює неправильно, вимкніть її."</string>
+ <string name="alert_windows_notification_turn_off_action" msgid="3367294525884949878">"ВИМКНУТИ"</string>
<string name="ext_media_checking_notification_title" msgid="5734005953288045806">"Підготовка пристрою пам’яті <xliff:g id="NAME">%s</xliff:g>"</string>
<string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Виявлення помилок"</string>
<string name="ext_media_new_notification_message" msgid="7589986898808506239">"Виявлено новий пристрій пам’яті (<xliff:g id="NAME">%s</xliff:g>)"</string>
@@ -1774,4 +1770,18 @@
<string name="time_picker_prompt_label" msgid="7588093983899966783">"Введіть час"</string>
<string name="time_picker_text_input_mode_description" msgid="4148166758173708199">"Перейти в текстовий режим, щоб ввести час."</string>
<string name="time_picker_radial_mode_description" msgid="4953403779779557198">"Перейти в режим годинника, щоб ввести час."</string>
+ <!-- no translation found for autofill_save_title (7081244500504163245) -->
+ <skip />
+ <!-- no translation found for autofill_save_title_with_type (4977385733042555659) -->
+ <skip />
+ <!-- no translation found for autofill_save_yes (6398026094049005921) -->
+ <skip />
+ <!-- no translation found for autofill_save_no (2625132258725581787) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_password (5288448918465971568) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_address (4936707762193009542) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_credit_card (7127694776265563071) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-ur/strings.xml b/core/res/res/values-ur/strings.xml
index 7e8b110..41c265d 100644
--- a/core/res/res/values-ur/strings.xml
+++ b/core/res/res/values-ur/strings.xml
@@ -1168,14 +1168,10 @@
<string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"زبان اور لے آؤٹ منتخب کرنے کیلئے تھپتھپائیں"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
- <!-- no translation found for alert_windows_notification_channel_name (7443890103456396837) -->
- <skip />
- <!-- no translation found for alert_windows_notification_title (5399998516035621282) -->
- <skip />
- <!-- no translation found for alert_windows_notification_message (2456738662997073459) -->
- <skip />
- <!-- no translation found for alert_windows_notification_turn_off_action (3367294525884949878) -->
- <skip />
+ <string name="alert_windows_notification_channel_name" msgid="7443890103456396837">"<xliff:g id="NAME">%s</xliff:g> کو دیگر ایپس پر ڈرا کریں"</string>
+ <string name="alert_windows_notification_title" msgid="5399998516035621282">"<xliff:g id="NAME">%s</xliff:g> ایپ اوپر ڈسپلے ہورہی ہے۔"</string>
+ <string name="alert_windows_notification_message" msgid="2456738662997073459">"ممکن ہے اس ایپ کے حصے ہر وقت مرئی رہیں۔ اگر یہ خصوصیت ٹھیک سے کام نہیں کررہی ہے، تو اسے آف کردیں۔"</string>
+ <string name="alert_windows_notification_turn_off_action" msgid="3367294525884949878">"آف کریں"</string>
<string name="ext_media_checking_notification_title" msgid="5734005953288045806">"<xliff:g id="NAME">%s</xliff:g> تیار کیا جا رہا ہے"</string>
<string name="ext_media_checking_notification_message" msgid="4747432538578886744">"خرابیوں کیلئے چیک کیا جا رہا ہے"</string>
<string name="ext_media_new_notification_message" msgid="7589986898808506239">"نئے <xliff:g id="NAME">%s</xliff:g> کا پتا چلا"</string>
@@ -1713,4 +1709,18 @@
<string name="time_picker_prompt_label" msgid="7588093983899966783">"وقت ٹائپ کریں"</string>
<string name="time_picker_text_input_mode_description" msgid="4148166758173708199">"وقت ان پٹ کے لیے ٹیکسٹ ان پٹ وضع پر سوئچ کریں۔"</string>
<string name="time_picker_radial_mode_description" msgid="4953403779779557198">"وقت ان پٹ کے لیے گھڑی وضع پر سوئچ کریں۔"</string>
+ <!-- no translation found for autofill_save_title (7081244500504163245) -->
+ <skip />
+ <!-- no translation found for autofill_save_title_with_type (4977385733042555659) -->
+ <skip />
+ <!-- no translation found for autofill_save_yes (6398026094049005921) -->
+ <skip />
+ <!-- no translation found for autofill_save_no (2625132258725581787) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_password (5288448918465971568) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_address (4936707762193009542) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_credit_card (7127694776265563071) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-uz/strings.xml b/core/res/res/values-uz/strings.xml
index 3210143..5309181 100644
--- a/core/res/res/values-uz/strings.xml
+++ b/core/res/res/values-uz/strings.xml
@@ -1168,14 +1168,10 @@
<string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Til va sxemani belgilash uchun bosing"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
- <!-- no translation found for alert_windows_notification_channel_name (7443890103456396837) -->
- <skip />
- <!-- no translation found for alert_windows_notification_title (5399998516035621282) -->
- <skip />
- <!-- no translation found for alert_windows_notification_message (2456738662997073459) -->
- <skip />
- <!-- no translation found for alert_windows_notification_turn_off_action (3367294525884949878) -->
- <skip />
+ <string name="alert_windows_notification_channel_name" msgid="7443890103456396837">"<xliff:g id="NAME">%s</xliff:g> boshqa ilovalar ustidan ochiladi"</string>
+ <string name="alert_windows_notification_title" msgid="5399998516035621282">"<xliff:g id="NAME">%s</xliff:g> eng tepada ochilgan."</string>
+ <string name="alert_windows_notification_message" msgid="2456738662997073459">"Bu ilovaning ba’zi qismlari har doim ko‘rinib qolishi mumkin. Agar bu funksiya to‘g‘ri ishlamasa, uni o‘chirib qo‘ying."</string>
+ <string name="alert_windows_notification_turn_off_action" msgid="3367294525884949878">"O‘CHIRIB QO‘YISH"</string>
<string name="ext_media_checking_notification_title" msgid="5734005953288045806">"<xliff:g id="NAME">%s</xliff:g> tayyorlanmoqda"</string>
<string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Xatolar qidirilmoqda"</string>
<string name="ext_media_new_notification_message" msgid="7589986898808506239">"Yangi <xliff:g id="NAME">%s</xliff:g> kartasi aniqlandi"</string>
@@ -1713,4 +1709,18 @@
<string name="time_picker_prompt_label" msgid="7588093983899966783">"Vaqtni kiriting"</string>
<string name="time_picker_text_input_mode_description" msgid="4148166758173708199">"Vaqtni kiritish uchun matn kiritish rejimiga o‘ting."</string>
<string name="time_picker_radial_mode_description" msgid="4953403779779557198">"Vaqtni kiritish uchun soat rejimiga o‘ting."</string>
+ <!-- no translation found for autofill_save_title (7081244500504163245) -->
+ <skip />
+ <!-- no translation found for autofill_save_title_with_type (4977385733042555659) -->
+ <skip />
+ <!-- no translation found for autofill_save_yes (6398026094049005921) -->
+ <skip />
+ <!-- no translation found for autofill_save_no (2625132258725581787) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_password (5288448918465971568) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_address (4936707762193009542) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_credit_card (7127694776265563071) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index 4ed7dc9..69e0ec3 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -1167,14 +1167,10 @@
<string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Nhấn để chọn ngôn ngữ và bố cục"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
- <!-- no translation found for alert_windows_notification_channel_name (7443890103456396837) -->
- <skip />
- <!-- no translation found for alert_windows_notification_title (5399998516035621282) -->
- <skip />
- <!-- no translation found for alert_windows_notification_message (2456738662997073459) -->
- <skip />
- <!-- no translation found for alert_windows_notification_turn_off_action (3367294525884949878) -->
- <skip />
+ <string name="alert_windows_notification_channel_name" msgid="7443890103456396837">"<xliff:g id="NAME">%s</xliff:g> vẽ lên các ứng dụng khác"</string>
+ <string name="alert_windows_notification_title" msgid="5399998516035621282">"Ứng dụng <xliff:g id="NAME">%s</xliff:g> hiển thị ở trên cùng."</string>
+ <string name="alert_windows_notification_message" msgid="2456738662997073459">"Các phần của ứng dụng này có thể vẫn hiển thị mọi lúc. Nếu tính năng này không hoạt động bình thường, hãy tắt tính năng này."</string>
+ <string name="alert_windows_notification_turn_off_action" msgid="3367294525884949878">"TẮT"</string>
<string name="ext_media_checking_notification_title" msgid="5734005953288045806">"Đang chuẩn bị <xliff:g id="NAME">%s</xliff:g>"</string>
<string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Đang kiểm tra lỗi"</string>
<string name="ext_media_new_notification_message" msgid="7589986898808506239">"Đã phát hiện <xliff:g id="NAME">%s</xliff:g> mới"</string>
@@ -1712,4 +1708,18 @@
<string name="time_picker_prompt_label" msgid="7588093983899966783">"Nhập thời gian"</string>
<string name="time_picker_text_input_mode_description" msgid="4148166758173708199">"Chuyển sang chế độ nhập văn bản để nhập thời gian."</string>
<string name="time_picker_radial_mode_description" msgid="4953403779779557198">"Chuyển sang chế độ đồng hồ để nhập thời gian."</string>
+ <!-- no translation found for autofill_save_title (7081244500504163245) -->
+ <skip />
+ <!-- no translation found for autofill_save_title_with_type (4977385733042555659) -->
+ <skip />
+ <!-- no translation found for autofill_save_yes (6398026094049005921) -->
+ <skip />
+ <!-- no translation found for autofill_save_no (2625132258725581787) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_password (5288448918465971568) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_address (4936707762193009542) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_credit_card (7127694776265563071) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index 1e71448..2236f1f 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -1167,14 +1167,10 @@
<string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"点按即可选择语言和布局"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
- <!-- no translation found for alert_windows_notification_channel_name (7443890103456396837) -->
- <skip />
- <!-- no translation found for alert_windows_notification_title (5399998516035621282) -->
- <skip />
- <!-- no translation found for alert_windows_notification_message (2456738662997073459) -->
- <skip />
- <!-- no translation found for alert_windows_notification_turn_off_action (3367294525884949878) -->
- <skip />
+ <string name="alert_windows_notification_channel_name" msgid="7443890103456396837">"<xliff:g id="NAME">%s</xliff:g>会在其他应用的上层显示内容"</string>
+ <string name="alert_windows_notification_title" msgid="5399998516035621282">"<xliff:g id="NAME">%s</xliff:g>应用目前显示在上层。"</string>
+ <string name="alert_windows_notification_message" msgid="2456738662997073459">"此应用的某些部分可能会一直保持可见状态。如果此功能未能正常运行,请将其关闭。"</string>
+ <string name="alert_windows_notification_turn_off_action" msgid="3367294525884949878">"关闭"</string>
<string name="ext_media_checking_notification_title" msgid="5734005953288045806">"正在准备<xliff:g id="NAME">%s</xliff:g>"</string>
<string name="ext_media_checking_notification_message" msgid="4747432538578886744">"检查是否有错误"</string>
<string name="ext_media_new_notification_message" msgid="7589986898808506239">"检测到新的<xliff:g id="NAME">%s</xliff:g>"</string>
@@ -1712,4 +1708,18 @@
<string name="time_picker_prompt_label" msgid="7588093983899966783">"请输入时间"</string>
<string name="time_picker_text_input_mode_description" msgid="4148166758173708199">"切换到文字输入模式来输入时间。"</string>
<string name="time_picker_radial_mode_description" msgid="4953403779779557198">"切换到时钟模式来输入时间。"</string>
+ <!-- no translation found for autofill_save_title (7081244500504163245) -->
+ <skip />
+ <!-- no translation found for autofill_save_title_with_type (4977385733042555659) -->
+ <skip />
+ <!-- no translation found for autofill_save_yes (6398026094049005921) -->
+ <skip />
+ <!-- no translation found for autofill_save_no (2625132258725581787) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_password (5288448918465971568) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_address (4936707762193009542) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_credit_card (7127694776265563071) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-zh-rHK/strings.xml b/core/res/res/values-zh-rHK/strings.xml
index b1273f4..db98761 100644
--- a/core/res/res/values-zh-rHK/strings.xml
+++ b/core/res/res/values-zh-rHK/strings.xml
@@ -1167,14 +1167,10 @@
<string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"輕按即可選取語言和鍵盤配置"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
- <!-- no translation found for alert_windows_notification_channel_name (7443890103456396837) -->
- <skip />
- <!-- no translation found for alert_windows_notification_title (5399998516035621282) -->
- <skip />
- <!-- no translation found for alert_windows_notification_message (2456738662997073459) -->
- <skip />
- <!-- no translation found for alert_windows_notification_turn_off_action (3367294525884949878) -->
- <skip />
+ <string name="alert_windows_notification_channel_name" msgid="7443890103456396837">"「<xliff:g id="NAME">%s</xliff:g>」會覆蓋其他應用程式"</string>
+ <string name="alert_windows_notification_title" msgid="5399998516035621282">"「<xliff:g id="NAME">%s</xliff:g>」應用程式目前在最上層顯示。"</string>
+ <string name="alert_windows_notification_message" msgid="2456738662997073459">"畫面上可能會一直保持顯示此應用程式的某些部分。如果此功能無法正常運作,請將其關閉。"</string>
+ <string name="alert_windows_notification_turn_off_action" msgid="3367294525884949878">"關閉"</string>
<string name="ext_media_checking_notification_title" msgid="5734005953288045806">"正在準備<xliff:g id="NAME">%s</xliff:g>"</string>
<string name="ext_media_checking_notification_message" msgid="4747432538578886744">"正在檢查錯誤"</string>
<string name="ext_media_new_notification_message" msgid="7589986898808506239">"已偵測到新<xliff:g id="NAME">%s</xliff:g>"</string>
@@ -1712,4 +1708,18 @@
<string name="time_picker_prompt_label" msgid="7588093983899966783">"輸入時間"</string>
<string name="time_picker_text_input_mode_description" msgid="4148166758173708199">"切換至文字輸入模式即可輸入時間。"</string>
<string name="time_picker_radial_mode_description" msgid="4953403779779557198">"切換至時鐘模式即可輸入時間。"</string>
+ <!-- no translation found for autofill_save_title (7081244500504163245) -->
+ <skip />
+ <!-- no translation found for autofill_save_title_with_type (4977385733042555659) -->
+ <skip />
+ <!-- no translation found for autofill_save_yes (6398026094049005921) -->
+ <skip />
+ <!-- no translation found for autofill_save_no (2625132258725581787) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_password (5288448918465971568) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_address (4936707762193009542) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_credit_card (7127694776265563071) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index b3b7e18..7f4c01b 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -321,9 +321,9 @@
<string name="permlab_systemAlertWindow" msgid="7238805243128138690">"這個應用程式可顯示在其他應用程式上方"</string>
<string name="permdesc_systemAlertWindow" msgid="2393776099672266188">"這個應用程式可顯示在其他應用程式上方或畫面中的其他位置。你可能會無法照常使用應用程式,且其他應用程式的顯示方式可能會受到影響。"</string>
<string name="permlab_runInBackground" msgid="7365290743781858803">"在背景執行"</string>
- <string name="permdesc_runInBackground" msgid="7370142232209999824">"這個應用程式可在背景執行,這樣可能會加快耗電速度。"</string>
+ <string name="permdesc_runInBackground" msgid="7370142232209999824">"這個應用程式可在背景執行,這樣可能導致耗電速度加快。"</string>
<string name="permlab_useDataInBackground" msgid="8694951340794341809">"在背景使用行動數據連線"</string>
- <string name="permdesc_useDataInBackground" msgid="6049514223791806027">"這個應用程式可在背景使用行動數據連線,這樣可能會增加數據用量。"</string>
+ <string name="permdesc_useDataInBackground" msgid="6049514223791806027">"這個應用程式可在背景使用行動數據連線,這樣可能導致數據用量增加。"</string>
<string name="permlab_persistentActivity" msgid="8841113627955563938">"一律執行應用程式"</string>
<string name="permdesc_persistentActivity" product="tablet" msgid="8525189272329086137">"允許應用程式的部分內容常駐在記憶體中。這項設定可能會限制其他應用程式可用的記憶體,並拖慢平板電腦運作速度。"</string>
<string name="permdesc_persistentActivity" product="tv" msgid="5086862529499103587">"允許應用程式的部分內容常駐在記憶體中。這項設定可能會限制其他應用程式可用的記憶體,造成電視的運作速度變慢。"</string>
@@ -1167,14 +1167,10 @@
<string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"輕觸即可選取語言和版面配置"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
- <!-- no translation found for alert_windows_notification_channel_name (7443890103456396837) -->
- <skip />
- <!-- no translation found for alert_windows_notification_title (5399998516035621282) -->
- <skip />
- <!-- no translation found for alert_windows_notification_message (2456738662997073459) -->
- <skip />
- <!-- no translation found for alert_windows_notification_turn_off_action (3367294525884949878) -->
- <skip />
+ <string name="alert_windows_notification_channel_name" msgid="7443890103456396837">"<xliff:g id="NAME">%s</xliff:g>會在其他應用程式上層繪製內容"</string>
+ <string name="alert_windows_notification_title" msgid="5399998516035621282">"<xliff:g id="NAME">%s</xliff:g>應用程式目前顯示在最上層。"</string>
+ <string name="alert_windows_notification_message" msgid="2456738662997073459">"這個應用程式的某些部分會一直保持顯示。如果這項功能未正常運作,請將它關閉。"</string>
+ <string name="alert_windows_notification_turn_off_action" msgid="3367294525884949878">"關閉"</string>
<string name="ext_media_checking_notification_title" msgid="5734005953288045806">"正在準備「<xliff:g id="NAME">%s</xliff:g>」"</string>
<string name="ext_media_checking_notification_message" msgid="4747432538578886744">"正在檢查錯誤"</string>
<string name="ext_media_new_notification_message" msgid="7589986898808506239">"偵測到新的「<xliff:g id="NAME">%s</xliff:g>」"</string>
@@ -1712,4 +1708,18 @@
<string name="time_picker_prompt_label" msgid="7588093983899966783">"輸入時間"</string>
<string name="time_picker_text_input_mode_description" msgid="4148166758173708199">"切換至文字輸入模式來輸入時間。"</string>
<string name="time_picker_radial_mode_description" msgid="4953403779779557198">"切換至時鐘模式來輸入時間。"</string>
+ <!-- no translation found for autofill_save_title (7081244500504163245) -->
+ <skip />
+ <!-- no translation found for autofill_save_title_with_type (4977385733042555659) -->
+ <skip />
+ <!-- no translation found for autofill_save_yes (6398026094049005921) -->
+ <skip />
+ <!-- no translation found for autofill_save_no (2625132258725581787) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_password (5288448918465971568) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_address (4936707762193009542) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_credit_card (7127694776265563071) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml
index 6a82ed5..dadd6c0 100644
--- a/core/res/res/values-zu/strings.xml
+++ b/core/res/res/values-zu/strings.xml
@@ -1167,14 +1167,10 @@
<string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Thepha ukuze ukhethe ulimi nesakhiwo"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
- <!-- no translation found for alert_windows_notification_channel_name (7443890103456396837) -->
- <skip />
- <!-- no translation found for alert_windows_notification_title (5399998516035621282) -->
- <skip />
- <!-- no translation found for alert_windows_notification_message (2456738662997073459) -->
- <skip />
- <!-- no translation found for alert_windows_notification_turn_off_action (3367294525884949878) -->
- <skip />
+ <string name="alert_windows_notification_channel_name" msgid="7443890103456396837">"I-<xliff:g id="NAME">%s</xliff:g> yokudweba ngaphezu kwezinye izinhlelo zokusebenza"</string>
+ <string name="alert_windows_notification_title" msgid="5399998516035621282">"Uhlelo lokusebenza lwe-<xliff:g id="NAME">%s</xliff:g> liboniswa ngaphezulu."</string>
+ <string name="alert_windows_notification_message" msgid="2456738662997073459">"Izingxenye zalolu hlelo lokusebenza zingahlala zibonakala ngazo zonke izikhathi. Uma lesi sici singasebenzi ngokufanelekile, sivale."</string>
+ <string name="alert_windows_notification_turn_off_action" msgid="3367294525884949878">"VALA"</string>
<string name="ext_media_checking_notification_title" msgid="5734005953288045806">"Ilungiselela i-<xliff:g id="NAME">%s</xliff:g>"</string>
<string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Ihlolela amaphutha"</string>
<string name="ext_media_new_notification_message" msgid="7589986898808506239">"I-<xliff:g id="NAME">%s</xliff:g> entsha itholiwe"</string>
@@ -1712,4 +1708,18 @@
<string name="time_picker_prompt_label" msgid="7588093983899966783">"Thayipha isikhathi"</string>
<string name="time_picker_text_input_mode_description" msgid="4148166758173708199">"Shintshela kumodi yokufaka umbhalo ngokufaka isikhathi."</string>
<string name="time_picker_radial_mode_description" msgid="4953403779779557198">"Shintshela kumodi yewashi ngokufakwa kwesikhathi."</string>
+ <!-- no translation found for autofill_save_title (7081244500504163245) -->
+ <skip />
+ <!-- no translation found for autofill_save_title_with_type (4977385733042555659) -->
+ <skip />
+ <!-- no translation found for autofill_save_yes (6398026094049005921) -->
+ <skip />
+ <!-- no translation found for autofill_save_no (2625132258725581787) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_password (5288448918465971568) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_address (4936707762193009542) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_credit_card (7127694776265563071) -->
+ <skip />
</resources>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 8031f19..e8169f8 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -66,6 +66,9 @@
<attr name="primaryContentAlpha" format="float" />
<!-- The alpha applied to the foreground color to create the secondary text color. -->
<attr name="secondaryContentAlpha" format="float" />
+ <!-- Color used for error states and things that need to be drawn to
+ the users attention.. -->
+ <attr name="colorError" format="reference|color" />
<!-- Default background dim amount when a menu, dialog, or something similar pops up. -->
<attr name="backgroundDimAmount" format="float" />
<!-- Control whether dimming behind the window is enabled. The default
@@ -135,9 +138,6 @@
<!-- Color of list item text in alert dialogs. -->
<attr name="textColorAlertDialogListItem" format="reference|color" />
- <!-- Text color for errors. -->
- <attr name="textColorError" format="reference|color" />
-
<!-- Search widget more corpus result item background. -->
<attr name="searchWidgetCorpusItemBackground" format="reference|color" />
@@ -3148,19 +3148,19 @@
If both layout_marginHorizontal and any of layout_marginLeft,
layout_marginRight, layout_marginStart, and layout_marginEnd are
also specified, the layout_marginHorizontal value will take precedence over the
- edge-specific values. Also, layout_margin will always take precendent over
+ edge-specific values. Also, layout_margin will always take precedence over
any of these values, including layout_marginHorizontal.
This space is outside this view's bounds.
Margin values should be positive.-->
<attr name="layout_marginHorizontal" format="dimension" />
- <!-- Specifies extra space on the tyop and bottom sides of this view.
+ <!-- Specifies extra space on the top and bottom sides of this view.
Specifying layout_marginVertical is equivalent to specifying
layout_marginTop and layout_marginBottom with that same value.
If both layout_marginVertical and either/both layout_marginTop and
layout_marginBottom are also specified, the layout_marginVertical value
will take precedence over the edge-specific values.
- Also, layout_margin will always take precendent over
- any of these values, including layout_marginHorizontal.
+ Also, layout_margin will always take precedence over
+ any of these values, including layout_marginVertical.
This space is outside this view's bounds.
Margin values should be positive.-->
<attr name="layout_marginVertical" format="dimension" />
@@ -4721,18 +4721,19 @@
</attr>
<!-- Specify the type of auto-size. Note that this feature is not supported by EditText,
works only for TextView -->
- <attr name="autoSizeText" format="enum">
+ <attr name="autoSizeTextType" format="enum">
<!-- No auto-sizing (default). -->
<enum name="none" value="0" />
- <!-- Uniform horizontal and vertical scaling. -->
+ <!-- Uniform horizontal and vertical text size scaling to fit within the
+ container -->
<enum name="uniform" value="1" />
</attr>
- <!-- Specify the auto-size step size if <code>autoSizeText</code> is set to
- <code>xy</code>. The default is 1px. Overwrites
+ <!-- Specify the auto-size step size if <code>autoSizeTextType</code> is set to
+ <code>uniform</code>. The default is 1px. Overwrites
<code>autoSizePresetSizes</code> if set. -->
<attr name="autoSizeStepGranularity" format="dimension" />
- <!-- Array of dimensions to be used in conjunction with
- <code>autoSizeText</code> set to <code>xy</code>. Overwrites
+ <!-- Resource array of dimensions to be used in conjunction with
+ <code>autoSizeTextType</code> set to <code>uniform</code>. Overrides
<code>autoSizeStepGranularity</code> if set. -->
<attr name="autoSizePresetSizes"/>
<!-- The minimum text size constraint to be used when auto-sizing text -->
@@ -8531,4 +8532,6 @@
<attr name="reverseLayout" format="boolean" />
<attr name="stackFromEnd" format="boolean" />
</declare-styleable>
+
+ <attr name="lockPatternStyle" format="reference" />
</resources>
diff --git a/core/res/res/values/colors.xml b/core/res/res/values/colors.xml
index b28c6f2..6015ed5 100644
--- a/core/res/res/values/colors.xml
+++ b/core/res/res/values/colors.xml
@@ -75,8 +75,6 @@
<drawable name="input_method_fullscreen_background">#fff9f9f9</drawable>
<color name="input_method_navigation_guard">#ff000000</color>
- <color name="system_error">#fff4511e</color> <!-- deep orange 600 -->
-
<!-- For date picker widget -->
<drawable name="selected_day_background">#ff0092f4</drawable>
@@ -88,7 +86,6 @@
<color name="perms_dangerous_grp_color">#33b5e5</color>
<color name="perms_dangerous_perm_color">#33b5e5</color>
<color name="shadow">#cc222222</color>
- <color name="perms_costs_money">#fff4511e</color>
<!-- For search-related UIs -->
<color name="search_url_text_normal">#7fa87f</color>
@@ -121,7 +118,6 @@
<!-- LockPatternView -->
<color name="lock_pattern_view_regular_color">#ffffffff</color>
<color name="lock_pattern_view_success_color">#ffffffff</color>
- <color name="lock_pattern_view_error_color">@color/system_error</color>
<!-- FaceLock -->
<color name="facelock_spotlight_mask">#CC000000</color>
@@ -156,7 +152,6 @@
<color name="accessibility_focus_highlight">#bf39b500</color>
<color name="system_notification_accent_color">#ff607D8B</color>
- <color name="battery_saver_mode_color">#fff4511e</color><!-- deep orange 600 -->
<!-- Default user icon colors -->
<color name="user_icon_1">#ff00bcd4</color><!-- cyan 500 -->
diff --git a/core/res/res/values/colors_material.xml b/core/res/res/values/colors_material.xml
index 0a24565..e0cc5b5 100644
--- a/core/res/res/values/colors_material.xml
+++ b/core/res/res/values/colors_material.xml
@@ -46,6 +46,7 @@
<color name="button_material_dark">#ff5a595b</color>
<color name="button_material_light">#ffd6d7d7</color>
+ <color name="error_color_material">#F4511E</color>
<color name="switch_thumb_normal_material_dark">#ffbdbdbd</color>
<color name="switch_thumb_normal_material_light">#fff1f1f1</color>
@@ -65,9 +66,6 @@
<!-- 70% white -->
<color name="secondary_text_default_material_dark">#b3ffffff</color>
- <color name="error_text_material_light">@color/material_red_A700</color>
- <color name="error_text_material_dark">@color/material_red_A100</color>
-
<item name="hint_alpha_material_dark" format="float" type="dimen">0.50</item>
<item name="hint_alpha_material_light" format="float" type="dimen">0.38</item>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index d233e24..ab2e090 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -239,6 +239,7 @@
<item>"mobile,0,0,0,-1,true"</item>
<item>"mobile_mms,2,0,2,60000,true"</item>
<item>"mobile_supl,3,0,2,60000,true"</item>
+ <item>"mobile_dun,4,0,2,60000,true"</item>
<item>"mobile_hipri,5,0,3,60000,true"</item>
<item>"mobile_fota,10,0,2,60000,true"</item>
<item>"mobile_ims,11,0,2,60000,true"</item>
@@ -1273,19 +1274,6 @@
config_enableFusedLocationOverlay is false. -->
<string name="config_fusedLocationProviderPackageName" translatable="false">com.android.location.fused</string>
- <!-- A list of potential packages, in priority order, that may contain a
- network recommendation provider. A network recommendation provider must:
- * Be granted the SCORE_NETWORKS permission.
- * Include a Service for the android.net.scoring.RECOMMEND_NETWORKS action
- protected by the BIND_NETWORK_RECOMMENDATION_SERVICE permission.
-
- This may be empty if network scoring and recommending isn't supported.
- -->
- <string-array name="config_networkRecommendationPackageNames" translatable="false">
- <!-- The standard AOSP network recommendation provider -->
- <item>com.android.networkrecommendation</item>
- </string-array>
-
<!-- The package name of the default network recommendation app.
A network recommendation provider must:
* Be granted the SCORE_NETWORKS permission.
@@ -2748,8 +2736,8 @@
<!-- Flag indicates that whether non-system apps can be installed on internal storage. -->
<bool name="config_allow3rdPartyAppOnInternal">true</bool>
- <!-- Component name of the default cell broadcast receiver -->
- <string name="config_defaultCellBroadcastReceiverComponent" translatable="false">com.android.cellbroadcastreceiver/.PrivilegedCellBroadcastReceiver</string>
+ <!-- Package name of the default cell broadcast receiver -->
+ <string name="config_defaultCellBroadcastReceiverPkg" translatable="false">com.android.cellbroadcastreceiver</string>
<!-- Specifies the path that is used by AdaptiveIconDrawable class to crop launcher icons. -->
<string name="config_icon_mask" translatable="false">"M50,0L100,0 100,100 0,100 0,0z"</string>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 78549b5..01737e7 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2765,7 +2765,7 @@
<public name="font" />
<public name="fontWeight" />
<public name="tooltipText" />
- <public name="autoSizeText" />
+ <public name="autoSizeTextType" />
<public name="autoSizeStepGranularity" />
<public name="autoSizePresetSizes" />
<public name="autoSizeMinTextSize" />
@@ -2780,7 +2780,7 @@
<public name="targetProcess" />
<public name="nextClusterForward" />
<public name="__removed1" />
- <public name="textColorError" />
+ <public name="colorError" />
<public name="focusedByDefault" />
<public name="appCategory" />
<public name="autoSizeMaxTextSize" />
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index f6da660..ea06664 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -587,6 +587,48 @@
<!-- Text shown in place of notification contents when the notification is hidden by policy on a secure lockscreen -->
<string name="notification_hidden_by_policy_text">Contents hidden by policy</string>
+ <!-- Text shown when viewing channel settings for notifications related to the virtual keyboard -->
+ <string name="notification_channel_virtual_keyboard">Virtual keyboard</string>
+
+ <!-- Text shown when viewing channel settings for notifications related to the hardware keyboard -->
+ <string name="notification_channel_physical_keyboard">Physical keyboard</string>
+
+ <!-- Text shown when viewing channel settings for notifications related to security -->
+ <string name="notification_channel_security">Security</string>
+
+ <!-- Text shown when viewing channel settings for notifications related to car mode -->
+ <string name="notification_channel_car_mode">Car mode</string>
+
+ <!-- Text shown when viewing channel settings for notifications related to account status -->
+ <string name="notification_channel_account">Account status</string>
+
+ <!-- Text shown when viewing channel settings for notifications related to developers -->
+ <string name="notification_channel_developer">Developer messages</string>
+
+ <!-- Text shown when viewing channel settings for notifications related to system updates -->
+ <string name="notification_channel_updates">Updates</string>
+
+ <!-- Text shown when viewing channel settings for notifications related to network status -->
+ <string name="notification_channel_network_status">Network status</string>
+
+ <!-- Text shown when viewing channel settings for notifications related to network alerts -->
+ <string name="notification_channel_network_alerts">Network alerts</string>
+
+ <!-- Text shown when viewing channel settings for notifications related to vpn status -->
+ <string name="notification_channel_vpn">VPN status</string>
+
+ <!-- Text shown when viewing channel settings for notifications related to remote device administration -->
+ <string name="notification_channel_device_admin">Device administration</string>
+
+ <!-- Text shown when viewing channel settings for notifications related to important alerts -->
+ <string name="notification_channel_alerts">Alerts</string>
+
+ <!-- Text shown when viewing channel settings for notifications related to being in retail mode -->
+ <string name="notification_channel_retail_mode">Retail demo</string>
+
+ <!-- Text shown when viewing channel settings for notifications related to a usb connection -->
+ <string name="notification_channel_usb">USB connection</string>
+
<!-- Displayed to the user to tell them that they have started up the phone in "safe mode" -->
<string name="safeMode">Safe mode</string>
@@ -728,6 +770,11 @@
the call to a different number or abort the call altogether.</string>
<!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+ <string name="permlab_answerPhoneCalls">answer phone calls</string>
+ <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+ <string name="permdesc_answerPhoneCalls">Allows the app to answer an incoming phone call.</string>
+
+ <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permlab_receiveSms">receive text messages (SMS)</string>
<!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permdesc_receiveSms">Allows the app to receive and process SMS
@@ -4510,4 +4557,22 @@
<!-- Accessibility string used for describing the button in time picker that changes the dialog to circular clock mode. [CHAR LIMIT=NONE] -->
<string name="time_picker_radial_mode_description">Switch to clock mode for the time input.</string>
+ <!-- Title for the auto-fill save dialog shown when the the contents of the activity can be saved
+ by an auto-fill service, but the service does not know what the activity represents [CHAR LIMIT=NONE] -->
+ <string name="autofill_save_title">Save to <xliff:g id="label" example="MyPass">%1$s</xliff:g>?</string>
+ <!-- Title for the auto-fill save dialog shown when the the contents of the activity can be saved
+ by an auto-fill service, and the service does knows what the activity represents (for example, credit card info) [CHAR LIMIT=NONE] -->
+ <string name="autofill_save_title_with_type">Save <xliff:g id="type" example="Credit Card">%1$s</xliff:g> to <xliff:g id="label" example="MyPass">%2$s</xliff:g>?</string>
+ <!-- Label for the auto-fill save button [CHAR LIMIT=NONE] -->
+ <string name="autofill_save_yes">Save</string>
+ <!-- Label for the auto-fill cancel button [CHAR LIMIT=NONE] -->
+ <string name="autofill_save_no">No thanks</string>
+
+ <!-- Label for the type of data being saved for auto-fill when it represent user credentials with a password [CHAR LIMIT=NONE] -->
+ <string name="autofill_save_type_password">password</string>
+ <!-- Label for the type of data being saved for auto-fill when it represent an address (street, city, etc.) [CHAR LIMIT=NONE] -->
+ <string name="autofill_save_type_address">address</string>
+ <!-- Label for the type of data being saved for auto-fill when it represents a credit card [CHAR LIMIT=NONE] -->
+ <string name="autofill_save_type_credit_card">credit card</string>
+
</resources>
diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml
index faf451b..25873d2 100644
--- a/core/res/res/values/styles.xml
+++ b/core/res/res/values/styles.xml
@@ -1475,4 +1475,10 @@
<item name="padding">16dp</item>
</style>
+ <style name="Widget.LockPatternView">
+ <item name="regularColor">@color/lock_pattern_view_regular_color</item>
+ <item name="errorColor">?attr/colorError</item>
+ <item name="successColor">@color/lock_pattern_view_success_color</item>
+ </style>
+
</resources>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index eb248e5..3ba6a27 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -1195,7 +1195,6 @@
<java-symbol type="drawable" name="btn_check_off" />
<java-symbol type="color" name="lock_pattern_view_regular_color" />
<java-symbol type="color" name="lock_pattern_view_success_color" />
- <java-symbol type="color" name="lock_pattern_view_error_color" />
<java-symbol type="dimen" name="lock_pattern_dot_line_width" />
<java-symbol type="dimen" name="lock_pattern_dot_size" />
<java-symbol type="dimen" name="lock_pattern_dot_size_activated" />
@@ -2310,7 +2309,6 @@
<java-symbol type="layout" name="select_dialog_singlechoice_material" />
<java-symbol type="layout" name="select_dialog_multichoice_material" />
<java-symbol type="array" name="no_ems_support_sim_operators" />
- <java-symbol type="color" name="battery_saver_mode_color" />
<java-symbol type="color" name="system_notification_accent_color" />
<java-symbol type="dimen" name="text_handle_min_size" />
<java-symbol type="id" name="transitionTransform" />
@@ -2787,7 +2785,6 @@
<java-symbol type="layout" name="notification_template_material_ambient" />
<!-- Network Recommendation -->
- <java-symbol type="array" name="config_networkRecommendationPackageNames" />
<java-symbol type="string" name="config_defaultNetworkRecommendationProviderPackage" />
<!-- Whether allow 3rd party apps on internal storage. -->
@@ -2798,7 +2795,7 @@
<java-symbol type="drawable" name="lockscreen_selected" />
<java-symbol type="string" name="notification_header_divider_symbol_with_spaces" />
- <java-symbol type="string" name="config_defaultCellBroadcastReceiverComponent" />
+ <java-symbol type="string" name="config_defaultCellBroadcastReceiverPkg" />
<java-symbol type="color" name="notification_primary_text_color_light" />
<java-symbol type="color" name="notification_primary_text_color_dark" />
@@ -2840,8 +2837,17 @@
<java-symbol type="layout" name="autofill_save"/>
<java-symbol type="layout" name="autofill_dataset_picker"/>
<java-symbol type="id" name="autofill_save_title" />
+ <java-symbol type="id" name="autofill_save_subtitle" />
<java-symbol type="id" name="autofill_save_no" />
<java-symbol type="id" name="autofill_save_yes" />
+ <java-symbol type="id" name="autofill_save_close" />
+ <java-symbol type="string" name="autofill_save_title" />
+ <java-symbol type="string" name="autofill_save_title_with_type" />
+ <java-symbol type="string" name="autofill_save_yes" />
+ <java-symbol type="string" name="autofill_save_no" />
+ <java-symbol type="string" name="autofill_save_type_password" />
+ <java-symbol type="string" name="autofill_save_type_address" />
+ <java-symbol type="string" name="autofill_save_type_credit_card" />
<!-- Accessibility fingerprint gestures -->
<java-symbol type="string" name="capability_title_canCaptureFingerprintGestures" />
@@ -2849,7 +2855,7 @@
<!-- android.service.trust -->
<java-symbol type="bool" name="config_allowEscrowTokenForTrustAgent"/>
-
+
<!-- Time picker -->
<java-symbol type="id" name="toggle_mode"/>
<java-symbol type="id" name="input_mode"/>
@@ -2876,7 +2882,26 @@
<java-symbol type="string" name="alert_windows_notification_message" />
<java-symbol type="string" name="alert_windows_notification_turn_off_action" />
<java-symbol type="drawable" name="alert_window_layer" />
+ <java-symbol type="style" name="Widget.LockPatternView" />
+ <java-symbol type="attr" name="lockPatternStyle" />
<!-- Colon separated list of package names that should be granted Notification Listener access -->
<java-symbol type="string" name="config_defaultListenerAccessPackages" />
+
+ <!-- system notification channels -->
+ <java-symbol type="string" name="notification_channel_virtual_keyboard" />
+ <java-symbol type="string" name="notification_channel_physical_keyboard" />
+ <java-symbol type="string" name="notification_channel_security" />
+ <java-symbol type="string" name="notification_channel_car_mode" />
+ <java-symbol type="string" name="notification_channel_account" />
+ <java-symbol type="string" name="notification_channel_developer" />
+ <java-symbol type="string" name="notification_channel_updates" />
+ <java-symbol type="string" name="notification_channel_network_status" />
+ <java-symbol type="string" name="notification_channel_network_alerts" />
+ <java-symbol type="string" name="notification_channel_vpn" />
+ <java-symbol type="string" name="notification_channel_device_admin" />
+ <java-symbol type="string" name="notification_channel_alerts" />
+ <java-symbol type="string" name="notification_channel_retail_mode" />
+ <java-symbol type="string" name="notification_channel_usb" />
+
</resources>
diff --git a/core/res/res/values/themes.xml b/core/res/res/values/themes.xml
index e357678..d100c63 100644
--- a/core/res/res/values/themes.xml
+++ b/core/res/res/values/themes.xml
@@ -63,6 +63,7 @@
<item name="colorControlHighlight">@color/legacy_button_pressed</item>
<item name="colorButtonNormal">@color/legacy_button_normal</item>
<item name="colorEdgeEffect">?attr/colorPrimary</item>
+ <item name="colorError">@color/red</item>
<item name="disabledAlpha">0.5</item>
<item name="backgroundDimAmount">0.6</item>
@@ -93,7 +94,6 @@
<item name="textColorLink">@color/link_text_dark</item>
<item name="textColorLinkInverse">@color/link_text_light</item>
<item name="textColorAlertDialogListItem">@color/primary_text_light_disable_only</item>
- <item name="textColorError">@color/red</item>
<item name="textAppearanceLarge">@style/TextAppearance.Large</item>
<item name="textAppearanceMedium">@style/TextAppearance.Medium</item>
diff --git a/core/res/res/values/themes_material.xml b/core/res/res/values/themes_material.xml
index 400fb47..008c817 100644
--- a/core/res/res/values/themes_material.xml
+++ b/core/res/res/values/themes_material.xml
@@ -51,6 +51,7 @@
<item name="primaryContentAlpha">@dimen/primary_content_alpha_material_dark</item>
<item name="secondaryContentAlpha">@dimen/secondary_content_alpha_material_dark</item>
<item name="backgroundDimAmount">0.6</item>
+ <item name="colorError">@color/error_color_material</item>
<!-- Text styles -->
<item name="textAppearance">@style/TextAppearance.Material</item>
@@ -73,7 +74,6 @@
<item name="textColorLinkInverse">?attr/colorAccent</item>
<item name="textColorSearchUrl">@color/search_url_text_material_dark</item>
<item name="textColorAlertDialogListItem">@color/primary_text_material_dark</item>
- <item name="textColorError">@color/error_text_material_dark</item>
<item name="textAppearanceLarge">@style/TextAppearance.Material.Large</item>
<item name="textAppearanceLargeInverse">@style/TextAppearance.Material.Large.Inverse</item>
@@ -441,7 +441,6 @@
<item name="textColorLinkInverse">?attr/colorAccent</item>
<item name="textColorSearchUrl">@color/search_url_text_material_light</item>
<item name="textColorAlertDialogListItem">@color/primary_text_material_light</item>
- <item name="textColorError">@color/error_text_material_light</item>
<item name="textAppearanceLarge">@style/TextAppearance.Material.Large</item>
<item name="textAppearanceLargeInverse">@style/TextAppearance.Material.Large.Inverse</item>
@@ -823,7 +822,6 @@
<item name="textColorHighlightInverse">@color/highlighted_text_material</item>
<item name="textColorSearchUrl">@color/search_url_text_material_light</item>
<item name="textColorAlertDialogListItem">@color/primary_text_material_light</item>
- <item name="textColorError">@color/error_text_material_light</item>
<item name="textCheckMark">@drawable/indicator_check_mark_light</item>
<item name="textCheckMarkInverse">@drawable/indicator_check_mark_dark</item>
@@ -856,7 +854,6 @@
<item name="textColorHighlightInverse">@color/highlighted_text_material</item>
<item name="textColorSearchUrl">@color/search_url_text_material_dark</item>
<item name="textColorAlertDialogListItem">@color/primary_text_material_dark</item>
- <item name="textColorError">@color/error_text_material_dark</item>
<item name="textCheckMark">@drawable/indicator_check_mark_dark</item>
<item name="textCheckMarkInverse">@drawable/indicator_check_mark_light</item>
diff --git a/graphics/tests/graphicstests/res/color/color1.xml b/core/tests/coretests/res/color/color1.xml
similarity index 100%
rename from graphics/tests/graphicstests/res/color/color1.xml
rename to core/tests/coretests/res/color/color1.xml
diff --git a/graphics/tests/graphicstests/res/color/color_no_default.xml b/core/tests/coretests/res/color/color_no_default.xml
similarity index 100%
rename from graphics/tests/graphicstests/res/color/color_no_default.xml
rename to core/tests/coretests/res/color/color_no_default.xml
diff --git a/graphics/tests/graphicstests/res/drawable-nodpi/landscape.png b/core/tests/coretests/res/drawable-nodpi/landscape.png
similarity index 100%
rename from graphics/tests/graphicstests/res/drawable-nodpi/landscape.png
rename to core/tests/coretests/res/drawable-nodpi/landscape.png
Binary files differ
diff --git a/graphics/tests/graphicstests/res/drawable/test128x96.png b/core/tests/coretests/res/drawable/test128x96.png
similarity index 100%
rename from graphics/tests/graphicstests/res/drawable/test128x96.png
rename to core/tests/coretests/res/drawable/test128x96.png
Binary files differ
diff --git a/graphics/tests/graphicstests/res/drawable/test16x12.png b/core/tests/coretests/res/drawable/test16x12.png
similarity index 100%
rename from graphics/tests/graphicstests/res/drawable/test16x12.png
rename to core/tests/coretests/res/drawable/test16x12.png
Binary files differ
diff --git a/graphics/tests/graphicstests/res/drawable/test256x192.png b/core/tests/coretests/res/drawable/test256x192.png
similarity index 100%
rename from graphics/tests/graphicstests/res/drawable/test256x192.png
rename to core/tests/coretests/res/drawable/test256x192.png
Binary files differ
diff --git a/graphics/tests/graphicstests/res/drawable/test320x240.png b/core/tests/coretests/res/drawable/test320x240.png
similarity index 100%
rename from graphics/tests/graphicstests/res/drawable/test320x240.png
rename to core/tests/coretests/res/drawable/test320x240.png
Binary files differ
diff --git a/graphics/tests/graphicstests/res/drawable/test32x24.png b/core/tests/coretests/res/drawable/test32x24.png
similarity index 100%
rename from graphics/tests/graphicstests/res/drawable/test32x24.png
rename to core/tests/coretests/res/drawable/test32x24.png
Binary files differ
diff --git a/graphics/tests/graphicstests/res/drawable/test64x48.png b/core/tests/coretests/res/drawable/test64x48.png
similarity index 100%
rename from graphics/tests/graphicstests/res/drawable/test64x48.png
rename to core/tests/coretests/res/drawable/test64x48.png
Binary files differ
diff --git a/core/tests/coretests/res/values/colors.xml b/core/tests/coretests/res/values/colors.xml
index f881660..f01af84 100644
--- a/core/tests/coretests/res/values/colors.xml
+++ b/core/tests/coretests/res/values/colors.xml
@@ -23,4 +23,7 @@
<drawable name="blue">#ff0000ff</drawable>
<drawable name="green">#ff00ff00</drawable>
<drawable name="yellow">#ffffff00</drawable>
+ <color name="testcolor1">#ff00ff00</color>
+ <color name="testcolor2">#ffff0000</color>
+ <color name="failColor">#ff0000ff</color>
</resources>
diff --git a/core/tests/coretests/src/android/content/pm/ParceledListSliceTest.java b/core/tests/coretests/src/android/content/pm/ParceledListSliceTest.java
index e5a92bf..5dd3c2c 100644
--- a/core/tests/coretests/src/android/content/pm/ParceledListSliceTest.java
+++ b/core/tests/coretests/src/android/content/pm/ParceledListSliceTest.java
@@ -91,6 +91,28 @@
}
}
+ public void testStringList() throws Exception {
+ final int objectCount = 400;
+ List<String> list = new ArrayList<String>();
+ for (long i = 0; i < objectCount; i++) {
+ list.add(Long.toString(i * (6 - i)));
+ }
+
+ StringParceledListSlice slice;
+ Parcel parcel = Parcel.obtain();
+ try {
+ parcel.writeParcelable(new StringParceledListSlice(list), 0);
+ parcel.setDataPosition(0);
+ slice = parcel.readParcelable(getClass().getClassLoader());
+ } finally {
+ parcel.recycle();
+ }
+
+ assertNotNull(slice);
+ assertNotNull(slice.getList());
+ assertEquals(list, slice.getList());
+ }
+
/**
* Test that only homogeneous elements may be unparceled.
*/
diff --git a/graphics/tests/graphicstests/src/android/graphics/BitmapFactoryTest.java b/core/tests/coretests/src/android/graphics/BitmapFactoryTest.java
similarity index 99%
rename from graphics/tests/graphicstests/src/android/graphics/BitmapFactoryTest.java
rename to core/tests/coretests/src/android/graphics/BitmapFactoryTest.java
index 09820ef..e9e2a4d 100644
--- a/graphics/tests/graphicstests/src/android/graphics/BitmapFactoryTest.java
+++ b/core/tests/coretests/src/android/graphics/BitmapFactoryTest.java
@@ -19,11 +19,11 @@
import android.os.ParcelFileDescriptor;
import android.test.suitebuilder.annotation.SmallTest;
+import junit.framework.TestCase;
+
import java.io.ByteArrayOutputStream;
import java.io.FileDescriptor;
-import junit.framework.TestCase;
-
public class BitmapFactoryTest extends TestCase {
diff --git a/graphics/tests/graphicstests/src/android/graphics/BitmapTest.java b/core/tests/coretests/src/android/graphics/BitmapTest.java
similarity index 91%
rename from graphics/tests/graphicstests/src/android/graphics/BitmapTest.java
rename to core/tests/coretests/src/android/graphics/BitmapTest.java
index 685a998..3666ddd 100644
--- a/graphics/tests/graphicstests/src/android/graphics/BitmapTest.java
+++ b/core/tests/coretests/src/android/graphics/BitmapTest.java
@@ -17,6 +17,7 @@
package android.graphics;
import android.test.suitebuilder.annotation.SmallTest;
+
import junit.framework.TestCase;
@@ -38,11 +39,11 @@
assertEquals("rowbytes", 400, bm1.getRowBytes());
assertEquals("rowbytes", 200, bm2.getRowBytes());
- assertEquals("rowbytes", 200, bm3.getRowBytes());
-
+ assertEquals("rowbytes", 400, bm3.getRowBytes());
+
assertEquals("byteCount", 80000, bm1.getByteCount());
assertEquals("byteCount", 40000, bm2.getByteCount());
- assertEquals("byteCount", 40000, bm3.getByteCount());
+ assertEquals("byteCount", 80000, bm3.getByteCount());
assertEquals("height", 200, bm1.getHeight());
assertEquals("height", 200, bm2.getHeight());
@@ -51,10 +52,10 @@
assertTrue("hasAlpha", bm1.hasAlpha());
assertFalse("hasAlpha", bm2.hasAlpha());
assertTrue("hasAlpha", bm3.hasAlpha());
-
+
assertTrue("getConfig", bm1.getConfig() == Bitmap.Config.ARGB_8888);
assertTrue("getConfig", bm2.getConfig() == Bitmap.Config.RGB_565);
- assertTrue("getConfig", bm3.getConfig() == Bitmap.Config.ARGB_4444);
+ assertTrue("getConfig", bm3.getConfig() == Bitmap.Config.ARGB_8888);
}
@SmallTest
@@ -181,12 +182,12 @@
for (int i = 0; i < 256; i++) {
colors[i] = (i << 24) | (0xFF << 16) | (0x80 << 8) | 0;
}
-
+
Bitmap.Config config = Bitmap.Config.ARGB_8888;
// create a bitmap with the color array specified
Bitmap bm1 = Bitmap.createBitmap(colors, 16, 16, config);
-
+
// create a bitmap with no colors, but then call setPixels
Bitmap bm2 = Bitmap.createBitmap(16, 16, config);
bm2.setPixels(colors, 0, 16, 0, 0, 16, 16);
@@ -197,32 +198,32 @@
int c0 = colors[i];
int c1 = bm1.getPixel(i % 16, i / 16);
int c2 = bm2.getPixel(i % 16, i / 16);
-
+
// these two should always be identical
assertEquals("getPixel", c1, c2);
-
+
// comparing the original (c0) with the returned color is tricky,
// since it gets premultiplied during the set(), and unpremultiplied
// by the get().
int a0 = Color.alpha(c0);
int a1 = Color.alpha(c1);
assertEquals("alpha", a0, a1);
-
+
int r0 = Color.red(c0);
int r1 = Color.red(c1);
int rr = computePrePostMul(a0, r0);
assertTrue("red", Math.abs(rr - r1) <= tolerance);
-
+
int g0 = Color.green(c0);
int g1 = Color.green(c1);
int gg = computePrePostMul(a0, g0);
assertTrue("green", Math.abs(gg - g1) <= tolerance);
-
+
int b0 = Color.blue(c0);
int b1 = Color.blue(c1);
int bb = computePrePostMul(a0, b0);
assertTrue("blue", Math.abs(bb - b1) <= tolerance);
-
+
if (false) {
int cc = Color.argb(a0, rr, gg, bb);
android.util.Log.d("skia", "original " + Integer.toHexString(c0) +
@@ -231,4 +232,16 @@
}
}
}
+
+ @SmallTest
+ public void testCreateHardwareBitmapFromGraphicBuffer() {
+ GraphicBuffer buffer = GraphicBuffer.create(10, 10, PixelFormat.RGBA_8888,
+ GraphicBuffer.USAGE_HW_TEXTURE | GraphicBuffer.USAGE_SOFTWARE_MASK);
+ Canvas canvas = buffer.lockCanvas();
+ canvas.drawColor(Color.YELLOW);
+ buffer.unlockCanvasAndPost(canvas);
+ Bitmap hardwareBitmap = Bitmap.createHardwareBitmap(buffer);
+ assertTrue(hardwareBitmap.isPremultiplied());
+ assertFalse(hardwareBitmap.isMutable());
+ }
}
diff --git a/graphics/tests/graphicstests/src/android/graphics/ColorStateListTest.java b/core/tests/coretests/src/android/graphics/ColorStateListTest.java
similarity index 97%
rename from graphics/tests/graphicstests/src/android/graphics/ColorStateListTest.java
rename to core/tests/coretests/src/android/graphics/ColorStateListTest.java
index eb1025c..374d142 100644
--- a/graphics/tests/graphicstests/src/android/graphics/ColorStateListTest.java
+++ b/core/tests/coretests/src/android/graphics/ColorStateListTest.java
@@ -16,13 +16,13 @@
package android.graphics;
-import com.android.frameworks.graphicstests.R;
-
-import android.content.res.Resources;
import android.content.res.ColorStateList;
+import android.content.res.Resources;
import android.test.AndroidTestCase;
import android.test.suitebuilder.annotation.SmallTest;
+import com.android.frameworks.coretests.R;
+
/**
* Tests of {@link android.graphics.ColorStateList}
*/
diff --git a/graphics/tests/graphicstests/src/android/graphics/GraphicsPerformanceTests.java b/core/tests/coretests/src/android/graphics/GraphicsPerformanceTests.java
similarity index 98%
rename from graphics/tests/graphicstests/src/android/graphics/GraphicsPerformanceTests.java
rename to core/tests/coretests/src/android/graphics/GraphicsPerformanceTests.java
index f60ac7b..164c1aa 100644
--- a/graphics/tests/graphicstests/src/android/graphics/GraphicsPerformanceTests.java
+++ b/core/tests/coretests/src/android/graphics/GraphicsPerformanceTests.java
@@ -16,19 +16,15 @@
package android.graphics;
-import junit.framework.Assert;
import android.content.Context;
import android.content.res.Resources;
-import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
-import android.graphics.Canvas;
-import android.graphics.Paint;
import android.test.AndroidTestCase;
import android.test.PerformanceTestCase;
import android.test.suitebuilder.annotation.Suppress;
-import android.util.Log;
-import com.android.frameworks.graphicstests.R;
+import com.android.frameworks.coretests.R;
+
+import junit.framework.Assert;
/**
* Graphics Performance Tests
diff --git a/graphics/tests/graphicstests/src/android/graphics/GraphicsTests.java b/core/tests/coretests/src/android/graphics/GraphicsTests.java
similarity index 100%
rename from graphics/tests/graphicstests/src/android/graphics/GraphicsTests.java
rename to core/tests/coretests/src/android/graphics/GraphicsTests.java
diff --git a/core/tests/coretests/src/android/graphics/PaintTest.java b/core/tests/coretests/src/android/graphics/PaintTest.java
index 2a3d463..5811ca0 100644
--- a/core/tests/coretests/src/android/graphics/PaintTest.java
+++ b/core/tests/coretests/src/android/graphics/PaintTest.java
@@ -156,4 +156,213 @@
}
}
}
+
+ public void testGetTextRunAdvances() {
+ {
+ // LTR
+ String text = "abcdef";
+ assertGetTextRunAdvances(text, 0, text.length(), 0, text.length(), false, true);
+ assertGetTextRunAdvances(text, 1, text.length() - 1, 0, text.length(), false, false);
+ }
+ {
+ // RTL
+ final String text =
+ "\u0645\u0627\u0020\u0647\u064A\u0020\u0627\u0644\u0634" +
+ "\u0641\u0631\u0629\u0020\u0627\u0644\u0645\u0648\u062D" +
+ "\u062F\u0629\u0020\u064A\u0648\u0646\u064A\u0643\u0648" +
+ "\u062F\u061F";
+ assertGetTextRunAdvances(text, 0, text.length(), 0, text.length(), true, true);
+ assertGetTextRunAdvances(text, 1, text.length() - 1, 0, text.length(), true, false);
+ }
+ }
+
+ private void assertGetTextRunAdvances(String str, int start, int end,
+ int contextStart, int contextEnd, boolean isRtl, boolean compareWithOtherMethods) {
+ Paint p = new Paint();
+
+ final int count = end - start;
+ final float[][] advanceArrays = new float[4][count];
+
+ final float advance = p.getTextRunAdvances(str, start, end, contextStart, contextEnd,
+ isRtl, advanceArrays[0], 0);
+
+ char chars[] = str.toCharArray();
+ final float advance_c = p.getTextRunAdvances(chars, start, count, contextStart,
+ contextEnd - contextStart, isRtl, advanceArrays[1], 0);
+ assertEquals(advance, advance_c, 1.0f);
+
+ for (int c = 1; c < count; ++c) {
+ final float firstPartAdvance = p.getTextRunAdvances(str, start, start + c,
+ contextStart, contextEnd, isRtl, advanceArrays[2], 0);
+ final float secondPartAdvance = p.getTextRunAdvances(str, start + c, end,
+ contextStart, contextEnd, isRtl, advanceArrays[2], c);
+ assertEquals(advance, firstPartAdvance + secondPartAdvance, 1.0f);
+
+
+ final float firstPartAdvance_c = p.getTextRunAdvances(chars, start, c,
+ contextStart, contextEnd - contextStart, isRtl, advanceArrays[3], 0);
+ final float secondPartAdvance_c = p.getTextRunAdvances(chars, start + c,
+ count - c, contextStart, contextEnd - contextStart, isRtl,
+ advanceArrays[3], c);
+ assertEquals(advance, firstPartAdvance_c + secondPartAdvance_c, 1.0f);
+ assertEquals(firstPartAdvance, firstPartAdvance_c, 1.0f);
+ assertEquals(secondPartAdvance, secondPartAdvance_c, 1.0f);
+
+ for (int i = 1; i < advanceArrays.length; i++) {
+ for (int j = 0; j < count; j++) {
+ assertEquals(advanceArrays[0][j], advanceArrays[i][j], 1.0f);
+ }
+ }
+
+ // Compare results with measureText, getRunAdvance, and getTextWidths.
+ if (compareWithOtherMethods && start == contextStart && end == contextEnd) {
+ assertEquals(advance, p.measureText(str, start, end), 1.0f);
+ assertEquals(advance, p.getRunAdvance(
+ str, start, end, contextStart, contextEnd, isRtl, end), 1.0f);
+
+ final float[] widths = new float[count];
+ p.getTextWidths(str, start, end, widths);
+ for (int i = 0; i < count; i++) {
+ assertEquals(advanceArrays[0][i], widths[i], 1.0f);
+ }
+ }
+ }
+ }
+
+ public void testGetTextRunAdvances_invalid() {
+ Paint p = new Paint();
+ String text = "test";
+
+ try {
+ p.getTextRunAdvances((String)null, 0, 0, 0, 0, false, null, 0);
+ fail("Should throw an IllegalArgumentException.");
+ } catch (IllegalArgumentException e) {
+ }
+
+ try {
+ p.getTextRunAdvances((CharSequence)null, 0, 0, 0, 0, false, null, 0);
+ fail("Should throw an IllegalArgumentException.");
+ } catch (IllegalArgumentException e) {
+ }
+
+ try {
+ p.getTextRunAdvances((char[])null, 0, 0, 0, 0, false, null, 0);
+ fail("Should throw an IllegalArgumentException.");
+ } catch (IllegalArgumentException e) {
+ }
+
+ try {
+ p.getTextRunAdvances(text, 0, text.length(), 0, text.length(), false,
+ new float[text.length() - 1], 0);
+ fail("Should throw an IndexOutOfBoundsException.");
+ } catch (IndexOutOfBoundsException e) {
+ }
+
+ try {
+ p.getTextRunAdvances(text, 0, text.length(), 0, text.length(), false,
+ new float[text.length()], 1);
+ fail("Should throw an IndexOutOfBoundsException.");
+ } catch (IndexOutOfBoundsException e) {
+ }
+
+ // 0 > contextStart
+ try {
+ p.getTextRunAdvances(text, 0, text.length(), -1, text.length(), false, null, 0);
+ fail("Should throw an IndexOutOfBoundsException.");
+ } catch (IndexOutOfBoundsException e) {
+ }
+
+ // contextStart > start
+ try {
+ p.getTextRunAdvances(text, 0, text.length(), 1, text.length(), false, null, 0);
+ fail("Should throw an IndexOutOfBoundsException.");
+ } catch (IndexOutOfBoundsException e) {
+ }
+
+ // start > end
+ try {
+ p.getTextRunAdvances(text, 1, 0, 0, text.length(), false, null, 0);
+ fail("Should throw an IndexOutOfBoundsException.");
+ } catch (IndexOutOfBoundsException e) {
+ }
+
+ // end > contextEnd
+ try {
+ p.getTextRunAdvances(text, 0, text.length(), 0, text.length() - 1, false, null, 0);
+ fail("Should throw an IndexOutOfBoundsException.");
+ } catch (IndexOutOfBoundsException e) {
+ }
+
+ // contextEnd > text.length
+ try {
+ p.getTextRunAdvances(text, 0, text.length(), 0, text.length() + 1, false, null, 0);
+ fail("Should throw an IndexOutOfBoundsException.");
+ } catch (IndexOutOfBoundsException e) {
+ }
+ }
+
+ public void testMeasureTextBidi() {
+ Paint p = new Paint();
+ {
+ String bidiText = "abc \u0644\u063A\u0629 def";
+ p.setBidiFlags(Paint.BIDI_LTR);
+ float width = p.measureText(bidiText, 0, 4);
+ p.setBidiFlags(Paint.BIDI_RTL);
+ width += p.measureText(bidiText, 4, 7);
+ p.setBidiFlags(Paint.BIDI_LTR);
+ width += p.measureText(bidiText, 7, bidiText.length());
+ assertEquals(width, p.measureText(bidiText), 1.0f);
+ }
+ {
+ String bidiText = "abc \u0644\u063A\u0629 def";
+ p.setBidiFlags(Paint.BIDI_DEFAULT_LTR);
+ float width = p.measureText(bidiText, 0, 4);
+ width += p.measureText(bidiText, 4, 7);
+ width += p.measureText(bidiText, 7, bidiText.length());
+ assertEquals(width, p.measureText(bidiText), 1.0f);
+ }
+ {
+ String bidiText = "abc \u0644\u063A\u0629 def";
+ p.setBidiFlags(Paint.BIDI_FORCE_LTR);
+ float width = p.measureText(bidiText, 0, 4);
+ width += p.measureText(bidiText, 4, 7);
+ width += p.measureText(bidiText, 7, bidiText.length());
+ assertEquals(width, p.measureText(bidiText), 1.0f);
+ }
+ {
+ String bidiText = "\u0644\u063A\u0629 abc \u0644\u063A\u0629";
+ p.setBidiFlags(Paint.BIDI_RTL);
+ float width = p.measureText(bidiText, 0, 4);
+ p.setBidiFlags(Paint.BIDI_LTR);
+ width += p.measureText(bidiText, 4, 7);
+ p.setBidiFlags(Paint.BIDI_RTL);
+ width += p.measureText(bidiText, 7, bidiText.length());
+ assertEquals(width, p.measureText(bidiText), 1.0f);
+ }
+ {
+ String bidiText = "\u0644\u063A\u0629 abc \u0644\u063A\u0629";
+ p.setBidiFlags(Paint.BIDI_DEFAULT_RTL);
+ float width = p.measureText(bidiText, 0, 4);
+ width += p.measureText(bidiText, 4, 7);
+ width += p.measureText(bidiText, 7, bidiText.length());
+ assertEquals(width, p.measureText(bidiText), 1.0f);
+ }
+ {
+ String bidiText = "\u0644\u063A\u0629 abc \u0644\u063A\u0629";
+ p.setBidiFlags(Paint.BIDI_FORCE_RTL);
+ float width = p.measureText(bidiText, 0, 4);
+ width += p.measureText(bidiText, 4, 7);
+ width += p.measureText(bidiText, 7, bidiText.length());
+ assertEquals(width, p.measureText(bidiText), 1.0f);
+ }
+ }
+
+ public void testSetGetWordSpacing() {
+ Paint p = new Paint();
+ assertEquals(0.0f, p.getWordSpacing()); // The default value should be 0.
+ p.setWordSpacing(1.0f);
+ assertEquals(1.0f, p.getWordSpacing());
+ p.setWordSpacing(-2.0f);
+ assertEquals(-2.0f, p.getWordSpacing());
+ }
}
diff --git a/graphics/tests/graphicstests/src/android/graphics/PathTest.java b/core/tests/coretests/src/android/graphics/PathTest.java
similarity index 99%
rename from graphics/tests/graphicstests/src/android/graphics/PathTest.java
rename to core/tests/coretests/src/android/graphics/PathTest.java
index 96200bc..78e4959 100644
--- a/graphics/tests/graphicstests/src/android/graphics/PathTest.java
+++ b/core/tests/coretests/src/android/graphics/PathTest.java
@@ -17,6 +17,7 @@
package android.graphics;
import android.test.suitebuilder.annotation.SmallTest;
+
import junit.framework.TestCase;
diff --git a/graphics/tests/graphicstests/src/android/graphics/ThreadBitmapTest.java b/core/tests/coretests/src/android/graphics/ThreadBitmapTest.java
similarity index 97%
rename from graphics/tests/graphicstests/src/android/graphics/ThreadBitmapTest.java
rename to core/tests/coretests/src/android/graphics/ThreadBitmapTest.java
index 84bdc56..909a8d9 100644
--- a/graphics/tests/graphicstests/src/android/graphics/ThreadBitmapTest.java
+++ b/core/tests/coretests/src/android/graphics/ThreadBitmapTest.java
@@ -16,10 +16,10 @@
package android.graphics;
-import junit.framework.TestCase;
-import android.graphics.Bitmap;
import android.test.suitebuilder.annotation.LargeTest;
+import junit.framework.TestCase;
+
public class ThreadBitmapTest extends TestCase {
@Override
diff --git a/graphics/tests/graphicstests/src/android/graphics/VariationParserTest.java b/core/tests/coretests/src/android/graphics/VariationParserTest.java
similarity index 99%
rename from graphics/tests/graphicstests/src/android/graphics/VariationParserTest.java
rename to core/tests/coretests/src/android/graphics/VariationParserTest.java
index c7a46a3..a2ead40 100644
--- a/graphics/tests/graphicstests/src/android/graphics/VariationParserTest.java
+++ b/core/tests/coretests/src/android/graphics/VariationParserTest.java
@@ -18,9 +18,11 @@
import android.test.suitebuilder.annotation.SmallTest;
import android.text.FontConfig;
-import java.util.List;
+
import junit.framework.TestCase;
+import java.util.List;
+
public class VariationParserTest extends TestCase {
diff --git a/graphics/tests/graphicstests/src/android/graphics/drawable/IconTest.java b/core/tests/coretests/src/android/graphics/drawable/IconTest.java
similarity index 99%
rename from graphics/tests/graphicstests/src/android/graphics/drawable/IconTest.java
rename to core/tests/coretests/src/android/graphics/drawable/IconTest.java
index d3e1a43..cf132890 100644
--- a/graphics/tests/graphicstests/src/android/graphics/drawable/IconTest.java
+++ b/core/tests/coretests/src/android/graphics/drawable/IconTest.java
@@ -26,14 +26,13 @@
import android.test.suitebuilder.annotation.SmallTest;
import android.util.Log;
+import com.android.frameworks.coretests.R;
+
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
-import java.lang.Override;
-import java.util.Arrays;
import java.util.ArrayList;
-
-import com.android.frameworks.graphicstests.R;
+import java.util.Arrays;
public class IconTest extends AndroidTestCase {
public static final String TAG = IconTest.class.getSimpleName();
diff --git a/graphics/tests/graphicstests/src/android/graphics/drawable/StateListDrawableTest.java b/core/tests/coretests/src/android/graphics/drawable/StateListDrawableTest.java
similarity index 99%
rename from graphics/tests/graphicstests/src/android/graphics/drawable/StateListDrawableTest.java
rename to core/tests/coretests/src/android/graphics/drawable/StateListDrawableTest.java
index 0d9f72e..03a9c25 100644
--- a/graphics/tests/graphicstests/src/android/graphics/drawable/StateListDrawableTest.java
+++ b/core/tests/coretests/src/android/graphics/drawable/StateListDrawableTest.java
@@ -16,14 +16,14 @@
package android.graphics.drawable;
-import junit.framework.TestCase;
-
import android.R;
import android.graphics.Canvas;
import android.graphics.ColorFilter;
import android.util.StateSet;
import android.view.MockView;
+import junit.framework.TestCase;
+
/**
* Tests for StateListDrawable
*
diff --git a/core/tests/coretests/src/android/net/NetworkRecommendationProviderTest.java b/core/tests/coretests/src/android/net/NetworkRecommendationProviderTest.java
index bdc0200..497bc5c 100644
--- a/core/tests/coretests/src/android/net/NetworkRecommendationProviderTest.java
+++ b/core/tests/coretests/src/android/net/NetworkRecommendationProviderTest.java
@@ -3,61 +3,62 @@
import static android.net.NetworkRecommendationProvider.EXTRA_RECOMMENDATION_RESULT;
import static android.net.NetworkRecommendationProvider.EXTRA_SEQUENCE;
+import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertSame;
+import static junit.framework.Assert.fail;
+import static junit.framework.TestCase.assertEquals;
+
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Matchers.eq;
+
+import android.Manifest.permission;
import android.content.Context;
import android.os.Bundle;
-import android.os.Handler;
-import android.os.HandlerThread;
import android.os.IRemoteCallback;
-import android.test.InstrumentationTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
-import android.test.suitebuilder.annotation.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.Executor;
+import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
/**
* Unit test for the {@link NetworkRecommendationProvider}.
*/
-public class NetworkRecommendationProviderTest extends InstrumentationTestCase {
+@RunWith(AndroidJUnit4.class)
+public class NetworkRecommendationProviderTest {
@Mock private IRemoteCallback mMockRemoteCallback;
+ @Mock private Context mContext;
private NetworkRecProvider mRecProvider;
- private Handler mHandler;
private INetworkRecommendationProvider mStub;
private CountDownLatch mRecRequestLatch;
private CountDownLatch mScoreRequestLatch;
private NetworkKey[] mTestNetworkKeys;
- @Override
+ @Before
public void setUp() throws Exception {
- super.setUp();
-
- // Configuration needed to make mockito/dexcache work.
- final Context context = getInstrumentation().getTargetContext();
- System.setProperty("dexmaker.dexcache",
- context.getCacheDir().getPath());
- ClassLoader newClassLoader = getInstrumentation().getClass().getClassLoader();
- Thread.currentThread().setContextClassLoader(newClassLoader);
-
MockitoAnnotations.initMocks(this);
- HandlerThread thread = new HandlerThread("NetworkRecommendationProviderTest");
- thread.start();
+ Executor executor = Executors.newSingleThreadExecutor();
mRecRequestLatch = new CountDownLatch(1);
mScoreRequestLatch = new CountDownLatch(1);
- mHandler = new Handler(thread.getLooper());
- mRecProvider = new NetworkRecProvider(mHandler, mRecRequestLatch, mScoreRequestLatch);
+ mRecProvider = new NetworkRecProvider(mContext, executor, mRecRequestLatch,
+ mScoreRequestLatch);
mStub = INetworkRecommendationProvider.Stub.asInterface(mRecProvider.getBinder());
mTestNetworkKeys = new NetworkKey[2];
mTestNetworkKeys[0] = new NetworkKey(new WifiKey("\"ssid_01\"", "00:00:00:00:00:11"));
mTestNetworkKeys[1] = new NetworkKey(new WifiKey("\"ssid_02\"", "00:00:00:00:00:22"));
}
- @MediumTest
+ @Test
public void testRecommendationRequestReceived() throws Exception {
final RecommendationRequest request = new RecommendationRequest.Builder().build();
final int sequence = 100;
@@ -71,7 +72,23 @@
assertEquals(expectedResultCallback, mRecProvider.mCapturedCallback);
}
- @SmallTest
+ @Test
+ public void testRecommendationRequest_permissionsEnforced() throws Exception {
+ final RecommendationRequest request = new RecommendationRequest.Builder().build();
+ final int sequence = 100;
+ Mockito.doThrow(new SecurityException())
+ .when(mContext)
+ .enforceCallingOrSelfPermission(eq(permission.REQUEST_NETWORK_SCORES), anyString());
+
+ try {
+ mStub.requestRecommendation(request, mMockRemoteCallback, sequence);
+ fail("SecurityException expected.");
+ } catch (SecurityException e) {
+ // expected
+ }
+ }
+
+ @Test
public void testResultCallbackOnResult() throws Exception {
final int sequence = 100;
final NetworkRecommendationProvider.ResultCallback callback =
@@ -87,7 +104,7 @@
assertSame(result, capturedBundle.getParcelable(EXTRA_RECOMMENDATION_RESULT));
}
- @SmallTest
+ @Test
public void testResultCallbackOnResult_runTwice_throwsException() throws Exception {
final int sequence = 100;
final NetworkRecommendationProvider.ResultCallback callback =
@@ -104,7 +121,7 @@
}
}
- @MediumTest
+ @Test
public void testScoreRequestReceived() throws Exception {
mStub.requestScores(mTestNetworkKeys);
@@ -114,7 +131,7 @@
assertSame(mTestNetworkKeys, mRecProvider.mCapturedNetworks);
}
- @MediumTest
+ @Test
public void testScoreRequest_nullInput() throws Exception {
mStub.requestScores(null);
@@ -122,7 +139,7 @@
assertFalse(mScoreRequestLatch.await(200, TimeUnit.MILLISECONDS));
}
- @MediumTest
+ @Test
public void testScoreRequest_emptyInput() throws Exception {
mStub.requestScores(new NetworkKey[0]);
@@ -130,6 +147,20 @@
assertFalse(mScoreRequestLatch.await(200, TimeUnit.MILLISECONDS));
}
+ @Test
+ public void testScoreRequest_permissionsEnforced() throws Exception {
+ Mockito.doThrow(new SecurityException())
+ .when(mContext)
+ .enforceCallingOrSelfPermission(eq(permission.REQUEST_NETWORK_SCORES), anyString());
+
+ try {
+ mStub.requestScores(mTestNetworkKeys);
+ fail("SecurityException expected.");
+ } catch (SecurityException e) {
+ // expected
+ }
+ }
+
private static class NetworkRecProvider extends NetworkRecommendationProvider {
private final CountDownLatch mRecRequestLatch;
private final CountDownLatch mScoreRequestLatch;
@@ -137,9 +168,9 @@
ResultCallback mCapturedCallback;
NetworkKey[] mCapturedNetworks;
- NetworkRecProvider(Handler handler, CountDownLatch recRequestLatch,
+ NetworkRecProvider(Context context, Executor executor, CountDownLatch recRequestLatch,
CountDownLatch networkRequestLatch) {
- super(handler);
+ super(context, executor);
mRecRequestLatch = recRequestLatch;
mScoreRequestLatch = networkRequestLatch;
}
diff --git a/core/tests/coretests/src/android/net/NetworkScorerAppManagerTest.java b/core/tests/coretests/src/android/net/NetworkScorerAppManagerTest.java
deleted file mode 100644
index ce5d3ef..0000000
--- a/core/tests/coretests/src/android/net/NetworkScorerAppManagerTest.java
+++ /dev/null
@@ -1,216 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package android.net;
-
-import static org.mockito.Mockito.when;
-
-import android.Manifest.permission;
-import android.content.ComponentName;
-import android.content.ContentResolver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageManager;
-import android.content.pm.ResolveInfo;
-import android.content.pm.ServiceInfo;
-import android.content.res.Resources;
-import android.net.NetworkScorerAppManager.NetworkScorerAppData;
-import android.provider.Settings;
-import android.test.InstrumentationTestCase;
-
-import com.android.internal.R;
-
-import org.mockito.ArgumentMatcher;
-import org.mockito.Mock;
-import org.mockito.Mockito;
-import org.mockito.MockitoAnnotations;
-
-import java.util.List;
-
-public class NetworkScorerAppManagerTest extends InstrumentationTestCase {
- @Mock private Context mMockContext;
- @Mock private PackageManager mMockPm;
- @Mock private Resources mResources;
- @Mock private ContentResolver mContentResolver;
- private Context mTargetContext;
- private NetworkScorerAppManager mNetworkScorerAppManager;
-
- @Override
- public void setUp() throws Exception {
- super.setUp();
-
- // Configuration needed to make mockito/dexcache work.
- mTargetContext = getInstrumentation().getTargetContext();
- System.setProperty("dexmaker.dexcache", mTargetContext.getCacheDir().getPath());
- ClassLoader newClassLoader = getInstrumentation().getClass().getClassLoader();
- Thread.currentThread().setContextClassLoader(newClassLoader);
-
- MockitoAnnotations.initMocks(this);
- when(mMockContext.getPackageManager()).thenReturn(mMockPm);
- when(mMockContext.getResources()).thenReturn(mResources);
- when(mMockContext.getContentResolver()).thenReturn(mTargetContext.getContentResolver());
- mNetworkScorerAppManager = new NetworkScorerAppManager(mMockContext);
- }
-
- public void testGetPotentialRecommendationProviderPackages_emptyConfig() throws Exception {
- setNetworkRecommendationPackageNames(/*no configured packages*/);
- assertTrue(mNetworkScorerAppManager.getPotentialRecommendationProviderPackages().isEmpty());
- }
-
- public void testGetPotentialRecommendationProviderPackages_permissionNotGranted()
- throws Exception {
- setNetworkRecommendationPackageNames("package1");
- mockScoreNetworksDenied("package1");
-
- assertTrue(mNetworkScorerAppManager.getPotentialRecommendationProviderPackages().isEmpty());
- }
-
- public void testGetPotentialRecommendationProviderPackages_permissionGranted()
- throws Exception {
- setNetworkRecommendationPackageNames("package1");
- mockScoreNetworksGranted("package1");
-
- List<String> potentialProviderPackages =
- mNetworkScorerAppManager.getPotentialRecommendationProviderPackages();
-
- assertFalse(potentialProviderPackages.isEmpty());
- assertEquals("package1", potentialProviderPackages.get(0));
- }
-
- public void testGetPotentialRecommendationProviderPackages_multipleConfigured()
- throws Exception {
- setNetworkRecommendationPackageNames("package1", "package2");
- mockScoreNetworksDenied("package1");
- mockScoreNetworksGranted("package2");
-
- List<String> potentialProviderPackages =
- mNetworkScorerAppManager.getPotentialRecommendationProviderPackages();
-
- assertEquals(1, potentialProviderPackages.size());
- assertEquals("package2", potentialProviderPackages.get(0));
- }
-
- public void testGetNetworkRecommendationProviderData_noPotentialPackages() throws Exception {
- setNetworkRecommendationPackageNames(/*no configured packages*/);
- assertNull(mNetworkScorerAppManager.getNetworkRecommendationProviderData());
- }
-
- public void testGetNetworkRecommendationProviderData_serviceMissing() throws Exception {
- setNetworkRecommendationPackageNames("package1");
- mockScoreNetworksGranted("package1");
-
- assertNull(mNetworkScorerAppManager.getNetworkRecommendationProviderData());
- }
-
- public void testGetNetworkRecommendationProviderData_scoreNetworksNotGranted()
- throws Exception {
- final ComponentName recoComponent = new ComponentName("package1", "class1");
- setNetworkRecommendationPackageNames(recoComponent.getPackageName());
- mockScoreNetworksDenied(recoComponent.getPackageName());
- mockRecommendationServiceAvailable(recoComponent, 924 /* packageUid */);
-
- assertNull(mNetworkScorerAppManager.getNetworkRecommendationProviderData());
- }
-
- public void testGetNetworkRecommendationProviderData_available() throws Exception {
- final ComponentName recoComponent = new ComponentName("package1", "class1");
- setNetworkRecommendationPackageNames(recoComponent.getPackageName());
- mockScoreNetworksGranted(recoComponent.getPackageName());
- mockRecommendationServiceAvailable(recoComponent, 924 /* packageUid */);
-
- NetworkScorerAppData appData =
- mNetworkScorerAppManager.getNetworkRecommendationProviderData();
- assertNotNull(appData);
- assertEquals(recoComponent, appData.getRecommendationServiceComponent());
- assertEquals(924, appData.packageUid);
- }
-
- public void testGetActiveScorer_providerAvailable() throws Exception {
- final ComponentName recoComponent = new ComponentName("package1", "class1");
- setNetworkRecommendationPackageNames(recoComponent.getPackageName());
- mockScoreNetworksGranted(recoComponent.getPackageName());
- mockRecommendationServiceAvailable(recoComponent, 924 /* packageUid */);
-
- ContentResolver cr = mTargetContext.getContentResolver();
- Settings.Global.putInt(cr, Settings.Global.NETWORK_RECOMMENDATIONS_ENABLED, 1);
-
- final NetworkScorerAppData activeScorer = mNetworkScorerAppManager.getActiveScorer();
- assertNotNull(activeScorer);
- assertEquals(recoComponent, activeScorer.getRecommendationServiceComponent());
- assertEquals(924, activeScorer.packageUid);
- }
-
- public void testGetActiveScorer_providerNotAvailable()
- throws Exception {
- ContentResolver cr = mTargetContext.getContentResolver();
- Settings.Global.putInt(cr, Settings.Global.NETWORK_RECOMMENDATIONS_ENABLED, 1);
-
- final NetworkScorerAppData activeScorer = mNetworkScorerAppManager.getActiveScorer();
- assertNull(activeScorer);
- }
-
- public void testGetActiveScorer_recommendationsDisabled() throws Exception {
- final ComponentName recoComponent = new ComponentName("package1", "class1");
- setNetworkRecommendationPackageNames(recoComponent.getPackageName());
- mockScoreNetworksGranted(recoComponent.getPackageName());
- mockRecommendationServiceAvailable(recoComponent, 924 /* packageUid */);
- ContentResolver cr = mTargetContext.getContentResolver();
- Settings.Global.putInt(cr, Settings.Global.NETWORK_RECOMMENDATIONS_ENABLED, 0);
-
- final NetworkScorerAppData activeScorer = mNetworkScorerAppManager.getActiveScorer();
- assertNull(activeScorer);
- }
-
- private void setNetworkRecommendationPackageNames(String... names) {
- if (names == null) {
- names = new String[0];
- }
- when(mResources.getStringArray(R.array.config_networkRecommendationPackageNames))
- .thenReturn(names);
- }
-
- private void mockScoreNetworksGranted(String packageName) {
- when(mMockPm.checkPermission(permission.SCORE_NETWORKS, packageName))
- .thenReturn(PackageManager.PERMISSION_GRANTED);
- }
-
- private void mockScoreNetworksDenied(String packageName) {
- when(mMockPm.checkPermission(permission.SCORE_NETWORKS, packageName))
- .thenReturn(PackageManager.PERMISSION_DENIED);
- }
-
- private void mockRecommendationServiceAvailable(final ComponentName compName, int packageUid) {
- final ResolveInfo serviceInfo = new ResolveInfo();
- serviceInfo.serviceInfo = new ServiceInfo();
- serviceInfo.serviceInfo.name = compName.getClassName();
- serviceInfo.serviceInfo.packageName = compName.getPackageName();
- serviceInfo.serviceInfo.applicationInfo = new ApplicationInfo();
- serviceInfo.serviceInfo.applicationInfo.uid = packageUid;
-
- final int flags = 0;
- when(mMockPm.resolveService(
- Mockito.argThat(new ArgumentMatcher<Intent>() {
- @Override
- public boolean matches(Object object) {
- Intent intent = (Intent) object;
- return NetworkScoreManager.ACTION_RECOMMEND_NETWORKS
- .equals(intent.getAction())
- && compName.getPackageName().equals(intent.getPackage());
- }
- }), Mockito.eq(flags))).thenReturn(serviceInfo);
- }
-}
diff --git a/core/tests/coretests/src/android/os/FileUtilsTest.java b/core/tests/coretests/src/android/os/FileUtilsTest.java
index bd90079..5c7da70 100644
--- a/core/tests/coretests/src/android/os/FileUtilsTest.java
+++ b/core/tests/coretests/src/android/os/FileUtilsTest.java
@@ -311,6 +311,28 @@
assertNameEquals("test.foo (1).bar", FileUtils.buildUniqueFile(mTarget, "test.foo.bar"));
}
+ public void testRoundStorageSize() throws Exception {
+ final long M128 = 134217728L;
+ final long M256 = M128 * 2;
+ final long M512 = M256 * 2;
+ final long M1024 = M512 * 2;
+ final long G16 = M1024 * 16;
+ final long G32 = M1024 * 32;
+ final long G64 = M1024 * 64;
+
+ assertEquals(M128, FileUtils.roundStorageSize(M128));
+ assertEquals(M256, FileUtils.roundStorageSize(M128 + 1));
+ assertEquals(M256, FileUtils.roundStorageSize(M256 - 1));
+ assertEquals(M256, FileUtils.roundStorageSize(M256));
+ assertEquals(M512, FileUtils.roundStorageSize(M256 + 1));
+
+ assertEquals(G16, FileUtils.roundStorageSize(G16));
+ assertEquals(G32, FileUtils.roundStorageSize(G16 + 1));
+ assertEquals(G32, FileUtils.roundStorageSize(G32 - 1));
+ assertEquals(G32, FileUtils.roundStorageSize(G32));
+ assertEquals(G64, FileUtils.roundStorageSize(G32 + 1));
+ }
+
private static void assertNameEquals(String expected, File actual) {
assertEquals(expected, actual.getName());
}
diff --git a/core/tests/coretests/src/android/provider/SettingsBackupTest.java b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
index da6a294..105a351 100644
--- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java
+++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
@@ -281,6 +281,7 @@
Settings.Global.RADIO_NFC,
Settings.Global.RADIO_WIFI,
Settings.Global.RADIO_WIMAX,
+ Settings.Global.RECOMMENDED_NETWORK_EVALUATOR_CACHE_EXPIRY_MS,
Settings.Global.READ_EXTERNAL_STORAGE_ENFORCED_DEFAULT,
Settings.Global.REQUIRE_PASSWORD_TO_DECRYPT,
Settings.Global.RETAIL_DEMO_MODE_CONSTANTS,
@@ -393,6 +394,7 @@
Settings.Secure.BACKUP_TRANSPORT,
Settings.Secure.BLUETOOTH_HCI_LOG,
Settings.Secure.CARRIER_APPS_HANDLED,
+ Settings.Secure.CMAS_ADDITIONAL_BROADCAST_PKG,
Settings.Secure.COMPLETED_CATEGORY_PREFIX,
Settings.Secure.CONNECTIVITY_RELEASE_PENDING_INTENT_DELAY_MS,
Settings.Secure.DEFAULT_INPUT_METHOD,
diff --git a/graphics/tests/graphicstests/src/android/view/MockView.java b/core/tests/coretests/src/android/view/MockView.java
similarity index 100%
rename from graphics/tests/graphicstests/src/android/view/MockView.java
rename to core/tests/coretests/src/android/view/MockView.java
diff --git a/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java b/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java
index 1080a9f..3dfecc6 100644
--- a/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java
+++ b/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java
@@ -16,6 +16,17 @@
package com.android.internal.app;
+import android.app.Instrumentation;
+import android.content.ComponentName;
+import android.content.IntentFilter;
+import android.content.pm.ActivityInfo;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.LauncherApps;
+import android.content.pm.PackageManager;
+import android.content.pm.ShortcutInfo;
+import android.content.pm.ShortcutManager;
+import android.graphics.drawable.Icon;
+import android.os.SystemClock;
import com.android.internal.R;
import com.android.internal.app.ResolverActivity.ResolvedComponentInfo;
@@ -48,25 +59,31 @@
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.not;
import static org.hamcrest.MatcherAssert.assertThat;
-import static org.mockito.Mockito.when;
-import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.isA;
+import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
/**
* Chooser activity instrumentation tests
*/
@RunWith(AndroidJUnit4.class)
public class ChooserActivityTest {
+ private Instrumentation instrumentation;
+
+ @Before
+ public void setUp() {
+ instrumentation = InstrumentationRegistry.getInstrumentation();
+ sOverrides.reset();
+ }
+
@Rule
public ActivityTestRule<ChooserWrapperActivity> mActivityRule =
new ActivityTestRule<>(ChooserWrapperActivity.class, false,
false);
- @Before
- public void cleanOverrideData() {
- sOverrides.reset();
- }
-
@Test
public void customTitle() throws InterruptedException {
Intent sendIntent = createSendImageIntent();
@@ -235,7 +252,6 @@
chosen[0] = targetInfo.getResolveInfo();
return true;
};
-
// Make a stable copy of the components as the original list may be modified
List<ResolvedComponentInfo> stableCopy =
createResolvedComponentsForTestWithOtherProfile(2);
@@ -324,6 +340,32 @@
assertThat(chosen[0], is(toChoose));
}
+ public void pushedChooserTarget() {
+ ResolveInfo[] chosen = new ResolveInfo[1];
+ sOverrides.onSafelyStartCallback = targetInfo -> {
+ chosen[0] = targetInfo.getResolveInfo();
+ return true;
+ };
+
+ setChooserShortcuts(1);
+ List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2);
+ when(sOverrides.resolverListController.getResolversForIntent(Mockito.anyBoolean(),
+ Mockito.anyBoolean(),
+ Mockito.isA(List.class))).thenReturn(resolvedComponentInfos);
+
+ Intent sendIntent = createSendImageIntent();
+ final ChooserWrapperActivity activity = mActivityRule
+ .launchActivity(Intent.createChooser(sendIntent, null));
+
+ waitForIdle();
+
+ onView(withText("short chooser label 0"))
+ .perform(click());
+ waitForIdle();
+ assertThat(chosen[0].resolvePackageName,
+ is(ResolverDataProvider.createActivityInfo(0).packageName));
+ }
+
private Intent createSendImageIntent() {
Intent sendIntent = new Intent();
sendIntent.setAction(Intent.ACTION_SEND);
@@ -371,4 +413,48 @@
}
return packageStats.mChooserCounts.get(action).getOrDefault(annotation, 0);
}
+
+ private void setChooserShortcuts(int numShortcuts) {
+ ArrayList<ShortcutInfo> shortcuts = new ArrayList<>();
+ for (int i = 0; i < numShortcuts; i++) {
+ shortcuts.add(makeShortcut(i));
+ }
+ when(sOverrides.launcherApps.getShortcuts(
+ Mockito.isA(LauncherApps.ShortcutQuery.class),
+ Mockito.eq(UserHandle.SYSTEM)))
+ .thenReturn(shortcuts);
+ }
+
+ private ShortcutInfo makeShortcut(int i) {
+ try {
+ IntentFilter filter = new IntentFilter(Intent.ACTION_SEND, "image/jpeg");
+
+ ComponentName component = new ComponentName("foo.bar", "foo.bar" + ".MainActivity");
+ ShortcutInfo.Builder b = new ShortcutInfo.Builder(instrumentation.getContext(), "" + i)
+ .setActivity(component)
+ .setShortLabel("short chooser label " + i)
+ .setLongLabel("long chooser label" + i)
+ .setRank(i)
+ .setIntent(createSendImageIntent())
+ .setIcon(Icon.createWithResource(instrumentation.getContext(),
+ android.R.drawable.ic_menu_add))
+ .addChooserIntentFilter(
+ filter,
+ component);
+
+ sOverrides.createPackageManager = pm -> {
+ final PackageManager spied = spy(pm);
+ try {
+ doAnswer(invocation -> ResolverDataProvider.createActivityInfo(i))
+ .when(spied).getActivityInfo(
+ Mockito.isA(ComponentName.class), Mockito.anyInt());
+ } catch (Exception e) {
+ // this is ok, just not found
+ e.printStackTrace();
+ }
+ return spied;
+ };
+ return b.build();
+ } catch (Exception e) {return null;}
+ }
}
\ No newline at end of file
diff --git a/core/tests/coretests/src/com/android/internal/app/ChooserWrapperActivity.java b/core/tests/coretests/src/com/android/internal/app/ChooserWrapperActivity.java
index c446f3c..0dac260 100644
--- a/core/tests/coretests/src/com/android/internal/app/ChooserWrapperActivity.java
+++ b/core/tests/coretests/src/com/android/internal/app/ChooserWrapperActivity.java
@@ -18,6 +18,7 @@
import android.app.usage.UsageStatsManager;
import android.content.Context;
+import android.content.pm.LauncherApps;
import android.content.pm.PackageManager;
import java.util.function.Function;
@@ -74,6 +75,11 @@
return super.getPackageManager();
}
+ @Override
+ public LauncherApps getLauncherApps() {
+ return sOverrides.launcherApps;
+ }
+
/**
* We cannot directly mock the activity created since instrumentation creates it.
* <p>
@@ -82,6 +88,7 @@
static class OverrideData {
@SuppressWarnings("Since15")
public Function<PackageManager, PackageManager> createPackageManager;
+ public LauncherApps launcherApps;
public Function<TargetInfo, Boolean> onSafelyStartCallback;
public ResolverListController resolverListController;
public Boolean isVoiceInteraction;
@@ -90,6 +97,7 @@
onSafelyStartCallback = null;
isVoiceInteraction = null;
createPackageManager = null;
+ launcherApps = mock(LauncherApps.class);
resolverListController = mock(ResolverListController.class);
}
}
diff --git a/data/etc/platform.xml b/data/etc/platform.xml
index 344f3c8..6248856 100644
--- a/data/etc/platform.xml
+++ b/data/etc/platform.xml
@@ -60,7 +60,6 @@
</permission>
<permission name="android.permission.WRITE_MEDIA_STORAGE" >
- <group gid="media_rw" />
<group gid="sdcard_rw" />
</permission>
diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index 5226fe5..bf3e793 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -253,6 +253,7 @@
<permission name="android.permission.BIND_APPWIDGET"/>
<permission name="android.permission.CHANGE_COMPONENT_ENABLED_STATE"/>
<permission name="android.permission.CHANGE_CONFIGURATION"/>
+ <permission name="android.permission.CHANGE_OVERLAY_PACKAGES"/>
<permission name="android.permission.CONNECTIVITY_INTERNAL"/>
<permission name="android.permission.DELETE_CACHE_FILES"/>
<permission name="android.permission.DELETE_PACKAGES"/>
diff --git a/data/fonts/fonts.xml b/data/fonts/fonts.xml
index d8e6db7..76598a0 100644
--- a/data/fonts/fonts.xml
+++ b/data/fonts/fonts.xml
@@ -1,8 +1,22 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
- All fonts without names are added to the default list. Fonts are chosen
- based on a match: full BCP-47 language tag including script, then just
- language, and finally order (the first font containing the glyph).
+ WARNING: Parsing of this file by third-party apps is not supported. The
+ file, and the font files it refers to, will be renamed and/or moved out
+ from their respective location in the next Android release, and/or the
+ format or syntax of the file may change significantly. You must not
+ parse this file for information about system fonts. Instead, you must
+ call android.text.FontManager#getSystemFonts(). For example, it can be
+ called as context.getSystemService(FontManager.class).getSystemFonts().
+ Note that the returned FontConfig includes data on all the defined font
+ families and all the details about weight, style, etc. It also provides
+ an open file descriptor to each font file. Note that callers of the API
+ should ensure they close the given file descriptors once they are done
+ using them.
+
+ In this file, all fonts without names are added to the default list.
+ Fonts are chosen based on a match: full BCP-47 language tag including
+ script, then just language, and finally order (the first font containing
+ the glyph).
Order of appearance is also the tiebreaker for weight matching. This is
the reason why the 900 weights of Roboto precede the 700 weights - we
diff --git a/graphics/java/android/graphics/Color.java b/graphics/java/android/graphics/Color.java
index ff21cac..33d19d4 100644
--- a/graphics/java/android/graphics/Color.java
+++ b/graphics/java/android/graphics/Color.java
@@ -1023,9 +1023,9 @@
"The color space must use a color model with at most 3 components");
}
- @HalfFloat short r = Half.valueOf(red);
- @HalfFloat short g = Half.valueOf(green);
- @HalfFloat short b = Half.valueOf(blue);
+ @HalfFloat short r = Half.toHalf(red);
+ @HalfFloat short g = Half.toHalf(green);
+ @HalfFloat short b = Half.toHalf(blue);
int a = (int) (Math.max(0.0f, Math.min(alpha, 1.0f)) * 1023.0f + 0.5f);
diff --git a/graphics/java/android/graphics/ColorSpace.java b/graphics/java/android/graphics/ColorSpace.java
index ec00c45..b1a433c 100644
--- a/graphics/java/android/graphics/ColorSpace.java
+++ b/graphics/java/android/graphics/ColorSpace.java
@@ -805,7 +805,8 @@
*/
public enum Adaptation {
/**
- * Bradford matrix for the von Kries chromatic adaptation transform.
+ * Bradford chromatic adaptation transform, as defined in the
+ * CIECAM97s color appearance model.
*/
BRADFORD(new float[] {
0.8951f, -0.7502f, 0.0389f,
@@ -813,12 +814,21 @@
-0.1614f, 0.0367f, 1.0296f
}),
/**
- * von Kries matrix for the von Kries chromatic adaptation transform.
+ * von Kries chromatic adaptation transform.
*/
VON_KRIES(new float[] {
0.40024f, -0.22630f, 0.00000f,
0.70760f, 1.16532f, 0.00000f,
-0.08081f, 0.04570f, 0.91822f
+ }),
+ /**
+ * CIECAT02 chromatic adaption transform, as defined in the
+ * CIECAM02 color appearance model.
+ */
+ CIECAT02(new float[] {
+ 0.7328f, -0.7036f, 0.0030f,
+ 0.4296f, 1.6975f, 0.0136f,
+ -0.1624f, 0.0061f, 0.9834f
});
final float[] mTransform;
diff --git a/graphics/java/android/graphics/drawable/ShapeDrawable.java b/graphics/java/android/graphics/drawable/ShapeDrawable.java
index fe82a93..a24b970 100644
--- a/graphics/java/android/graphics/drawable/ShapeDrawable.java
+++ b/graphics/java/android/graphics/drawable/ShapeDrawable.java
@@ -16,9 +16,11 @@
package android.graphics.drawable;
+import android.annotation.NonNull;
import android.content.pm.ActivityInfo.Config;
import android.content.res.ColorStateList;
import android.content.res.Resources;
+import android.content.res.Resources.Theme;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.ColorFilter;
@@ -31,10 +33,10 @@
import android.graphics.Rect;
import android.graphics.Shader;
import android.graphics.drawable.shapes.Shape;
-import android.content.res.Resources.Theme;
import android.util.AttributeSet;
import com.android.internal.R;
+
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
@@ -69,7 +71,7 @@
* @attr ref android.R.styleable#ShapeDrawable_height
*/
public class ShapeDrawable extends Drawable {
- private ShapeState mShapeState;
+ private @NonNull ShapeState mShapeState;
private PorterDuffColorFilter mTintFilter;
private boolean mMutated;
@@ -77,7 +79,7 @@
* ShapeDrawable constructor.
*/
public ShapeDrawable() {
- this(new ShapeState(null), null);
+ this(new ShapeState(), null);
}
/**
@@ -86,7 +88,7 @@
* @param s the Shape that this ShapeDrawable should be
*/
public ShapeDrawable(Shape s) {
- this(new ShapeState(null), null);
+ this(new ShapeState(), null);
mShapeState.mShape = s;
}
@@ -402,7 +404,7 @@
}
// Update local properties.
- updateLocalState(r);
+ updateLocalState();
}
@Override
@@ -426,7 +428,7 @@
}
// Update local properties.
- updateLocalState(t.getResources());
+ updateLocalState();
}
private void updateStateFromTypedArray(TypedArray a) {
@@ -447,10 +449,10 @@
dither = a.getBoolean(R.styleable.ShapeDrawable_dither, dither);
paint.setDither(dither);
- setIntrinsicWidth((int) a.getDimension(
- R.styleable.ShapeDrawable_width, state.mIntrinsicWidth));
- setIntrinsicHeight((int) a.getDimension(
- R.styleable.ShapeDrawable_height, state.mIntrinsicHeight));
+ state.mIntrinsicWidth = (int) a.getDimension(
+ R.styleable.ShapeDrawable_width, state.mIntrinsicWidth);
+ state.mIntrinsicHeight = (int) a.getDimension(
+ R.styleable.ShapeDrawable_height, state.mIntrinsicHeight);
final int tintMode = a.getInt(R.styleable.ShapeDrawable_tintMode, -1);
if (tintMode != -1) {
@@ -494,21 +496,8 @@
@Override
public Drawable mutate() {
if (!mMutated && super.mutate() == this) {
- if (mShapeState.mPaint != null) {
- mShapeState.mPaint = new Paint(mShapeState.mPaint);
- } else {
- mShapeState.mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
- }
- if (mShapeState.mPadding != null) {
- mShapeState.mPadding = new Rect(mShapeState.mPadding);
- } else {
- mShapeState.mPadding = new Rect();
- }
- try {
- mShapeState.mShape = mShapeState.mShape.clone();
- } catch (CloneNotSupportedException e) {
- return null;
- }
+ mShapeState = new ShapeState(mShapeState);
+ updateLocalState();
mMutated = true;
}
return this;
@@ -525,12 +514,13 @@
/**
* Defines the intrinsic properties of this ShapeDrawable's Shape.
*/
- final static class ShapeState extends ConstantState {
- int[] mThemeAttrs;
+ static final class ShapeState extends ConstantState {
+ final @NonNull Paint mPaint;
+
@Config int mChangingConfigurations;
- Paint mPaint;
+ int[] mThemeAttrs;
Shape mShape;
- ColorStateList mTint = null;
+ ColorStateList mTint;
Mode mTintMode = DEFAULT_TINT_MODE;
Rect mPadding;
int mIntrinsicWidth;
@@ -538,21 +528,43 @@
int mAlpha = 255;
ShaderFactory mShaderFactory;
- ShapeState(ShapeState orig) {
- if (orig != null) {
- mThemeAttrs = orig.mThemeAttrs;
- mPaint = orig.mPaint;
- mShape = orig.mShape;
- mTint = orig.mTint;
- mTintMode = orig.mTintMode;
- mPadding = orig.mPadding;
- mIntrinsicWidth = orig.mIntrinsicWidth;
- mIntrinsicHeight = orig.mIntrinsicHeight;
- mAlpha = orig.mAlpha;
- mShaderFactory = orig.mShaderFactory;
- } else {
- mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+ /**
+ * Constructs a new ShapeState.
+ */
+ ShapeState() {
+ mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+ }
+
+ /**
+ * Constructs a new ShapeState that contains a deep copy of the
+ * specified ShapeState.
+ *
+ * @param orig the state to create a deep copy of
+ */
+ ShapeState(@NonNull ShapeState orig) {
+ mChangingConfigurations = orig.mChangingConfigurations;
+ mPaint = new Paint(orig.mPaint);
+ mThemeAttrs = orig.mThemeAttrs;
+ if (mShape != null) {
+ try {
+ mShape = orig.mShape.clone();
+ } catch (CloneNotSupportedException e) {
+ // Well, at least we tried.
+ mShape = orig.mShape;
+ }
}
+ mTint = orig.mTint;
+ mTintMode = orig.mTintMode;
+ if (orig.mPadding != null) {
+ mPadding = new Rect(orig.mPadding);
+ }
+ mIntrinsicWidth = orig.mIntrinsicWidth;
+ mIntrinsicHeight = orig.mIntrinsicHeight;
+ mAlpha = orig.mAlpha;
+
+ // We don't have any way to clone a shader factory, so hopefully
+ // this class doesn't contain any local state.
+ mShaderFactory = orig.mShaderFactory;
}
@Override
@@ -585,7 +597,7 @@
private ShapeDrawable(ShapeState state, Resources res) {
mShapeState = state;
- updateLocalState(res);
+ updateLocalState();
}
/**
@@ -593,7 +605,7 @@
* after significant state changes, e.g. from the One True Constructor and
* after inflating or applying a theme.
*/
- private void updateLocalState(Resources res) {
+ private void updateLocalState() {
mTintFilter = updateTintFilter(mTintFilter, mShapeState.mTint, mShapeState.mTintMode);
}
@@ -617,8 +629,4 @@
*/
public abstract Shader resize(int width, int height);
}
-
- // other subclass could wack the Shader's localmatrix based on the
- // resize params (e.g. scaletofit, etc.). This could be used to scale
- // a bitmap to fill the bounds without needing any other special casing.
}
diff --git a/graphics/java/android/graphics/drawable/shapes/ArcShape.java b/graphics/java/android/graphics/drawable/shapes/ArcShape.java
index c4b239f..85ba0a9 100644
--- a/graphics/java/android/graphics/drawable/shapes/ArcShape.java
+++ b/graphics/java/android/graphics/drawable/shapes/ArcShape.java
@@ -21,31 +21,47 @@
import android.graphics.Paint;
/**
- * Creates an arc shape. The arc shape starts at a specified
- * angle and sweeps clockwise, drawing slices of pie.
- * The arc can be drawn to a Canvas with its own draw() method,
- * but more graphical control is available if you instead pass
- * the ArcShape to a {@link android.graphics.drawable.ShapeDrawable}.
+ * Creates an arc shape. The arc shape starts at a specified angle and sweeps
+ * clockwise, drawing slices of pie.
+ * <p>
+ * The arc can be drawn to a {@link Canvas} with its own
+ * {@link #draw(Canvas, Paint)} method, but more graphical control is available
+ * if you instead pass the ArcShape to a
+ * {@link android.graphics.drawable.ShapeDrawable}.
*/
public class ArcShape extends RectShape {
- private float mStart;
- private float mSweep;
-
+ private final float mStartAngle;
+ private final float mSweepAngle;
+
/**
- * ArcShape constructor.
- *
+ * ArcShape constructor.
+ *
* @param startAngle the angle (in degrees) where the arc begins
- * @param sweepAngle the sweep angle (in degrees). Anything equal to or
+ * @param sweepAngle the sweep angle (in degrees). Anything equal to or
* greater than 360 results in a complete circle/oval.
*/
public ArcShape(float startAngle, float sweepAngle) {
- mStart = startAngle;
- mSweep = sweepAngle;
+ mStartAngle = startAngle;
+ mSweepAngle = sweepAngle;
}
-
+
+ /**
+ * @return the angle (in degrees) where the arc begins
+ */
+ public final float getStartAngle() {
+ return mStartAngle;
+ }
+
+ /**
+ * @return the sweep angle (in degrees)
+ */
+ public final float getSweepAngle() {
+ return mSweepAngle;
+ }
+
@Override
public void draw(Canvas canvas, Paint paint) {
- canvas.drawArc(rect(), mStart, mSweep, true, paint);
+ canvas.drawArc(rect(), mStartAngle, mSweepAngle, true, paint);
}
@Override
@@ -53,5 +69,10 @@
// Since we don't support concave outlines, arc shape does not attempt
// to provide an outline.
}
+
+ @Override
+ public ArcShape clone() throws CloneNotSupportedException {
+ return (ArcShape) super.clone();
+ }
}
diff --git a/graphics/java/android/graphics/drawable/shapes/OvalShape.java b/graphics/java/android/graphics/drawable/shapes/OvalShape.java
index c9473f0..fb87d28 100644
--- a/graphics/java/android/graphics/drawable/shapes/OvalShape.java
+++ b/graphics/java/android/graphics/drawable/shapes/OvalShape.java
@@ -22,7 +22,8 @@
import android.graphics.RectF;
/**
- * Defines an oval shape.
+ * Defines an oval shape.
+ * <p>
* The oval can be drawn to a Canvas with its own draw() method,
* but more graphical control is available if you instead pass
* the OvalShape to a {@link android.graphics.drawable.ShapeDrawable}.
@@ -42,5 +43,10 @@
outline.setOval((int) Math.ceil(rect.left), (int) Math.ceil(rect.top),
(int) Math.floor(rect.right), (int) Math.floor(rect.bottom));
}
+
+ @Override
+ public OvalShape clone() throws CloneNotSupportedException {
+ return (OvalShape) super.clone();
+ }
}
diff --git a/graphics/java/android/graphics/drawable/shapes/PathShape.java b/graphics/java/android/graphics/drawable/shapes/PathShape.java
index 30b7347..ce5552b 100644
--- a/graphics/java/android/graphics/drawable/shapes/PathShape.java
+++ b/graphics/java/android/graphics/drawable/shapes/PathShape.java
@@ -16,41 +16,44 @@
package android.graphics.drawable.shapes;
+import android.annotation.NonNull;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Path;
/**
* Creates geometric paths, utilizing the {@link android.graphics.Path} class.
+ * <p>
* The path can be drawn to a Canvas with its own draw() method,
* but more graphical control is available if you instead pass
* the PathShape to a {@link android.graphics.drawable.ShapeDrawable}.
*/
public class PathShape extends Shape {
- private Path mPath;
- private float mStdWidth;
- private float mStdHeight;
-
- private float mScaleX; // cached from onResize
- private float mScaleY; // cached from onResize
-
+ private final float mStdWidth;
+ private final float mStdHeight;
+
+ private Path mPath;
+
+ private float mScaleX; // cached from onResize
+ private float mScaleY; // cached from onResize
+
/**
* PathShape constructor.
- *
- * @param path a Path that defines the geometric paths for this shape
- * @param stdWidth the standard width for the shape. Any changes to the
- * width with resize() will result in a width scaled based
- * on the new width divided by this width.
- * @param stdHeight the standard height for the shape. Any changes to the
- * height with resize() will result in a height scaled based
- * on the new height divided by this height.
+ *
+ * @param path a Path that defines the geometric paths for this shape
+ * @param stdWidth the standard width for the shape. Any changes to the
+ * width with resize() will result in a width scaled based
+ * on the new width divided by this width.
+ * @param stdHeight the standard height for the shape. Any changes to the
+ * height with resize() will result in a height scaled based
+ * on the new height divided by this height.
*/
- public PathShape(Path path, float stdWidth, float stdHeight) {
+ public PathShape(@NonNull Path path, float stdWidth, float stdHeight) {
mPath = path;
mStdWidth = stdWidth;
mStdHeight = stdHeight;
}
-
+
@Override
public void draw(Canvas canvas, Paint paint) {
canvas.save();
@@ -58,7 +61,7 @@
canvas.drawPath(mPath, paint);
canvas.restore();
}
-
+
@Override
protected void onResize(float width, float height) {
mScaleX = width / mStdWidth;
@@ -67,7 +70,7 @@
@Override
public PathShape clone() throws CloneNotSupportedException {
- PathShape shape = (PathShape) super.clone();
+ final PathShape shape = (PathShape) super.clone();
shape.mPath = new Path(mPath);
return shape;
}
diff --git a/graphics/java/android/graphics/drawable/shapes/RectShape.java b/graphics/java/android/graphics/drawable/shapes/RectShape.java
index 04cf293..e339a21 100644
--- a/graphics/java/android/graphics/drawable/shapes/RectShape.java
+++ b/graphics/java/android/graphics/drawable/shapes/RectShape.java
@@ -23,6 +23,7 @@
/**
* Defines a rectangle shape.
+ * <p>
* The rectangle can be drawn to a Canvas with its own draw() method,
* but more graphical control is available if you instead pass
* the RectShape to a {@link android.graphics.drawable.ShapeDrawable}.
diff --git a/graphics/java/android/graphics/drawable/shapes/RoundRectShape.java b/graphics/java/android/graphics/drawable/shapes/RoundRectShape.java
index e5253b8..f5cbb24 100644
--- a/graphics/java/android/graphics/drawable/shapes/RoundRectShape.java
+++ b/graphics/java/android/graphics/drawable/shapes/RoundRectShape.java
@@ -16,6 +16,7 @@
package android.graphics.drawable.shapes;
+import android.annotation.Nullable;
import android.graphics.Canvas;
import android.graphics.Outline;
import android.graphics.Paint;
@@ -24,40 +25,41 @@
/**
* Creates a rounded-corner rectangle. Optionally, an inset (rounded) rectangle
- * can be included (to make a sort of "O" shape).
+ * can be included (to make a sort of "O" shape).
+ * <p>
* The rounded rectangle can be drawn to a Canvas with its own draw() method,
* but more graphical control is available if you instead pass
* the RoundRectShape to a {@link android.graphics.drawable.ShapeDrawable}.
*/
public class RoundRectShape extends RectShape {
private float[] mOuterRadii;
- private RectF mInset;
+ private RectF mInset;
private float[] mInnerRadii;
private RectF mInnerRect;
- private Path mPath; // this is what we actually draw
+ private Path mPath; // this is what we actually draw
/**
* RoundRectShape constructor.
+ * <p>
* Specifies an outer (round)rect and an optional inner (round)rect.
*
* @param outerRadii An array of 8 radius values, for the outer roundrect.
- * The first two floats are for the
- * top-left corner (remaining pairs correspond clockwise).
- * For no rounded corners on the outer rectangle,
- * pass null.
- * @param inset A RectF that specifies the distance from the inner
- * rect to each side of the outer rect.
- * For no inner, pass null.
+ * The first two floats are for the top-left corner
+ * (remaining pairs correspond clockwise). For no rounded
+ * corners on the outer rectangle, pass {@code null}.
+ * @param inset A RectF that specifies the distance from the inner
+ * rect to each side of the outer rect. For no inner, pass
+ * {@code null}.
* @param innerRadii An array of 8 radius values, for the inner roundrect.
- * The first two floats are for the
- * top-left corner (remaining pairs correspond clockwise).
- * For no rounded corners on the inner rectangle,
- * pass null.
- * If inset parameter is null, this parameter is ignored.
+ * The first two floats are for the top-left corner
+ * (remaining pairs correspond clockwise). For no rounded
+ * corners on the inner rectangle, pass {@code null}. If
+ * inset parameter is {@code null}, this parameter is
+ * ignored.
*/
- public RoundRectShape(float[] outerRadii, RectF inset,
- float[] innerRadii) {
+ public RoundRectShape(@Nullable float[] outerRadii, @Nullable RectF inset,
+ @Nullable float[] innerRadii) {
if (outerRadii != null && outerRadii.length < 8) {
throw new ArrayIndexOutOfBoundsException("outer radii must have >= 8 values");
}
@@ -97,8 +99,7 @@
final RectF rect = rect();
outline.setRoundRect((int) Math.ceil(rect.left), (int) Math.ceil(rect.top),
- (int) Math.floor(rect.right), (int) Math.floor(rect.bottom),
- radius);
+ (int) Math.floor(rect.right), (int) Math.floor(rect.bottom), radius);
}
@Override
@@ -128,7 +129,7 @@
@Override
public RoundRectShape clone() throws CloneNotSupportedException {
- RoundRectShape shape = (RoundRectShape) super.clone();
+ final RoundRectShape shape = (RoundRectShape) super.clone();
shape.mOuterRadii = mOuterRadii != null ? mOuterRadii.clone() : null;
shape.mInnerRadii = mInnerRadii != null ? mInnerRadii.clone() : null;
shape.mInset = new RectF(mInset);
diff --git a/graphics/java/android/graphics/drawable/shapes/Shape.java b/graphics/java/android/graphics/drawable/shapes/Shape.java
index eab8666..30b28f3 100644
--- a/graphics/java/android/graphics/drawable/shapes/Shape.java
+++ b/graphics/java/android/graphics/drawable/shapes/Shape.java
@@ -23,21 +23,25 @@
/**
* Defines a generic graphical "shape."
- * Any Shape can be drawn to a Canvas with its own draw() method,
- * but more graphical control is available if you instead pass
- * it to a {@link android.graphics.drawable.ShapeDrawable}.
+ * <p>
+ * Any Shape can be drawn to a Canvas with its own draw() method, but more
+ * graphical control is available if you instead pass it to a
+ * {@link android.graphics.drawable.ShapeDrawable}.
+ * <p>
+ * Custom Shape classes must implement {@link #clone()} and return an instance
+ * of the custom Shape class.
*/
public abstract class Shape implements Cloneable {
private float mWidth;
private float mHeight;
-
+
/**
* Returns the width of the Shape.
*/
public final float getWidth() {
return mWidth;
}
-
+
/**
* Returns the height of the Shape.
*/
@@ -46,9 +50,10 @@
}
/**
- * Draw this shape into the provided Canvas, with the provided Paint.
+ * Draws this shape into the provided Canvas, with the provided Paint.
+ * <p>
* Before calling this, you must call {@link #resize(float,float)}.
- *
+ *
* @param canvas the Canvas within which this shape should be drawn
* @param paint the Paint object that defines this shape's characteristics
*/
@@ -56,8 +61,9 @@
/**
* Resizes the dimensions of this shape.
+ * <p>
* Must be called before {@link #draw(Canvas,Paint)}.
- *
+ *
* @param width the width of the shape (in pixels)
* @param height the height of the shape (in pixels)
*/
@@ -74,30 +80,34 @@
onResize(width, height);
}
}
-
+
/**
* Checks whether the Shape is opaque.
- * Default impl returns true. Override if your subclass can be opaque.
- *
- * @return true if any part of the drawable is <em>not</em> opaque.
+ * <p>
+ * Default impl returns {@code true}. Override if your subclass can be
+ * opaque.
+ *
+ * @return true if any part of the drawable is <em>not</em> opaque.
*/
public boolean hasAlpha() {
return true;
}
-
+
/**
* Callback method called when {@link #resize(float,float)} is executed.
- *
+ *
* @param width the new width of the Shape
* @param height the new height of the Shape
*/
protected void onResize(float width, float height) {}
/**
- * Compute the Outline of the shape and return it in the supplied Outline
- * parameter. The default implementation does nothing and {@code outline} is not changed.
+ * Computes the Outline of the shape and return it in the supplied Outline
+ * parameter. The default implementation does nothing and {@code outline}
+ * is not changed.
*
- * @param outline The Outline to be populated with the result. Should not be null.
+ * @param outline the Outline to be populated with the result. Must be
+ * non-{@code null}.
*/
public void getOutline(@NonNull Outline outline) {}
@@ -105,5 +115,4 @@
public Shape clone() throws CloneNotSupportedException {
return (Shape) super.clone();
}
-
}
diff --git a/graphics/tests/graphicstests/Android.mk b/graphics/tests/graphicstests/Android.mk
deleted file mode 100644
index 8ea44bd..0000000
--- a/graphics/tests/graphicstests/Android.mk
+++ /dev/null
@@ -1,15 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-# We only want this apk build for tests.
-LOCAL_MODULE_TAGS := tests
-
-# Include all test java files.
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_JAVA_LIBRARIES := android.test.runner
-LOCAL_STATIC_JAVA_LIBRARIES := junit legacy-android-test
-LOCAL_PACKAGE_NAME := FrameworksGraphicsTests
-
-include $(BUILD_PACKAGE)
-
diff --git a/graphics/tests/graphicstests/AndroidManifest.xml b/graphics/tests/graphicstests/AndroidManifest.xml
deleted file mode 100644
index e019e28..0000000
--- a/graphics/tests/graphicstests/AndroidManifest.xml
+++ /dev/null
@@ -1,38 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2008 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.frameworks.graphicstests">
- <uses-permission android:name="android.permission.RECEIVE_SMS"/>
- <uses-permission android:name="android.permission.INTERNET" />
- <uses-permission android:name="android.permission.READ_CONTACTS" />
- <uses-permission android:name="android.permission.WRITE_CONTACTS" />
- <uses-permission android:name="android.permission.WAKE_LOCK" />
- <uses-permission android:name="android.permission.CHANGE_CONFIGURATION" />
- <uses-permission android:name="android.permission.WRITE_APN_SETTINGS" />
- <uses-permission android:name="android.permission.BROADCAST_STICKY" />
- <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
-
-
- <application>
- <uses-library android:name="android.test.runner" />
- </application>
-
- <instrumentation
- android:name="android.test.InstrumentationTestRunner"
- android:targetPackage="com.android.frameworks.graphicstests"
- android:label="Frameworks Graphics Tests" />
-</manifest>
diff --git a/graphics/tests/graphicstests/res/values/colors.xml b/graphics/tests/graphicstests/res/values/colors.xml
deleted file mode 100644
index 7559e65..0000000
--- a/graphics/tests/graphicstests/res/values/colors.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
--->
-<resources>
- <color name="testcolor1">#ff00ff00</color>
- <color name="testcolor2">#ffff0000</color>
- <color name="failColor">#ff0000ff</color>
-</resources>
-
diff --git a/graphics/tests/graphicstests/src/android/graphics/PaintTest.java b/graphics/tests/graphicstests/src/android/graphics/PaintTest.java
deleted file mode 100644
index 318bfb6..0000000
--- a/graphics/tests/graphicstests/src/android/graphics/PaintTest.java
+++ /dev/null
@@ -1,230 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.graphics;
-
-import android.test.AndroidTestCase;
-
-public class PaintTest extends AndroidTestCase {
- public void testGetTextRunAdvances() {
- {
- // LTR
- String text = "abcdef";
- assertGetTextRunAdvances(text, 0, text.length(), 0, text.length(), false, true);
- assertGetTextRunAdvances(text, 1, text.length() - 1, 0, text.length(), false, false);
- }
- {
- // RTL
- final String text =
- "\u0645\u0627\u0020\u0647\u064A\u0020\u0627\u0644\u0634" +
- "\u0641\u0631\u0629\u0020\u0627\u0644\u0645\u0648\u062D" +
- "\u062F\u0629\u0020\u064A\u0648\u0646\u064A\u0643\u0648" +
- "\u062F\u061F";
- assertGetTextRunAdvances(text, 0, text.length(), 0, text.length(), true, true);
- assertGetTextRunAdvances(text, 1, text.length() - 1, 0, text.length(), true, false);
- }
- }
-
- private void assertGetTextRunAdvances(String str, int start, int end,
- int contextStart, int contextEnd, boolean isRtl, boolean compareWithOtherMethods) {
- Paint p = new Paint();
-
- final int count = end - start;
- final float[][] advanceArrays = new float[4][count];
-
- final float advance = p.getTextRunAdvances(str, start, end, contextStart, contextEnd,
- isRtl, advanceArrays[0], 0);
-
- char chars[] = str.toCharArray();
- final float advance_c = p.getTextRunAdvances(chars, start, count, contextStart,
- contextEnd - contextStart, isRtl, advanceArrays[1], 0);
- assertEquals(advance, advance_c, 1.0f);
-
- for (int c = 1; c < count; ++c) {
- final float firstPartAdvance = p.getTextRunAdvances(str, start, start + c,
- contextStart, contextEnd, isRtl, advanceArrays[2], 0);
- final float secondPartAdvance = p.getTextRunAdvances(str, start + c, end,
- contextStart, contextEnd, isRtl, advanceArrays[2], c);
- assertEquals(advance, firstPartAdvance + secondPartAdvance, 1.0f);
-
-
- final float firstPartAdvance_c = p.getTextRunAdvances(chars, start, c,
- contextStart, contextEnd - contextStart, isRtl, advanceArrays[3], 0);
- final float secondPartAdvance_c = p.getTextRunAdvances(chars, start + c,
- count - c, contextStart, contextEnd - contextStart, isRtl,
- advanceArrays[3], c);
- assertEquals(advance, firstPartAdvance_c + secondPartAdvance_c, 1.0f);
- assertEquals(firstPartAdvance, firstPartAdvance_c, 1.0f);
- assertEquals(secondPartAdvance, secondPartAdvance_c, 1.0f);
-
- for (int i = 1; i < advanceArrays.length; i++) {
- for (int j = 0; j < count; j++) {
- assertEquals(advanceArrays[0][j], advanceArrays[i][j], 1.0f);
- }
- }
-
- // Compare results with measureText, getRunAdvance, and getTextWidths.
- if (compareWithOtherMethods && start == contextStart && end == contextEnd) {
- assertEquals(advance, p.measureText(str, start, end), 1.0f);
- assertEquals(advance, p.getRunAdvance(
- str, start, end, contextStart, contextEnd, isRtl, end), 1.0f);
-
- final float[] widths = new float[count];
- p.getTextWidths(str, start, end, widths);
- for (int i = 0; i < count; i++) {
- assertEquals(advanceArrays[0][i], widths[i], 1.0f);
- }
- }
- }
- }
-
- public void testGetTextRunAdvances_invalid() {
- Paint p = new Paint();
- String text = "test";
-
- try {
- p.getTextRunAdvances((String)null, 0, 0, 0, 0, false, null, 0);
- fail("Should throw an IllegalArgumentException.");
- } catch (IllegalArgumentException e) {
- }
-
- try {
- p.getTextRunAdvances((CharSequence)null, 0, 0, 0, 0, false, null, 0);
- fail("Should throw an IllegalArgumentException.");
- } catch (IllegalArgumentException e) {
- }
-
- try {
- p.getTextRunAdvances((char[])null, 0, 0, 0, 0, false, null, 0);
- fail("Should throw an IllegalArgumentException.");
- } catch (IllegalArgumentException e) {
- }
-
- try {
- p.getTextRunAdvances(text, 0, text.length(), 0, text.length(), false,
- new float[text.length() - 1], 0);
- fail("Should throw an IndexOutOfBoundsException.");
- } catch (IndexOutOfBoundsException e) {
- }
-
- try {
- p.getTextRunAdvances(text, 0, text.length(), 0, text.length(), false,
- new float[text.length()], 1);
- fail("Should throw an IndexOutOfBoundsException.");
- } catch (IndexOutOfBoundsException e) {
- }
-
- // 0 > contextStart
- try {
- p.getTextRunAdvances(text, 0, text.length(), -1, text.length(), false, null, 0);
- fail("Should throw an IndexOutOfBoundsException.");
- } catch (IndexOutOfBoundsException e) {
- }
-
- // contextStart > start
- try {
- p.getTextRunAdvances(text, 0, text.length(), 1, text.length(), false, null, 0);
- fail("Should throw an IndexOutOfBoundsException.");
- } catch (IndexOutOfBoundsException e) {
- }
-
- // start > end
- try {
- p.getTextRunAdvances(text, 1, 0, 0, text.length(), false, null, 0);
- fail("Should throw an IndexOutOfBoundsException.");
- } catch (IndexOutOfBoundsException e) {
- }
-
- // end > contextEnd
- try {
- p.getTextRunAdvances(text, 0, text.length(), 0, text.length() - 1, false, null, 0);
- fail("Should throw an IndexOutOfBoundsException.");
- } catch (IndexOutOfBoundsException e) {
- }
-
- // contextEnd > text.length
- try {
- p.getTextRunAdvances(text, 0, text.length(), 0, text.length() + 1, false, null, 0);
- fail("Should throw an IndexOutOfBoundsException.");
- } catch (IndexOutOfBoundsException e) {
- }
- }
-
- public void testMeasureTextBidi() {
- Paint p = new Paint();
- {
- String bidiText = "abc \u0644\u063A\u0629 def";
- p.setBidiFlags(Paint.BIDI_LTR);
- float width = p.measureText(bidiText, 0, 4);
- p.setBidiFlags(Paint.BIDI_RTL);
- width += p.measureText(bidiText, 4, 7);
- p.setBidiFlags(Paint.BIDI_LTR);
- width += p.measureText(bidiText, 7, bidiText.length());
- assertEquals(width, p.measureText(bidiText), 1.0f);
- }
- {
- String bidiText = "abc \u0644\u063A\u0629 def";
- p.setBidiFlags(Paint.BIDI_DEFAULT_LTR);
- float width = p.measureText(bidiText, 0, 4);
- width += p.measureText(bidiText, 4, 7);
- width += p.measureText(bidiText, 7, bidiText.length());
- assertEquals(width, p.measureText(bidiText), 1.0f);
- }
- {
- String bidiText = "abc \u0644\u063A\u0629 def";
- p.setBidiFlags(Paint.BIDI_FORCE_LTR);
- float width = p.measureText(bidiText, 0, 4);
- width += p.measureText(bidiText, 4, 7);
- width += p.measureText(bidiText, 7, bidiText.length());
- assertEquals(width, p.measureText(bidiText), 1.0f);
- }
- {
- String bidiText = "\u0644\u063A\u0629 abc \u0644\u063A\u0629";
- p.setBidiFlags(Paint.BIDI_RTL);
- float width = p.measureText(bidiText, 0, 4);
- p.setBidiFlags(Paint.BIDI_LTR);
- width += p.measureText(bidiText, 4, 7);
- p.setBidiFlags(Paint.BIDI_RTL);
- width += p.measureText(bidiText, 7, bidiText.length());
- assertEquals(width, p.measureText(bidiText), 1.0f);
- }
- {
- String bidiText = "\u0644\u063A\u0629 abc \u0644\u063A\u0629";
- p.setBidiFlags(Paint.BIDI_DEFAULT_RTL);
- float width = p.measureText(bidiText, 0, 4);
- width += p.measureText(bidiText, 4, 7);
- width += p.measureText(bidiText, 7, bidiText.length());
- assertEquals(width, p.measureText(bidiText), 1.0f);
- }
- {
- String bidiText = "\u0644\u063A\u0629 abc \u0644\u063A\u0629";
- p.setBidiFlags(Paint.BIDI_FORCE_RTL);
- float width = p.measureText(bidiText, 0, 4);
- width += p.measureText(bidiText, 4, 7);
- width += p.measureText(bidiText, 7, bidiText.length());
- assertEquals(width, p.measureText(bidiText), 1.0f);
- }
- }
-
- public void testSetGetWordSpacing() {
- Paint p = new Paint();
- assertEquals(0.0f, p.getWordSpacing()); // The default value should be 0.
- p.setWordSpacing(1.0f);
- assertEquals(1.0f, p.getWordSpacing());
- p.setWordSpacing(-2.0f);
- assertEquals(-2.0f, p.getWordSpacing());
- }
-}
diff --git a/keystore/java/android/security/IKeyChainAliasCallback.aidl b/keystore/java/android/security/IKeyChainAliasCallback.aidl
index 1ea9521..b9d3753 100644
--- a/keystore/java/android/security/IKeyChainAliasCallback.aidl
+++ b/keystore/java/android/security/IKeyChainAliasCallback.aidl
@@ -20,7 +20,7 @@
*
* @hide
*/
-interface IKeyChainAliasCallback {
+oneway interface IKeyChainAliasCallback {
void alias(String alias);
}
diff --git a/keystore/java/android/security/IKeyChainService.aidl b/keystore/java/android/security/IKeyChainService.aidl
index deea972..b685431 100644
--- a/keystore/java/android/security/IKeyChainService.aidl
+++ b/keystore/java/android/security/IKeyChainService.aidl
@@ -15,7 +15,7 @@
*/
package android.security;
-import android.content.pm.ParceledListSlice;
+import android.content.pm.StringParceledListSlice;
/**
* Caller is required to ensure that {@link KeyStore#unlock
@@ -39,8 +39,8 @@
// APIs used by Settings
boolean deleteCaCertificate(String alias);
boolean reset();
- ParceledListSlice getUserCaAliases();
- ParceledListSlice getSystemCaAliases();
+ StringParceledListSlice getUserCaAliases();
+ StringParceledListSlice getSystemCaAliases();
boolean containsCaAlias(String alias);
byte[] getEncodedCaCertificate(String alias, boolean includeDeletedSystem);
List<String> getCaCertificateChainAliases(String rootAlias, boolean includeDeletedSystem);
diff --git a/legacy-test/Android.mk b/legacy-test/Android.mk
index 0a814f3..05fec5e 100644
--- a/legacy-test/Android.mk
+++ b/legacy-test/Android.mk
@@ -50,5 +50,5 @@
LOCAL_SRC_FILES := src/android/test/PerformanceTestCase.java
LOCAL_MODULE := legacy-performance-test-hostdex
-include $(BUILD_HOST_DALVIK_JAVA_LIBRARY)
+include $(BUILD_HOST_DALVIK_STATIC_JAVA_LIBRARY)
endif # HOST_OS == linux
diff --git a/libs/androidfw/AssetManager.cpp b/libs/androidfw/AssetManager.cpp
index acacd76..84111ae 100644
--- a/libs/androidfw/AssetManager.cpp
+++ b/libs/androidfw/AssetManager.cpp
@@ -202,15 +202,6 @@
*cookie = static_cast<int32_t>(mAssetPaths.size());
}
-#ifdef __ANDROID__
- // Load overlays, if any
- asset_path oap;
- for (size_t idx = 0; mZipSet.getOverlay(ap.path, idx, &oap); idx++) {
- oap.isSystemAsset = isSystemAsset;
- mAssetPaths.add(oap);
- }
-#endif
-
if (mResources != NULL) {
appendPathToResTable(ap, appAsLib);
}
@@ -493,11 +484,6 @@
}
bool AssetManager::appendPathToResTable(const asset_path& ap, bool appAsLib) const {
- // skip those ap's that correspond to system overlays
- if (ap.isSystemOverlay) {
- return true;
- }
-
Asset* ass = NULL;
ResTable* sharedRes = NULL;
bool shared = true;
@@ -539,14 +525,6 @@
ALOGV("Creating shared resources for %s", ap.path.string());
sharedRes = new ResTable();
sharedRes->add(ass, idmap, nextEntryIdx + 1, false);
-#ifdef __ANDROID__
- const char* data = getenv("ANDROID_DATA");
- LOG_ALWAYS_FATAL_IF(data == NULL, "ANDROID_DATA not set");
- String8 overlaysListPath(data);
- overlaysListPath.appendPath(kResourceCache);
- overlaysListPath.appendPath("overlays.list");
- addSystemOverlays(overlaysListPath.string(), ap.path, sharedRes, nextEntryIdx);
-#endif
sharedRes = const_cast<AssetManager*>(this)->
mZipSet.setZipResourceTable(ap.path, sharedRes);
}
@@ -655,58 +633,6 @@
return ass;
}
-void AssetManager::addSystemOverlays(const char* pathOverlaysList,
- const String8& targetPackagePath, ResTable* sharedRes, size_t offset) const
-{
- FILE* fin = fopen(pathOverlaysList, "r");
- if (fin == NULL) {
- return;
- }
-
-#ifndef _WIN32
- if (TEMP_FAILURE_RETRY(flock(fileno(fin), LOCK_SH)) != 0) {
- fclose(fin);
- return;
- }
-#endif
- char buf[1024];
- while (fgets(buf, sizeof(buf), fin)) {
- // format of each line:
- // <path to apk><space><path to idmap><newline>
- char* space = strchr(buf, ' ');
- char* newline = strchr(buf, '\n');
- asset_path oap;
-
- if (space == NULL || newline == NULL || newline < space) {
- continue;
- }
-
- oap.path = String8(buf, space - buf);
- oap.type = kFileTypeRegular;
- oap.idmap = String8(space + 1, newline - space - 1);
- oap.isSystemOverlay = true;
-
- Asset* oass = const_cast<AssetManager*>(this)->
- openNonAssetInPathLocked("resources.arsc",
- Asset::ACCESS_BUFFER,
- oap);
-
- if (oass != NULL) {
- Asset* oidmap = openIdmapLocked(oap);
- offset++;
- sharedRes->add(oass, oidmap, offset + 1, false);
- const_cast<AssetManager*>(this)->mAssetPaths.add(oap);
- const_cast<AssetManager*>(this)->mZipSet.addOverlay(targetPackagePath, oap);
- delete oidmap;
- }
- }
-
-#ifndef _WIN32
- TEMP_FAILURE_RETRY(flock(fileno(fin), LOCK_UN));
-#endif
- fclose(fin);
-}
-
const ResTable& AssetManager::getResources(bool required) const
{
const ResTable* rt = getResTable(required);
@@ -1446,20 +1372,6 @@
return mModWhen == modWhen;
}
-void AssetManager::SharedZip::addOverlay(const asset_path& ap)
-{
- mOverlays.add(ap);
-}
-
-bool AssetManager::SharedZip::getOverlay(size_t idx, asset_path* out) const
-{
- if (idx >= mOverlays.size()) {
- return false;
- }
- *out = mOverlays[idx];
- return true;
-}
-
AssetManager::SharedZip::~SharedZip()
{
if (kIsDebug) {
@@ -1578,22 +1490,6 @@
return true;
}
-void AssetManager::ZipSet::addOverlay(const String8& path, const asset_path& overlay)
-{
- int idx = getIndex(path);
- sp<SharedZip> zip = mZipFile[idx];
- zip->addOverlay(overlay);
-}
-
-bool AssetManager::ZipSet::getOverlay(const String8& path, size_t idx, asset_path* out) const
-{
- sp<SharedZip> zip = SharedZip::get(path, false);
- if (zip == NULL) {
- return false;
- }
- return zip->getOverlay(idx, out);
-}
-
/*
* Compute the zip file's index.
*
diff --git a/libs/androidfw/include/androidfw/AssetManager.h b/libs/androidfw/include/androidfw/AssetManager.h
index becd307..f1e8b93 100644
--- a/libs/androidfw/include/androidfw/AssetManager.h
+++ b/libs/androidfw/include/androidfw/AssetManager.h
@@ -202,12 +202,10 @@
private:
struct asset_path
{
- asset_path() : path(""), type(kFileTypeRegular), idmap(""),
- isSystemOverlay(false), isSystemAsset(false) {}
+ asset_path() : path(""), type(kFileTypeRegular), idmap(""), isSystemAsset(false) {}
String8 path;
FileType type;
String8 idmap;
- bool isSystemOverlay;
bool isSystemAsset;
};
@@ -237,9 +235,6 @@
Asset* openIdmapLocked(const struct asset_path& ap) const;
- void addSystemOverlays(const char* pathOverlaysList, const String8& targetPackagePath,
- ResTable* sharedRes, size_t offset) const;
-
class SharedZip : public RefBase {
public:
static sp<SharedZip> get(const String8& path, bool createIfNotPresent = true);
@@ -254,9 +249,6 @@
bool isUpToDate();
- void addOverlay(const asset_path& ap);
- bool getOverlay(size_t idx, asset_path* out) const;
-
protected:
~SharedZip();
@@ -271,8 +263,6 @@
Asset* mResourceTableAsset;
ResTable* mResourceTable;
- Vector<asset_path> mOverlays;
-
static Mutex gLock;
static DefaultKeyedVector<String8, wp<SharedZip> > gOpen;
};
@@ -306,9 +296,6 @@
bool isUpToDate();
- void addOverlay(const String8& path, const asset_path& overlay);
- bool getOverlay(const String8& path, size_t idx, asset_path* out) const;
-
private:
void closeZip(int idx);
diff --git a/libs/hwui/Properties.cpp b/libs/hwui/Properties.cpp
index 2931255..aad81df 100644
--- a/libs/hwui/Properties.cpp
+++ b/libs/hwui/Properties.cpp
@@ -213,10 +213,13 @@
char prop[PROPERTY_VALUE_MAX];
property_get(PROPERTY_RENDERER, prop, "opengl");
if (!strcmp(prop, "skiagl") ) {
+ ALOGD("Skia GL Pipeline");
sRenderPipelineType = RenderPipelineType::SkiaGL;
} else if (!strcmp(prop, "skiavk") ) {
+ ALOGD("Skia Vulkan Pipeline");
sRenderPipelineType = RenderPipelineType::SkiaVulkan;
} else { //"opengl"
+ ALOGD("HWUI GL Pipeline");
sRenderPipelineType = RenderPipelineType::OpenGL;
}
return sRenderPipelineType;
diff --git a/libs/hwui/hwui/Canvas.cpp b/libs/hwui/hwui/Canvas.cpp
index c365b5d..c64a89d 100644
--- a/libs/hwui/hwui/Canvas.cpp
+++ b/libs/hwui/hwui/Canvas.cpp
@@ -153,8 +153,8 @@
// minikin may modify the original paint
Paint paint(origPaint);
- minikin::Layout layout;
- MinikinUtils::doLayout(&layout, &paint, bidiFlags, typeface, text, start, count, contextCount);
+ minikin::Layout layout = MinikinUtils::doLayout(
+ &paint, bidiFlags, typeface, text, start, count, contextCount);
size_t nGlyphs = layout.nGlyphs();
std::unique_ptr<uint16_t[]> glyphs(new uint16_t[nGlyphs]);
@@ -205,8 +205,8 @@
void Canvas::drawTextOnPath(const uint16_t* text, int count, int bidiFlags, const SkPath& path,
float hOffset, float vOffset, const Paint& paint, Typeface* typeface) {
Paint paintCopy(paint);
- minikin::Layout layout;
- MinikinUtils::doLayout(&layout, &paintCopy, bidiFlags, typeface, text, 0, count, count);
+ minikin::Layout layout = MinikinUtils::doLayout(
+ &paintCopy, bidiFlags, typeface, text, 0, count, count);
hOffset += MinikinUtils::hOffsetForTextAlign(&paintCopy, layout, path);
// Set align to left for drawing, as we don't want individual
diff --git a/libs/hwui/hwui/MinikinSkia.cpp b/libs/hwui/hwui/MinikinSkia.cpp
index cbae0a0..ba4e3a4 100644
--- a/libs/hwui/hwui/MinikinSkia.cpp
+++ b/libs/hwui/hwui/MinikinSkia.cpp
@@ -91,7 +91,7 @@
return mAxes;
}
-minikin::MinikinFont* MinikinFontSkia::createFontWithVariation(
+std::shared_ptr<minikin::MinikinFont> MinikinFontSkia::createFontWithVariation(
const std::vector<minikin::FontVariation>& variations) const {
SkFontMgr::FontParameters params;
@@ -110,7 +110,8 @@
sk_sp<SkFontMgr> fm(SkFontMgr::RefDefault());
sk_sp<SkTypeface> face(fm->createFromStream(stream, params));
- return new MinikinFontSkia(std::move(face), mFontData, mFontSize, ttcIndex, variations);
+ return std::make_shared<MinikinFontSkia>(std::move(face), mFontData, mFontSize, ttcIndex,
+ variations);
}
uint32_t MinikinFontSkia::packPaintFlags(const SkPaint* paint) {
diff --git a/libs/hwui/hwui/MinikinSkia.h b/libs/hwui/hwui/MinikinSkia.h
index db59fe5..6c12485 100644
--- a/libs/hwui/hwui/MinikinSkia.h
+++ b/libs/hwui/hwui/MinikinSkia.h
@@ -45,7 +45,7 @@
size_t GetFontSize() const;
int GetFontIndex() const;
const std::vector<minikin::FontVariation>& GetAxes() const;
- minikin::MinikinFont* createFontWithVariation(
+ std::shared_ptr<minikin::MinikinFont> createFontWithVariation(
const std::vector<minikin::FontVariation>&) const;
static uint32_t packPaintFlags(const SkPaint* paint);
diff --git a/libs/hwui/hwui/MinikinUtils.cpp b/libs/hwui/hwui/MinikinUtils.cpp
index 713e509..d1871ff 100644
--- a/libs/hwui/hwui/MinikinUtils.cpp
+++ b/libs/hwui/hwui/MinikinUtils.cpp
@@ -27,9 +27,8 @@
namespace android {
minikin::FontStyle MinikinUtils::prepareMinikinPaint(minikin::MinikinPaint* minikinPaint,
- minikin::FontCollection** pFont, const Paint* paint, Typeface* typeface) {
+ const Paint* paint, Typeface* typeface) {
const Typeface* resolvedFace = Typeface::resolveDefault(typeface);
- *pFont = resolvedFace->fFontCollection;
minikin::FontStyle resolved = resolvedFace->fStyle;
/* Prepare minikin FontStyle */
@@ -54,23 +53,23 @@
return minikinStyle;
}
-void MinikinUtils::doLayout(minikin::Layout* layout, const Paint* paint, int bidiFlags,
+minikin::Layout MinikinUtils::doLayout(const Paint* paint, int bidiFlags,
Typeface* typeface, const uint16_t* buf, size_t start, size_t count,
size_t bufSize) {
- minikin::FontCollection *font;
minikin::MinikinPaint minikinPaint;
- minikin::FontStyle minikinStyle = prepareMinikinPaint(&minikinPaint, &font, paint, typeface);
- layout->setFontCollection(font);
- layout->doLayout(buf, start, count, bufSize, bidiFlags, minikinStyle, minikinPaint);
+ minikin::FontStyle minikinStyle = prepareMinikinPaint(&minikinPaint, paint, typeface);
+ minikin::Layout layout(Typeface::resolveDefault(typeface)->fFontCollection);
+ layout.doLayout(buf, start, count, bufSize, bidiFlags, minikinStyle, minikinPaint);
+ return layout;
}
float MinikinUtils::measureText(const Paint* paint, int bidiFlags, Typeface* typeface,
const uint16_t* buf, size_t start, size_t count, size_t bufSize, float *advances) {
- minikin::FontCollection *font;
minikin::MinikinPaint minikinPaint;
- minikin::FontStyle minikinStyle = prepareMinikinPaint(&minikinPaint, &font, paint, typeface);
+ minikin::FontStyle minikinStyle = prepareMinikinPaint(&minikinPaint, paint, typeface);
+ Typeface* resolvedTypeface = Typeface::resolveDefault(typeface);
return minikin::Layout::measureText(buf, start, count, bufSize, bidiFlags, minikinStyle,
- minikinPaint, font, advances);
+ minikinPaint, resolvedTypeface->fFontCollection, advances);
}
bool MinikinUtils::hasVariationSelector(Typeface* typeface, uint32_t codepoint, uint32_t vs) {
diff --git a/libs/hwui/hwui/MinikinUtils.h b/libs/hwui/hwui/MinikinUtils.h
index d6f64d2..0f22adc 100644
--- a/libs/hwui/hwui/MinikinUtils.h
+++ b/libs/hwui/hwui/MinikinUtils.h
@@ -35,9 +35,9 @@
class MinikinUtils {
public:
ANDROID_API static minikin::FontStyle prepareMinikinPaint(minikin::MinikinPaint* minikinPaint,
- minikin::FontCollection** pFont, const Paint* paint, Typeface* typeface);
+ const Paint* paint, Typeface* typeface);
- ANDROID_API static void doLayout(minikin::Layout* layout, const Paint* paint, int bidiFlags,
+ ANDROID_API static minikin::Layout doLayout(const Paint* paint, int bidiFlags,
Typeface* typeface, const uint16_t* buf, size_t start, size_t count,
size_t bufSize);
@@ -56,11 +56,11 @@
ANDROID_API static void forFontRun(const minikin::Layout& layout, Paint* paint, F& f) {
float saveSkewX = paint->getTextSkewX();
bool savefakeBold = paint->isFakeBoldText();
- minikin::MinikinFont* curFont = NULL;
+ const minikin::MinikinFont* curFont = nullptr;
size_t start = 0;
size_t nGlyphs = layout.nGlyphs();
for (size_t i = 0; i < nGlyphs; i++) {
- minikin::MinikinFont* nextFont = layout.getFont(i);
+ const minikin::MinikinFont* nextFont = layout.getFont(i);
if (i > 0 && nextFont != curFont) {
MinikinFontSkia::populateSkPaint(paint, curFont, layout.getFakery(start));
f(start, i);
diff --git a/libs/hwui/hwui/Typeface.cpp b/libs/hwui/hwui/Typeface.cpp
index 9f9fac6..4b8575a 100644
--- a/libs/hwui/hwui/Typeface.cpp
+++ b/libs/hwui/hwui/Typeface.cpp
@@ -64,7 +64,6 @@
Typeface* result = new Typeface;
if (result != nullptr) {
result->fFontCollection = resolvedFace->fFontCollection;
- result->fFontCollection->Ref();
result->fSkiaStyle = style;
result->fBaseWeight = resolvedFace->fBaseWeight;
resolveStyle(result);
@@ -83,7 +82,6 @@
// None of passed axes are supported by this collection.
// So we will reuse the same collection with incrementing reference count.
result->fFontCollection = resolvedFace->fFontCollection;
- result->fFontCollection->Ref();
}
result->fSkiaStyle = resolvedFace->fSkiaStyle;
result->fBaseWeight = resolvedFace->fBaseWeight;
@@ -97,7 +95,6 @@
Typeface* result = new Typeface;
if (result != nullptr) {
result->fFontCollection = resolvedFace->fFontCollection;
- result->fFontCollection->Ref();
result->fSkiaStyle = resolvedFace->fSkiaStyle;
result->fBaseWeight = weight;
resolveStyle(result);
@@ -105,18 +102,19 @@
return result;
}
-Typeface* Typeface::createFromFamilies(const std::vector<minikin::FontFamily*>& families) {
+Typeface* Typeface::createFromFamilies(
+ std::vector<std::shared_ptr<minikin::FontFamily>>&& families) {
Typeface* result = new Typeface;
- result->fFontCollection = new minikin::FontCollection(families);
+ result->fFontCollection.reset(new minikin::FontCollection(families));
if (families.empty()) {
ALOGW("createFromFamilies creating empty collection");
result->fSkiaStyle = SkTypeface::kNormal;
} else {
const minikin::FontStyle defaultStyle;
- minikin::FontFamily* firstFamily = reinterpret_cast<minikin::FontFamily*>(families[0]);
- minikin::MinikinFont* mf = firstFamily->getClosestMatch(defaultStyle).font;
- if (mf != NULL) {
- SkTypeface* skTypeface = reinterpret_cast<MinikinFontSkia*>(mf)->GetSkTypeface();
+ const std::shared_ptr<minikin::FontFamily>& firstFamily = families[0];
+ const minikin::MinikinFont* mf = firstFamily->getClosestMatch(defaultStyle).font;
+ if (mf != nullptr) {
+ SkTypeface* skTypeface = reinterpret_cast<const MinikinFontSkia*>(mf)->GetSkTypeface();
// TODO: probably better to query more precise style from family, will be important
// when we open up API to access 100..900 weights
result->fSkiaStyle = skTypeface->style();
@@ -129,11 +127,6 @@
return result;
}
-void Typeface::unref() {
- fFontCollection->Unref();
- delete this;
-}
-
void Typeface::setDefault(Typeface* face) {
gDefaultTypeface = face;
}
@@ -150,15 +143,12 @@
sk_sp<SkTypeface> typeface = SkTypeface::MakeFromStream(fontData.release());
LOG_ALWAYS_FATAL_IF(typeface == nullptr, "Failed to make typeface from %s", kRobotoFont);
- minikin::MinikinFont* font = new MinikinFontSkia(std::move(typeface), data, st.st_size, 0,
- std::vector<minikin::FontVariation>());
- minikin::FontFamily* family = new minikin::FontFamily(
- std::vector<minikin::Font>({ minikin::Font(font, minikin::FontStyle()) }));
- font->Unref();
-
- std::vector<minikin::FontFamily*> typefaces = { family };
- minikin::FontCollection *collection = new minikin::FontCollection(typefaces);
- family->Unref();
+ std::shared_ptr<minikin::MinikinFont> font = std::make_shared<MinikinFontSkia>(
+ std::move(typeface), data, st.st_size, 0, std::vector<minikin::FontVariation>());
+ std::shared_ptr<minikin::FontFamily> family = std::make_shared<minikin::FontFamily>(
+ std::vector<minikin::Font>({ minikin::Font(std::move(font), minikin::FontStyle()) }));
+ std::shared_ptr<minikin::FontCollection> collection =
+ std::make_shared<minikin::FontCollection>(std::move(family));
Typeface* hwTypeface = new Typeface();
hwTypeface->fFontCollection = collection;
diff --git a/libs/hwui/hwui/Typeface.h b/libs/hwui/hwui/Typeface.h
index 4392ebc..19a4f6c5 100644
--- a/libs/hwui/hwui/Typeface.h
+++ b/libs/hwui/hwui/Typeface.h
@@ -23,11 +23,12 @@
#include <cutils/compiler.h>
#include <minikin/FontCollection.h>
#include <vector>
+#include <memory>
namespace android {
struct ANDROID_API Typeface {
- minikin::FontCollection *fFontCollection;
+ std::shared_ptr<minikin::FontCollection> fFontCollection;
// style used for constructing and querying Typeface objects
SkTypeface::Style fSkiaStyle;
@@ -37,8 +38,6 @@
// resolved style actually used for rendering
minikin::FontStyle fStyle;
- void unref();
-
static Typeface* resolveDefault(Typeface* src);
static Typeface* createFromTypeface(Typeface* src, SkTypeface::Style style);
@@ -48,7 +47,8 @@
static Typeface* createWeightAlias(Typeface* src, int baseweight);
- static Typeface* createFromFamilies(const std::vector<minikin::FontFamily*>& families);
+ static Typeface* createFromFamilies(
+ std::vector<std::shared_ptr<minikin::FontFamily>>&& families);
static void setDefault(Typeface* face);
diff --git a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp
index f2b0eb3..ae13131 100644
--- a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp
+++ b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp
@@ -26,7 +26,6 @@
#include "SkiaProfileRenderer.h"
#include "utils/TraceUtils.h"
-#include <android/native_window.h>
#include <cutils/properties.h>
#include <strings.h>
diff --git a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp
index c63dce1..d28e605 100644
--- a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp
+++ b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp
@@ -31,7 +31,6 @@
#include <GrTypes.h>
#include <vk/GrVkTypes.h>
-#include <android/native_window.h>
#include <cutils/properties.h>
#include <strings.h>
diff --git a/libs/hwui/renderthread/EglManager.cpp b/libs/hwui/renderthread/EglManager.cpp
index 860725b..44af5fd 100644
--- a/libs/hwui/renderthread/EglManager.cpp
+++ b/libs/hwui/renderthread/EglManager.cpp
@@ -133,7 +133,7 @@
LOG_ALWAYS_FATAL_IF(!glInterface.get());
GrContextOptions options;
- options.fDisableDistanceFieldPaths = true;
+ options.fGpuPathRenderers &= ~GrContextOptions::GpuPathRenderers::kDistanceField;
options.fAllowPathMaskCaching = true;
mRenderThread.setGrContext(GrContext::Create(GrBackend::kOpenGL_GrBackend,
(GrBackendContext)glInterface.get(), options));
diff --git a/libs/hwui/renderthread/OpenGLPipeline.cpp b/libs/hwui/renderthread/OpenGLPipeline.cpp
index acd6110..e1ae585 100644
--- a/libs/hwui/renderthread/OpenGLPipeline.cpp
+++ b/libs/hwui/renderthread/OpenGLPipeline.cpp
@@ -24,7 +24,6 @@
#include "renderstate/RenderState.h"
#include "OpenGLReadback.h"
-#include <android/native_window.h>
#include <cutils/properties.h>
#include <strings.h>
diff --git a/libs/hwui/tests/unit/FrameBuilderTests.cpp b/libs/hwui/tests/unit/FrameBuilderTests.cpp
index a391d1e..95d9459 100644
--- a/libs/hwui/tests/unit/FrameBuilderTests.cpp
+++ b/libs/hwui/tests/unit/FrameBuilderTests.cpp
@@ -579,7 +579,7 @@
SkPaint textPaint;
textPaint.setAntiAlias(true);
textPaint.setTextSize(20);
- textPaint.setStrikeThruText(true);
+ textPaint.setFlags(textPaint.getFlags() | SkPaint::kStrikeThruText_ReserveFlag);
textPaint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
for (int i = 0; i < LOOPS; i++) {
TestUtils::drawUtf8ToCanvas(&canvas, "test text", textPaint, 10, 100 * (i + 1));
diff --git a/libs/hwui/tests/unit/RecordingCanvasTests.cpp b/libs/hwui/tests/unit/RecordingCanvasTests.cpp
index 669f03c..b2ea9ac 100644
--- a/libs/hwui/tests/unit/RecordingCanvasTests.cpp
+++ b/libs/hwui/tests/unit/RecordingCanvasTests.cpp
@@ -200,8 +200,18 @@
paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
for (int i = 0; i < 2; i++) {
for (int j = 0; j < 2; j++) {
- paint.setUnderlineText(i != 0);
- paint.setStrikeThruText(j != 0);
+ uint32_t flags = paint.getFlags();
+ if (i != 0) {
+ flags |= SkPaint::kUnderlineText_ReserveFlag;
+ } else {
+ flags &= ~SkPaint::kUnderlineText_ReserveFlag;
+ }
+ if (j != 0) {
+ flags |= SkPaint::kStrikeThruText_ReserveFlag;
+ } else {
+ flags &= ~SkPaint::kStrikeThruText_ReserveFlag;
+ }
+ paint.setFlags(flags);
TestUtils::drawUtf8ToCanvas(&canvas, "test text", paint, 25, 25);
}
}
diff --git a/libs/input/Android.mk b/libs/input/Android.mk
index 2bbfdcc..e824275 100644
--- a/libs/input/Android.mk
+++ b/libs/input/Android.mk
@@ -28,7 +28,8 @@
libgui \
libui \
libinput \
- libinputflinger
+ libinputflinger \
+ libnativewindow
LOCAL_C_INCLUDES := \
frameworks/native/services
diff --git a/location/java/android/location/ILocationManager.aidl b/location/java/android/location/ILocationManager.aidl
index fc31f32..8f341a8 100644
--- a/location/java/android/location/ILocationManager.aidl
+++ b/location/java/android/location/ILocationManager.aidl
@@ -113,5 +113,6 @@
// for reporting callback completion
void locationCallbackFinished(ILocationListener listener);
-
+ // used by gts tests to verify throttling whitelist
+ String[] getBackgroundThrottlingWhitelist();
}
diff --git a/media/java/android/media/AudioFocusRequest.java b/media/java/android/media/AudioFocusRequest.java
new file mode 100644
index 0000000..1b75a78
--- /dev/null
+++ b/media/java/android/media/AudioFocusRequest.java
@@ -0,0 +1,321 @@
+/*
+ * Copyright (C) 2017 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.media;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.media.AudioManager.OnAudioFocusChangeListener;
+import android.os.Handler;
+import android.os.Looper;
+
+/**
+ * A class to encapsulate information about an audio focus request.
+ * An {@code AudioFocusRequest} instance is built by {@link Builder}, and is used to
+ * request and abandon audio focus, respectively
+ * with {@link AudioManager#requestAudioFocus(AudioFocusRequest)} and
+ * {@link AudioManager#abandonAudioFocusRequest(AudioFocusRequest)}.
+ * <p>In the context of describing audio focus, the term "ducking" is used. It describes a temporary
+ * lowering of the audio level of an application in response to another application playing audio
+ * concurrently. An example is during the playback of driving directions,
+ * a user listening to music expects the music to "duck" during the playback of the message
+ * announcing directions.
+ */
+// TODO use this class to provide more documentation about audio focus and the new behaviors
+// describe up to N, and after.
+public final class AudioFocusRequest {
+
+ // default attributes for the request when not specified
+ private final static AudioAttributes FOCUS_DEFAULT_ATTR = new AudioAttributes.Builder()
+ .setUsage(AudioAttributes.USAGE_MEDIA).build();
+
+ private final OnAudioFocusChangeListener mFocusListener; // may be null
+ private final Handler mListenerHandler; // may be null
+ private final AudioAttributes mAttr; // never null
+ private final int mFocusGain;
+ private final int mFlags;
+
+ //TODO implement use of optional handler
+ private AudioFocusRequest(OnAudioFocusChangeListener listener, Handler handler,
+ AudioAttributes attr, int focusGain, int flags) {
+ mFocusListener = listener;
+ mListenerHandler = handler;
+ mFocusGain = focusGain;
+ mAttr = attr;
+ mFlags = flags;
+ }
+
+ /**
+ * @hide
+ * Checks whether a focus gain constant is a valid value for an audio focus request.
+ * @param focusGain value to check
+ * @return true if focusGain is a valid value for an audio focus request.
+ */
+ final static boolean isValidFocusGain(int focusGain) {
+ switch (focusGain) {
+ case AudioManager.AUDIOFOCUS_GAIN:
+ case AudioManager.AUDIOFOCUS_GAIN_TRANSIENT:
+ case AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK:
+ case AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ /**
+ * Returns the focus change listener set for this {@code AudioFocusRequest}.
+ * @return null if no {@link AudioManager.OnAudioFocusChangeListener} was set.
+ */
+ public @Nullable OnAudioFocusChangeListener getOnAudioFocusChangeListener() {
+ return mFocusListener;
+ }
+
+ /**
+ * Returns the {@link Handler} to be used for the focus change listener.
+ * @return the same {@code Handler} set in.
+ * {@link Builder#setOnAudioFocusChangeListener(OnAudioFocusChangeListener, Handler)}, or null
+ * if no listener was set.
+ */
+ public @Nullable Handler getOnAudioFocusChangeListenerHandler() {
+ return mListenerHandler;
+ }
+
+ /**
+ * Returns the {@link AudioAttributes} set for this {@code AudioFocusRequest}, or the default
+ * attributes if none were set.
+ * @return non-null {@link AudioAttributes}.
+ */
+ public @NonNull AudioAttributes getAudioAttributes() {
+ return mAttr;
+ }
+
+ /**
+ * Returns the type of audio focus request configured for this {@code AudioFocusRequest}.
+ * @return one of {@link AudioManager#AUDIOFOCUS_GAIN},
+ * {@link AudioManager#AUDIOFOCUS_GAIN_TRANSIENT},
+ * {@link AudioManager#AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK}, and
+ * {@link AudioManager#AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE}.
+ */
+ public int getFocusGain() {
+ return mFocusGain;
+ }
+
+ /**
+ * Returns whether the application that would use this {@code AudioFocusRequest} would pause
+ * when it is requested to duck.
+ * @return the duck/pause behavior.
+ */
+ public boolean willPauseWhenDucked() {
+ return (mFlags & AudioManager.AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS)
+ == AudioManager.AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS;
+ }
+
+ /**
+ * Returns whether the application that would use this {@code AudioFocusRequest} supports
+ * a focus gain granted after a temporary request failure.
+ * @return whether delayed focus gain is supported.
+ */
+ public boolean acceptsDelayedFocusGain() {
+ return (mFlags & AudioManager.AUDIOFOCUS_FLAG_DELAY_OK)
+ == AudioManager.AUDIOFOCUS_FLAG_DELAY_OK;
+ }
+
+ int getFlags() {
+ return mFlags;
+ }
+
+ /**
+ * Builder class for {@link AudioFocusRequest} objects.
+ * <p> Here is an example where {@code Builder} is used to define the
+ * {@link AudioFocusRequest} for requesting audio focus:
+ *
+ * <pre class="prettyprint">
+ * mAudioManager = (AudioManager) Context.getSystemService(Context.AUDIO_SERVICE);
+ * mPlaybackAttributes = new AudioAttributes.Builder()
+ * .setUsage(AudioAttributes.USAGE_GAME)
+ * .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
+ * .build();
+ * mFocusRequest = new AudioFocusRequest.Builder(AudioManager.AUDIOFOCUS_GAIN)
+ * .setAudioAttributes(mPlaybackAttributes)
+ * .setAcceptsDelayedFocusGain(true)
+ * .setOnAudioFocusChangeListener(mMyFocusListener, mMyHandler)
+ * .build();
+ * mMediaPlayer = new MediaPlayer();
+ * ...
+ * mMediaPlayer.setAudioAttributes(mPlaybackAttributes);
+ * ...
+ * mAudioManager.requestAudioFocus(mFocusRequest);
+ * ...
+ * mAudioManager.abandonAudioFocusRequest(mFocusRequest);
+ * </pre>
+ *
+ */
+ public static final class Builder {
+ private OnAudioFocusChangeListener mFocusListener;
+ private Handler mListenerHandler;
+ private AudioAttributes mAttr = FOCUS_DEFAULT_ATTR;
+ private int mFocusGain;
+ private boolean mPausesOnDuck = false;
+ private boolean mDelayedFocus = false;
+
+ /**
+ * Constructs a new {@code Builder}, and specifies how audio focus
+ * will be requested. Valid values for focus requests are
+ * {@link AudioManager#AUDIOFOCUS_GAIN}, {@link AudioManager#AUDIOFOCUS_GAIN_TRANSIENT},
+ * {@link AudioManager#AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK}, and
+ * {@link AudioManager#AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE}.
+ * <p>By default there is no focus change listener, and the <code>AudioAttributes</code>
+ * have a usage of {@link AudioAttributes#USAGE_MEDIA}.
+ * @param focusGain the type of audio focus gain that will be requested
+ * @throws IllegalArgumentException thrown when an invalid focus gain type is used
+ */
+ public Builder(int focusGain) {
+ setFocusGain(focusGain);
+ }
+
+ /**
+ * Constructs a new {@code Builder} with all the properties of the {@code AudioFocusRequest}
+ * passed as parameter.
+ * Use this method when you want a new request to differ only by some properties.
+ * @param requestToCopy the non-null {@code AudioFocusRequest} to build a duplicate from.
+ * @throws IllegalArgumentException thrown when a null {@code AudioFocusRequest} is used.
+ */
+ public Builder(@NonNull AudioFocusRequest requestToCopy) {
+ if (requestToCopy == null) {
+ throw new IllegalArgumentException("Illegal null AudioFocusRequest");
+ }
+ mAttr = requestToCopy.mAttr;
+ mFocusListener = requestToCopy.mFocusListener;
+ mListenerHandler = requestToCopy.mListenerHandler;
+ mFocusGain = requestToCopy.mFocusGain;
+ mPausesOnDuck = requestToCopy.willPauseWhenDucked();
+ mDelayedFocus = requestToCopy.acceptsDelayedFocusGain();
+ }
+
+ /**
+ * Sets the type of focus gain that will be requested.
+ * Use this method to replace the focus gain when building a request by modifying an
+ * existing {@code AudioFocusRequest} instance.
+ * @param focusGain the type of audio focus gain that will be requested.
+ * @return this {@code Builder} instance
+ * @throws IllegalArgumentException thrown when an invalid focus gain type is used
+ */
+ public @NonNull Builder setFocusGain(int focusGain) {
+ if (!isValidFocusGain(focusGain)) {
+ throw new IllegalArgumentException("Illegal audio focus gain type " + focusGain);
+ }
+ mFocusGain = focusGain;
+ return this;
+ }
+
+ /**
+ * Sets the listener called when audio focus changes after being requested with
+ * {@link AudioManager#requestAudioFocus(AudioFocusRequest)}, and until being abandoned
+ * with {@link AudioManager#abandonAudioFocusRequest(AudioFocusRequest)}.
+ * Note that only focus changes (gains and losses) affecting the focus owner are reported,
+ * not gains and losses of other focus requesters in the system.
+ * @param listener the listener receiving the focus change notifications.
+ * @param handler the {@link Handler} for the thread on which to execute
+ * the notifications. If {@code null}, the {@code Handler} associated with the main
+ * {@link Looper} will be used.
+ * @return this {@code Builder} instance.
+ * @throws IllegalArgumentException thrown when a non-null handler is used with a null
+ * listener.
+ */
+ public @NonNull Builder setOnAudioFocusChangeListener(
+ @Nullable OnAudioFocusChangeListener listener, @Nullable Handler handler) {
+ if (listener == null && handler != null) {
+ throw new IllegalArgumentException(
+ "Illegal non-null handler without a focus listener");
+ }
+ mFocusListener = listener;
+ mListenerHandler = handler;
+ return this;
+ }
+
+ /**
+ * Sets the {@link AudioAttributes} to be associated with the focus request, and which
+ * describe the use case describing why focus is requested.
+ * As the focus requests typically precede audio playback, this information is used on
+ * certain platforms to declare the subsequent playback use case. It is therefore good
+ * practice to use in this method the same {@code AudioAttributes} as used for
+ * playback, see for example {@link MediaPlayer#setAudioAttributes(AudioAttributes)} in
+ * {@code MediaPlayer} or {@link AudioTrack.Builder#setAudioAttributes(AudioAttributes)}
+ * in {@code AudioTrack}.
+ * @param attributes the {@link AudioAttributes} for the focus request.
+ * @return this {@code Builder} instance.
+ * @throws IllegalArgumentException thrown when using null for the attributes.
+ */
+ public @NonNull Builder setAudioAttributes(@NonNull AudioAttributes attributes) {
+ if (attributes == null) {
+ throw new IllegalArgumentException("Illegal null AudioAttributes");
+ }
+ mAttr = attributes;
+ return this;
+ }
+
+ /**
+ * Declare the intended behavior of the application with regards to audio ducking.
+ * See more details in the {@link AudioFocusRequest} class documentation.
+ * @param pauseOnDuck use {@code true} if the application intends to pause audio playback
+ * when losing focus with {@link AudioManager#AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK}.
+ * If {@code true}, note that you must also set a focus listener to receive such an
+ * event, with
+ * {@link #setOnAudioFocusChangeListener(OnAudioFocusChangeListener, Handler)}.
+ * @return this {@code Builder} instance.
+ */
+ public @NonNull Builder setWillPauseWhenDucked(boolean pauseOnDuck) {
+ mPausesOnDuck = pauseOnDuck;
+ return this;
+ }
+
+ /**
+ * Marks this focus request as compatible with delayed focus.
+ * See more details about delayed focus in the {@link AudioFocusRequest} class
+ * documentation.
+ * @param acceptsDelayedFocusGain use {@code true} if the application supports delayed
+ * focus. If {@code true}, note that you must also set a focus listener to be notified
+ * of delayed focus gain, with
+ * {@link #setOnAudioFocusChangeListener(OnAudioFocusChangeListener, Handler)}.
+ * @return this {@code Builder} instance
+ */
+ public @NonNull Builder setAcceptsDelayedFocusGain(boolean acceptsDelayedFocusGain) {
+ mDelayedFocus = acceptsDelayedFocusGain;
+ return this;
+ }
+
+ /**
+ * Builds a new {@code AudioFocusRequest} instance combining all the information gathered
+ * by this {@code Builder}'s configuration methods.
+ * @return the {@code AudioFocusRequest} instance qualified by all the properties set
+ * on this {@code Builder}.
+ * @throws IllegalArgumentException thrown when focus request is set to accept delayed
+ * focus, or to pause on duck, but no focus change listener was set.
+ */
+ public AudioFocusRequest build() {
+ if ((mDelayedFocus || mPausesOnDuck) && (mFocusListener == null)) {
+ throw new IllegalArgumentException(
+ "Can't use delayed focus or pause on duck without a listener");
+ }
+ final int flags = 0
+ | (mDelayedFocus ? AudioManager.AUDIOFOCUS_FLAG_DELAY_OK : 0)
+ | (mPausesOnDuck ? AudioManager.AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS : 0);
+ return new AudioFocusRequest(mFocusListener, mListenerHandler,
+ mAttr, mFocusGain, flags);
+ }
+ }
+}
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index a4f2a7e..dc69a69 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -1981,8 +1981,7 @@
}
/**
- * @hide
- * Used to indicate no audio focus has been gained or lost.
+ * Used to indicate no audio focus has been gained or lost, or requested.
*/
public static final int AUDIOFOCUS_NONE = 0;
@@ -2210,11 +2209,11 @@
*/
public static final int AUDIOFOCUS_REQUEST_GRANTED = 1;
/**
- * @hide
* A focus change request whose granting is delayed: the request was successful, but the
* requester will only be granted audio focus once the condition that prevented immediate
* granting has ended.
- * See {@link #requestAudioFocus(OnAudioFocusChangeListener, AudioAttributes, int, int)}
+ * See {@link #requestAudioFocus(AudioFocusRequest)} and
+ * {@link AudioFocusRequest.Builder#setAcceptsDelayedFocusGain(boolean)}
*/
public static final int AUDIOFOCUS_REQUEST_DELAYED = 2;
@@ -2294,6 +2293,44 @@
| AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS | AUDIOFOCUS_FLAG_LOCK;
/**
+ * Request audio focus.
+ * See the {@link AudioFocusRequest} for information about the options available to configure
+ * your request, and notification of focus gain and loss.
+ * @param focusRequest a {@link AudioFocusRequest} instance used to configure how focus is
+ * requested.
+ * @return {@link #AUDIOFOCUS_REQUEST_FAILED}, {@link #AUDIOFOCUS_REQUEST_GRANTED}
+ * or {@link #AUDIOFOCUS_REQUEST_DELAYED}.
+ * <br>Note that the return value is never {@link #AUDIOFOCUS_REQUEST_DELAYED} when focus
+ * is requested without building the {@link AudioFocusRequest} with
+ * {@link AudioFocusRequest.Builder#setAcceptsDelayedFocusGain(boolean)} set to
+ * {@code true}.
+ * @throws IllegalArgumentException if passed a null argument
+ */
+ public int requestAudioFocus(@NonNull AudioFocusRequest focusRequest) {
+ if (focusRequest == null) {
+ throw new IllegalArgumentException("Illegal null AudioFocusRequest");
+ }
+ return requestAudioFocus(focusRequest.getOnAudioFocusChangeListener(),
+ focusRequest.getAudioAttributes(),
+ focusRequest.getFocusGain(), focusRequest.getFlags(), null /* no AudioPolicy*/);
+ }
+
+ /**
+ * Abandon audio focus. Causes the previous focus owner, if any, to receive focus.
+ * @param focusRequest the {@link AudioFocusRequest} that was used when requesting focus
+ * with {@link #requestAudioFocus(AudioFocusRequest)}.
+ * @return {@link #AUDIOFOCUS_REQUEST_FAILED} or {@link #AUDIOFOCUS_REQUEST_GRANTED}
+ * @throws IllegalArgumentException if passed a null argument
+ */
+ public int abandonAudioFocusRequest(@NonNull AudioFocusRequest focusRequest) {
+ if (focusRequest == null) {
+ throw new IllegalArgumentException("Illegal null AudioFocusRequest");
+ }
+ return abandonAudioFocus(focusRequest.getOnAudioFocusChangeListener(),
+ focusRequest.getAudioAttributes());
+ }
+
+ /**
* @hide
* Request audio focus.
* Send a request to obtain the audio focus. This method differs from
@@ -2373,8 +2410,7 @@
if (requestAttributes == null) {
throw new IllegalArgumentException("Illegal null AudioAttributes argument");
}
- if ((durationHint < AUDIOFOCUS_GAIN) ||
- (durationHint > AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE)) {
+ if (!AudioFocusRequest.isValidFocusGain(durationHint)) {
throw new IllegalArgumentException("Invalid duration hint");
}
if (flags != (flags & AUDIOFOCUS_FLAGS_SYSTEM)) {
diff --git a/media/java/android/media/AudioPlaybackConfiguration.java b/media/java/android/media/AudioPlaybackConfiguration.java
index dd9c6a7..6b8a279 100644
--- a/media/java/android/media/AudioPlaybackConfiguration.java
+++ b/media/java/android/media/AudioPlaybackConfiguration.java
@@ -366,11 +366,18 @@
* @param pw
*/
public void dump(PrintWriter pw) {
- pw.println(" ID:" + mPlayerIId
- + " -- type:" + toLogFriendlyPlayerType(mPlayerType)
- + " -- u/pid:" + mClientUid +"/" + mClientPid
- + " -- state:" + toLogFriendlyPlayerState(mPlayerState)
- + " -- attr:" + mPlayerAttr);
+ pw.println(" " + toLogFriendlyString(this));
+ }
+
+ /**
+ * @hide
+ */
+ public static String toLogFriendlyString(AudioPlaybackConfiguration apc) {
+ return new String("ID:" + apc.mPlayerIId
+ + " -- type:" + toLogFriendlyPlayerType(apc.mPlayerType)
+ + " -- u/pid:" + apc.mClientUid +"/" + apc.mClientPid
+ + " -- state:" + toLogFriendlyPlayerState(apc.mPlayerState)
+ + " -- attr:" + apc.mPlayerAttr);
}
public static final Parcelable.Creator<AudioPlaybackConfiguration> CREATOR
diff --git a/media/java/android/media/AudioTrack.java b/media/java/android/media/AudioTrack.java
index ddd8a65..7f5d3a0 100644
--- a/media/java/android/media/AudioTrack.java
+++ b/media/java/android/media/AudioTrack.java
@@ -79,6 +79,7 @@
*/
public class AudioTrack extends PlayerBase
implements AudioRouting
+ , VolumeAutomation
{
//---------------------------------------------------------
// Constants
@@ -1753,6 +1754,12 @@
return native_getVolumeShaperState(id);
}
+ @Override
+ public @NonNull VolumeShaper createVolumeShaper(
+ @NonNull VolumeShaper.Configuration configuration) {
+ return new VolumeShaper(configuration, this);
+ }
+
/**
* Sets the playback sample rate for this track. This sets the sampling rate at which
* the audio data will be consumed and played back
diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl
index fa4796a..5855984 100644
--- a/media/java/android/media/IAudioService.aidl
+++ b/media/java/android/media/IAudioService.aidl
@@ -192,7 +192,7 @@
oneway void releasePlayer(in int piid);
- void disableRingtoneSync();
+ void disableRingtoneSync(in int userId);
int getFocusRampTimeMs(in int focusGain, in AudioAttributes attr);
diff --git a/media/java/android/media/MediaCas.java b/media/java/android/media/MediaCas.java
new file mode 100644
index 0000000..2e22132
--- /dev/null
+++ b/media/java/android/media/MediaCas.java
@@ -0,0 +1,656 @@
+/*
+ * Copyright (C) 2017 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.media;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.IBinder;
+import android.os.Looper;
+import android.os.Message;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.os.Process;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.util.Log;
+import android.util.Singleton;
+
+/**
+ * MediaCas can be used to obtain keys for descrambling protected media streams, in
+ * conjunction with {@link android.media.MediaDescrambler}. The MediaCas APIs are
+ * designed to support conditional access such as those in the ISO/IEC13818-1.
+ * The CA system is identified by a 16-bit integer CA_system_id. The scrambling
+ * algorithms are usually proprietary and implemented by vendor-specific CA plugins
+ * installed on the device.
+ * <p>
+ * The app is responsible for constructing a MediaCas object for the CA system it
+ * intends to use. The app can query if a certain CA system is supported using static
+ * method {@link #isSystemIdSupported}. It can also obtain the entire list of supported
+ * CA systems using static method {@link #enumeratePlugins}.
+ * <p>
+ * Once the MediaCas object is constructed, the app should properly provision it by
+ * using method {@link #provision} and/or {@link #processEmm}. The EMMs (Entitlement
+ * management messages) can be distributed out-of-band, or in-band with the stream.
+ * <p>
+ * To descramble elementary streams, the app first calls {@link #openSession} to
+ * generate a sessionId that will uniquely identify a session. A session provides
+ * a context for subsequent key updates and descrambling activities. The ECMs
+ * (Entitlement control messages) are sent to the session via method {@link #processEcm}.
+ * <p>
+ * The app next constructs a MediaDescrambler object, and initializes it with the
+ * sessionId using {@link MediaDescrambler#setMediaCasSession}. This ties the
+ * descrambler to the session, and the descrambler can then be used to descramble
+ * content secured with the session's key, either during extraction, or during decoding
+ * with {@link android.media.MediaCodec}.
+ * <p>
+ * If the app handles sample extraction using its own extractor, it can use
+ * MediaDescrambler to descramble samples into clear buffers (if the session's license
+ * doesn't require secure decoders), or descramble a small amount of data to retrieve
+ * information necessary for the downstream pipeline to process the sample (if the
+ * session's license requires secure decoders).
+ * <p>
+ * If the session requires a secure decoder, a MediaDescrambler needs to be provided to
+ * MediaCodec to descramble samples queued by {@link MediaCodec#queueSecureInputBuffer}
+ * into protected buffers. The app should use {@link MediaCodec#configure(MediaFormat,
+ * android.view.Surface, int, MediaDescrambler)} instead of the normal {@link
+ * MediaCodec#configure(MediaFormat, android.view.Surface, MediaCrypto, int)} method
+ * to configure MediaCodec.
+ * <p>
+ * <h3>Using Android's MediaExtractor</h3>
+ * <p>
+ * If the app uses {@link MediaExtractor}, it can delegate the CAS session
+ * management to MediaExtractor by calling {@link MediaExtractor#setMediaCas}.
+ * MediaExtractor will take over and call {@link #openSession}, {@link #processEmm}
+ * and/or {@link #processEcm}, etc.. if necessary.
+ * <p>
+ * When using {@link MediaExtractor}, the app would still need a MediaDescrambler
+ * to use with {@link MediaCodec} if the licensing requires a secure decoder. The
+ * sessionId of the descrambler can be retrieved by {@link MediaExtractor#getDrmInitData}
+ * and used to initialize a MediaDescrambler object for MediaCodec.
+ * <p>
+ * TODO: determine exception handling schemes.
+ * <p>
+ * <h3>Listeners</h3>
+ * <p>The app may register a listener to receive events from the CA system using
+ * method {@link #setEventListener}. The exact format of the event is scheme-specific
+ * and is not specified by this API.
+ */
+public final class MediaCas {
+ private static final String TAG = "MediaCas";
+ private final ParcelableCasData mCasData = new ParcelableCasData();
+ private ICas mICas;
+ private EventListener mListener;
+ private HandlerThread mHandlerThread;
+ private EventHandler mEventHandler;
+
+ private static final Singleton<IMediaCasService> gDefault =
+ new Singleton<IMediaCasService>() {
+ @Override
+ protected IMediaCasService create() {
+ return IMediaCasService.Stub.asInterface(
+ ServiceManager.getService("media.cas"));
+ }
+ };
+
+ static IMediaCasService getService() {
+ return gDefault.get();
+ }
+
+ private void validateInternalStates() {
+ if (mICas == null) {
+ throw new IllegalStateException();
+ }
+ }
+
+ private void cleanupAndRethrowIllegalState() {
+ mICas = null;
+ throw new IllegalStateException();
+ }
+
+ private class EventHandler extends Handler
+ {
+ private static final int MSG_CAS_EVENT = 0;
+
+ public EventHandler(Looper looper) {
+ super(looper);
+ }
+
+ @Override
+ public void handleMessage(Message msg) {
+ if (msg.what == MSG_CAS_EVENT) {
+ mListener.onEvent(MediaCas.this, msg.arg1, msg.arg2, (byte[]) msg.obj);
+ }
+ }
+ }
+
+ private final ICasListener.Stub mBinder = new ICasListener.Stub() {
+ @Override
+ public void onEvent(int event, int arg, @Nullable byte[] data)
+ throws RemoteException {
+ mEventHandler.sendMessage(mEventHandler.obtainMessage(
+ EventHandler.MSG_CAS_EVENT, event, arg, data));
+ }
+ };
+
+ /**
+ * Class for parceling byte array data over ICas binder.
+ */
+ static class ParcelableCasData implements Parcelable {
+ private byte[] mData;
+ private int mOffset;
+ private int mLength;
+
+ ParcelableCasData() {
+ mData = null;
+ mOffset = mLength = 0;
+ }
+
+ private ParcelableCasData(Parcel in) {
+ this();
+ }
+
+ void set(@NonNull byte[] data, int offset, int length) {
+ mData = data;
+ mOffset = offset;
+ mLength = length;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeByteArray(mData, mOffset, mLength);
+ }
+
+ public static final Parcelable.Creator<ParcelableCasData> CREATOR
+ = new Parcelable.Creator<ParcelableCasData>() {
+ public ParcelableCasData createFromParcel(Parcel in) {
+ return new ParcelableCasData(in);
+ }
+
+ public ParcelableCasData[] newArray(int size) {
+ return new ParcelableCasData[size];
+ }
+ };
+ }
+
+ /**
+ * Describe a CAS plugin with its CA_system_ID and string name.
+ *
+ * Returned as results of {@link #enumeratePlugins}.
+ *
+ */
+ public static class PluginDescriptor {
+ private final int mCASystemId;
+ private final String mName;
+
+ private PluginDescriptor() {
+ mCASystemId = 0xffff;
+ mName = null;
+ }
+
+ PluginDescriptor(int CA_system_id, String name) {
+ mCASystemId = CA_system_id;
+ mName = name;
+ }
+
+ public int getSystemId() {
+ return mCASystemId;
+ }
+
+ @NonNull
+ public String getName() {
+ return mName;
+ }
+
+ @Override
+ public String toString() {
+ return "PluginDescriptor {" + mCASystemId + ", " + mName + "}";
+ }
+ }
+
+ /**
+ * Class for parceling CAS plugin descriptors over IMediaCasService binder.
+ */
+ static class ParcelableCasPluginDescriptor
+ extends PluginDescriptor implements Parcelable {
+
+ private ParcelableCasPluginDescriptor(int CA_system_id, String name) {
+ super(CA_system_id, name);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ Log.w(TAG, "ParcelableCasPluginDescriptor.writeToParcel shouldn't be called!");
+ }
+
+ public static final Parcelable.Creator<ParcelableCasPluginDescriptor> CREATOR
+ = new Parcelable.Creator<ParcelableCasPluginDescriptor>() {
+ public ParcelableCasPluginDescriptor createFromParcel(Parcel in) {
+ int CA_system_id = in.readInt();
+ String name = in.readString();
+ return new ParcelableCasPluginDescriptor(CA_system_id, name);
+ }
+
+ public ParcelableCasPluginDescriptor[] newArray(int size) {
+ return new ParcelableCasPluginDescriptor[size];
+ }
+ };
+ }
+
+ /**
+ * Query if a certain CA system is supported on this device.
+ *
+ * @param CA_system_id the id of the CA system.
+ *
+ * @return Whether the specified CA system is supported on this device.
+ */
+ public static boolean isSystemIdSupported(int CA_system_id) {
+ IMediaCasService service = getService();
+
+ if (service != null) {
+ try {
+ return service.isSystemIdSupported(CA_system_id);
+ } catch (RemoteException e) {
+ }
+ }
+ return false;
+ }
+
+ /**
+ * List all available CA plugins on the device.
+ *
+ * @return an array of descriptors for the available CA plugins.
+ */
+ public static PluginDescriptor[] enumeratePlugins() {
+ IMediaCasService service = getService();
+
+ if (service != null) {
+ try {
+ ParcelableCasPluginDescriptor[] descriptors = service.enumeratePlugins();
+ if (descriptors.length == 0) {
+ return null;
+ }
+ PluginDescriptor[] results = new PluginDescriptor[descriptors.length];
+ for (int i = 0; i < results.length; i++) {
+ results[i] = descriptors[i];
+ }
+ return results;
+ } catch (RemoteException e) {
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Instantiate a CA system of the specified system id.
+ *
+ * @param CA_system_id The system id of the CA system.
+ *
+ * @throws UnsupportedCasException if the device does not support the
+ * specified CA system.
+ */
+ public MediaCas(int CA_system_id) throws UnsupportedCasException {
+ try {
+ mICas = getService().createPlugin(CA_system_id, mBinder);
+ } catch(Exception e) {
+ Log.e(TAG, "Failed to create plugin: " + e);
+ mICas = null;
+ } finally {
+ if (mICas == null) {
+ throw new UnsupportedCasException(
+ "Unsupported CA_system_id " + CA_system_id);
+ }
+ }
+ }
+
+ IBinder getBinder() {
+ validateInternalStates();
+
+ return mICas.asBinder();
+ }
+
+ /**
+ * An interface registered by the caller to {@link #setEventListener}
+ * to receives scheme-specific notifications from a MediaCas instance.
+ */
+ public interface EventListener {
+ /**
+ * Notify the listener of a scheme-specific event from the CA system.
+ *
+ * @param MediaCas the MediaCas object to receive this event.
+ * @param event an integer whose meaning is scheme-specific.
+ * @param arg an integer whose meaning is scheme-specific.
+ * @param data a byte array of data whose format and meaning are
+ * scheme-specific.
+ */
+ void onEvent(MediaCas MediaCas, int event, int arg, @Nullable byte[] data);
+ }
+
+ /**
+ * Set an event listener to receive notifications from the MediaCas instance.
+ *
+ * @param listener the event listener to be set.
+ * @param handler the handler whose looper the event listener will be called on.
+ * If handler is null, we'll try to use current thread's looper, or the main
+ * looper. If neither are available, an internal thread will be created instead.
+ */
+ public void setEventListener(
+ @Nullable EventListener listener, @Nullable Handler handler) {
+ mListener = listener;
+
+ if (mListener == null) {
+ mEventHandler = null;
+ return;
+ }
+
+ Looper looper = (handler != null) ? handler.getLooper() : null;
+ if (looper == null
+ && (looper = Looper.myLooper()) == null
+ && (looper = Looper.getMainLooper()) == null) {
+ if (mHandlerThread == null || !mHandlerThread.isAlive()) {
+ mHandlerThread = new HandlerThread("MediaCasEventThread",
+ Process.THREAD_PRIORITY_FOREGROUND);
+ mHandlerThread.start();
+ }
+ looper = mHandlerThread.getLooper();
+ }
+ mEventHandler = new EventHandler(looper);
+ }
+
+ /*
+ * TODO: handle ServiceSpecificException from the IMediaCas
+ * All Drm-specific failures will be thrown by mICas as
+ * ServiceSpecificException exception with Drm error code.
+ * These need to be re-thrown as crypto exceptions.
+ */
+
+ /**
+ * Send the private data for the CA system.
+ *
+ * @param data byte array of the private data.
+ *
+ * @throws IllegalStateException if the MediaCas instance is not valid.
+ */
+ /*
+ * TODO: need to re-throw DRM-specific exceptions
+ */
+ public void setPrivateData(@NonNull byte[] data) {
+ validateInternalStates();
+
+ try {
+ mICas.setPrivateData(data);
+ } catch (RemoteException e) {
+ cleanupAndRethrowIllegalState();
+ }
+ }
+
+ /**
+ * Open a session for the specified program.
+ *
+ * @param programNumber program_number of the program (as in ISO/IEC13818-1).
+ *
+ * @return session id of the newly opened session.
+ *
+ * @throws IllegalStateException if the MediaCas instance is not valid,
+ * or IllegalArgumentException if a session for the program already exists.
+ */
+ public byte[] openSession(int programNumber) {
+ validateInternalStates();
+
+ try {
+ return mICas.openSession(programNumber);
+ } catch (RemoteException e) {
+ cleanupAndRethrowIllegalState();
+ }
+ return null;
+ }
+
+ /**
+ * Open a session for the specified stream.
+ *
+ * @param programNumber program_number of the stream (as in ISO/IEC13818-1).
+ * @param elementaryPID elementary_PID of the stream (as in ISO/IEC13818-1).
+ *
+ * @return session id of the newly opened session.
+ *
+ * @throws IllegalStateException if the MediaCas instance is not valid,
+ * or IllegalArgumentException if a session for the stream already exists.
+ */
+ public byte[] openSession(int programNumber, int elementaryPID) {
+ validateInternalStates();
+
+ try {
+ return mICas.openSessionForStream(programNumber, elementaryPID);
+ } catch (RemoteException e) {
+ cleanupAndRethrowIllegalState();
+ }
+ return null;
+ }
+
+ /**
+ * Close the specified session.
+ *
+ * @param sessionId the session to be closed.
+ *
+ * @throws IllegalStateException if the MediaCas instance is not valid,
+ * or IllegalArgumentException if the session is not valid.
+ */
+ public void closeSession(@NonNull byte[] sessionId) {
+ validateInternalStates();
+
+ try {
+ mICas.closeSession(sessionId);
+ } catch (RemoteException e) {
+ cleanupAndRethrowIllegalState();
+ }
+ }
+
+ /**
+ * Set the private data for a session.
+ *
+ * @param sessionId the session for which the private data is intended.
+ * @param data byte array of the private data.
+ *
+ * @throws IllegalStateException if the MediaCas instance is not valid,
+ * or IllegalArgumentException if the session is not valid.
+ */
+ /*
+ * TODO: need to re-throw DRM-specific exceptions
+ */
+ public void setSessionPrivateData(@NonNull byte[] sessionId, @NonNull byte[] data) {
+ validateInternalStates();
+
+ try {
+ mICas.setSessionPrivateData(sessionId, data);
+ } catch (RemoteException e) {
+ cleanupAndRethrowIllegalState();
+ }
+ }
+
+ /**
+ * Send a received ECM packet to the specified session of the CA system.
+ *
+ * @param sessionId the session for which the ECM is intended.
+ * @param data byte array of the ECM data.
+ * @param offset position within data where the ECM data begins.
+ * @param length length of the data (starting from offset).
+ *
+ * @throws IllegalStateException if the MediaCas instance is not valid,
+ * or IllegalArgumentException if the session is not valid.
+ */
+ /*
+ * TODO: need to re-throw DRM-specific exceptions
+ */
+ public void processEcm(
+ @NonNull byte[] sessionId, @NonNull byte[] data, int offset, int length) {
+ validateInternalStates();
+
+ try {
+ mCasData.set(data, offset, length);
+ mICas.processEcm(sessionId, mCasData);
+ } catch (RemoteException e) {
+ cleanupAndRethrowIllegalState();
+ }
+ }
+
+ /**
+ * Send a received ECM packet to the specified session of the CA system.
+ * This is similar to {@link #processEcm(byte[], byte[], int, int)}
+ * except that the entire byte array is sent.
+ *
+ * @param sessionId the session for which the ECM is intended.
+ * @param data byte array of the ECM data.
+ *
+ * @throws IllegalStateException if the MediaCas instance is not valid,
+ * or IllegalArgumentException if the session is not valid.
+ */
+ /*
+ * TODO: need to re-throw DRM-specific exceptions
+ */
+ public void processEcm(@NonNull byte[] sessionId, @NonNull byte[] data) {
+ processEcm(sessionId, data, 0, data.length);
+ }
+
+ /**
+ * Send a received EMM packet to the CA system.
+ *
+ * @param data byte array of the EMM data.
+ * @param offset position within data where the EMM data begins.
+ * @param length length of the data (starting from offset).
+ *
+ * @throws IllegalStateException if the MediaCas instance is not valid.
+ */
+ /*
+ * TODO: need to re-throw DRM-specific exceptions
+ */
+ public void processEmm(@NonNull byte[] data, int offset, int length) {
+ validateInternalStates();
+
+ try {
+ mCasData.set(data, offset, length);
+ mICas.processEmm(mCasData);
+ } catch (RemoteException e) {
+ cleanupAndRethrowIllegalState();
+ }
+ }
+
+ /**
+ * Send a received EMM packet to the CA system. This is similar to
+ * {@link #processEmm(byte[], int, int)} except that the entire byte
+ * array is sent.
+ *
+ * @param data byte array of the EMM data.
+ *
+ * @throws IllegalStateException if the MediaCas instance is not valid.
+ */
+ /*
+ * TODO: need to re-throw DRM-specific exceptions
+ */
+ public void processEmm(@NonNull byte[] data) {
+ processEmm(data, 0, data.length);
+ }
+
+ /**
+ * Send an event to a CA system. The format of the event is scheme-specific
+ * and is opaque to the framework.
+ *
+ * @param event an integer denoting a scheme-specific event to be sent.
+ * @param arg a scheme-specific integer argument for the event.
+ * @param data a byte array containing scheme-specific data for the event.
+ *
+ * @throws IllegalStateException if the MediaCas instance is not valid.
+ */
+ public void sendEvent(int event, int arg, @Nullable byte[] data) {
+ validateInternalStates();
+
+ try {
+ mICas.sendEvent(event, arg, data);
+ } catch (RemoteException e) {
+ cleanupAndRethrowIllegalState();
+ }
+ }
+
+ /**
+ * Initiate a provisioning operation for a CA system.
+ *
+ * @param provisionString string containing information needed for the
+ * provisioning operation, the format of which is scheme and implementation
+ * specific.
+ *
+ * @throws IllegalStateException if the MediaCas instance is not valid.
+ */
+ public void provision(@NonNull String provisionString) {
+ validateInternalStates();
+
+ try {
+ mICas.provision(provisionString);
+ } catch (RemoteException e) {
+ cleanupAndRethrowIllegalState();
+ }
+ }
+
+ /**
+ * Notify the CA system to refresh entitlement keys.
+ *
+ * @param refreshType the type of the refreshment.
+ * @param refreshData private data associated with the refreshment.
+ *
+ * @throws IllegalStateException if the MediaCas instance is not valid.
+ */
+ /*
+ * TODO: define enums for refreshType
+ */
+ public void refreshEntitlements(int refreshType, @Nullable byte[] refreshData) {
+ validateInternalStates();
+
+ try {
+ mICas.refreshEntitlements(refreshType, refreshData);
+ } catch (RemoteException e) {
+ cleanupAndRethrowIllegalState();
+ }
+ }
+
+ /**
+ * Release the MediaCas instance.
+ */
+ public void release() {
+ if (mICas != null) {
+ try {
+ mICas.release();
+ } catch (RemoteException e) {
+ } finally {
+ mICas = null;
+ }
+ }
+ }
+
+ @Override
+ protected void finalize() {
+ release();
+ }
+}
\ No newline at end of file
diff --git a/core/java/android/net/NetworkScorerAppManager.aidl b/media/java/android/media/MediaCasException.java
similarity index 61%
copy from core/java/android/net/NetworkScorerAppManager.aidl
copy to media/java/android/media/MediaCasException.java
index d968343..1d5d3cd 100644
--- a/core/java/android/net/NetworkScorerAppManager.aidl
+++ b/media/java/android/media/MediaCasException.java
@@ -1,11 +1,11 @@
-/**
- * Copyright (c) 2017, The Android Open Source Project
+/*
+ * Copyright (C) 2017 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
+ * 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,
@@ -14,6 +14,13 @@
* limitations under the License.
*/
-package android.net;
+package android.media;
-parcelable NetworkScorerAppManager.NetworkScorerAppData;
+/**
+ * Base class for MediaCas exceptions
+ */
+public class MediaCasException extends Exception {
+ public MediaCasException(String detailMessage) {
+ super(detailMessage);
+ }
+}
diff --git a/media/java/android/media/MediaCodec.java b/media/java/android/media/MediaCodec.java
index 75ccffee..1ca9658 100644
--- a/media/java/android/media/MediaCodec.java
+++ b/media/java/android/media/MediaCodec.java
@@ -25,6 +25,7 @@
import android.media.MediaCodecInfo.CodecCapabilities;
import android.os.Bundle;
import android.os.Handler;
+import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
import android.view.Surface;
@@ -1567,6 +1568,13 @@
*/
public static final int BUFFER_FLAG_END_OF_STREAM = 4;
+ /**
+ * This indicates that the buffer only contains part of a frame,
+ * and the decoder should batch the data until a buffer without
+ * this flag appears before decoding the frame.
+ */
+ public static final int BUFFER_FLAG_PARTIAL_FRAME = 8;
+
/** @hide */
@IntDef(
flag = true,
@@ -1575,6 +1583,7 @@
BUFFER_FLAG_KEY_FRAME,
BUFFER_FLAG_CODEC_CONFIG,
BUFFER_FLAG_END_OF_STREAM,
+ BUFFER_FLAG_PARTIAL_FRAME,
})
@Retention(RetentionPolicy.SOURCE)
public @interface BufferFlag {}
@@ -1851,6 +1860,48 @@
@Nullable MediaFormat format,
@Nullable Surface surface, @Nullable MediaCrypto crypto,
@ConfigureFlag int flags) {
+ configure(format, surface, crypto, null, flags);
+ }
+
+ /**
+ * Configure a component to be used with a descrambler.
+ * @param format The format of the input data (decoder) or the desired
+ * format of the output data (encoder). Passing {@code null}
+ * as {@code format} is equivalent to passing an
+ * {@link MediaFormat#MediaFormat an empty mediaformat}.
+ * @param surface Specify a surface on which to render the output of this
+ * decoder. Pass {@code null} as {@code surface} if the
+ * codec does not generate raw video output (e.g. not a video
+ * decoder) and/or if you want to configure the codec for
+ * {@link ByteBuffer} output.
+ * @param flags Specify {@link #CONFIGURE_FLAG_ENCODE} to configure the
+ * component as an encoder.
+ * @param descrambler Specify a descrambler object to facilitate secure
+ * descrambling of the media data. descrambler must not be
+ * null if this method is used. For non-secure codecs, use
+ * {@link #configure} and with null crypto parameter.
+ * @throws IllegalArgumentException if the surface has been released (or is invalid),
+ * or the format is unacceptable (e.g. missing a mandatory key),
+ * or the flags are not set properly
+ * (e.g. missing {@link #CONFIGURE_FLAG_ENCODE} for an encoder).
+ * @throws IllegalStateException if not in the Uninitialized state.
+ * @throws CryptoException upon DRM error.
+ * @throws CodecException upon codec error.
+ */
+ public void configure(
+ @Nullable MediaFormat format, @Nullable Surface surface,
+ @ConfigureFlag int flags, @NonNull MediaDescrambler descrambler) {
+ configure(format, surface, null, descrambler.getBinder(), flags);
+ }
+
+ private void configure(
+ @Nullable MediaFormat format, @Nullable Surface surface,
+ @Nullable MediaCrypto crypto, @Nullable IBinder descramblerBinder,
+ @ConfigureFlag int flags) {
+ if (crypto != null && descramblerBinder != null) {
+ throw new IllegalArgumentException("Can't use crypto and descrambler together!");
+ }
+
String[] keys = null;
Object[] values = null;
@@ -1881,7 +1932,7 @@
mHasSurface = surface != null;
- native_configure(keys, values, surface, crypto, flags);
+ native_configure(keys, values, surface, crypto, descramblerBinder, flags);
}
/**
@@ -1959,7 +2010,8 @@
private native final void native_configure(
@Nullable String[] keys, @Nullable Object[] values,
- @Nullable Surface surface, @Nullable MediaCrypto crypto, @ConfigureFlag int flags);
+ @Nullable Surface surface, @Nullable MediaCrypto crypto,
+ @Nullable IBinder descramblerBinder, @ConfigureFlag int flags);
/**
* Requests a Surface to use as the input to an encoder, in place of input buffers. This
diff --git a/media/java/android/media/MediaCodecInfo.java b/media/java/android/media/MediaCodecInfo.java
index 8ada295f..3ac4c34 100644
--- a/media/java/android/media/MediaCodecInfo.java
+++ b/media/java/android/media/MediaCodecInfo.java
@@ -460,6 +460,11 @@
public static final String FEATURE_TunneledPlayback = "tunneled-playback";
/**
+ * <b>video decoder only</b>: codec supports queuing partial frames.
+ */
+ public static final String FEATURE_PartialFrame = "partial-frame";
+
+ /**
* <b>video encoder only</b>: codec supports intra refresh.
*/
public static final String FEATURE_IntraRefresh = "intra-refresh";
@@ -489,6 +494,7 @@
new Feature(FEATURE_AdaptivePlayback, (1 << 0), true),
new Feature(FEATURE_SecurePlayback, (1 << 1), false),
new Feature(FEATURE_TunneledPlayback, (1 << 2), false),
+ new Feature(FEATURE_PartialFrame, (1 << 3), false),
};
private static final Feature[] encoderFeatures = {
diff --git a/media/java/android/media/MediaDescrambler.java b/media/java/android/media/MediaDescrambler.java
new file mode 100644
index 0000000..f5eede8
--- /dev/null
+++ b/media/java/android/media/MediaDescrambler.java
@@ -0,0 +1,249 @@
+/*
+ * Copyright (C) 2017 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.media;
+
+import android.annotation.NonNull;
+import android.os.IBinder;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.os.RemoteException;
+import android.util.Log;
+
+import java.nio.ByteBuffer;
+
+/**
+ * MediaDescrambler class can be used in conjunction with {@link android.media.MediaCodec}
+ * and {@link android.media.MediaExtractor} to decode media data scrambled by conditional
+ * access (CA) systems such as those in the ISO/IEC13818-1.
+ *
+ * A MediaDescrambler object is initialized from a session opened by a MediaCas object,
+ * and can be used to descramble media streams scrambled with that session's keys.
+ *
+ * Scrambling schemes are identified by 16-bit unsigned integer as in CA_system_id.
+ *
+ */
+public final class MediaDescrambler {
+ private static final String TAG = "MediaDescrambler";
+ private IDescrambler mIDescrambler;
+
+ private final void validateInternalStates() {
+ if (mIDescrambler == null) {
+ throw new IllegalStateException();
+ }
+ }
+
+ private final void cleanupAndRethrowIllegalState() {
+ mIDescrambler = null;
+ throw new IllegalStateException();
+ }
+
+ /**
+ * Class for parceling descrambling parameters over IDescrambler binder.
+ */
+ static class DescrambleInfo implements Parcelable {
+ private DescrambleInfo() {
+ // TODO: implement
+ }
+
+ private DescrambleInfo(Parcel in) {
+ // TODO: disable
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ // TODO: implement
+ }
+
+ public static final Parcelable.Creator<DescrambleInfo> CREATOR
+ = new Parcelable.Creator<DescrambleInfo>() {
+ public DescrambleInfo createFromParcel(Parcel in) {
+ return new DescrambleInfo(in);
+ }
+
+ public DescrambleInfo[] newArray(int size) {
+ return new DescrambleInfo[size];
+ }
+ };
+ }
+
+ /**
+ * Instantiate a MediaDescrambler.
+ *
+ * @param CA_system_id The system id of the scrambling scheme.
+ *
+ * @throws UnsupportedCasException if the scrambling scheme is not supported.
+ */
+ public MediaDescrambler(int CA_system_id) throws UnsupportedCasException {
+ try {
+ mIDescrambler = MediaCas.getService().createDescrambler(CA_system_id);
+ } catch(Exception e) {
+ Log.e(TAG, "Failed to create descrambler: " + e);
+ mIDescrambler = null;
+ } finally {
+ if (mIDescrambler == null) {
+ throw new UnsupportedCasException("Unsupported CA_system_id " + CA_system_id);
+ }
+ }
+ native_setup(mIDescrambler.asBinder());
+ }
+
+ IBinder getBinder() {
+ validateInternalStates();
+
+ return mIDescrambler.asBinder();
+ }
+
+ /*
+ * TODO: handle ServiceSpecificException from the mIDescrambler
+ * All Drm-specific failures will be thrown by mIDescrambler as
+ * ServiceSpecificException exception with Drm error code.
+ * These need to be re-thrown as crypto exceptions.
+ */
+
+ /**
+ * Query if the scrambling scheme requires the use of a secure decoder
+ * to decode data of the given mime type.
+ *
+ * @param mime The mime type of the media data
+ *
+ * @throws IllegalStateException if the descrambler instance is not valid.
+ */
+ public final boolean requiresSecureDecoderComponent(@NonNull String mime) {
+ validateInternalStates();
+
+ try {
+ return mIDescrambler.requiresSecureDecoderComponent(mime);
+ } catch (RemoteException e) {
+ cleanupAndRethrowIllegalState();
+ }
+ return true;
+ }
+
+ /**
+ * Associate a MediaCas session with this MediaDescrambler instance.
+ * The MediaCas session is used to securely load decryption keys for
+ * the descrambler. The crypto keys loaded through the MediaCas session
+ * may be selected for use during the descrambling operation performed
+ * by {@link android.media.MediaExtractor or @link
+ * android.media.MediaCodec#queueSecureInputBuffer} by specifying even
+ * or odd key in the {@link android.media.MediaCodec.CryptoInfo#key} field.
+ *
+ * @param sessionId the MediaCas sessionId to associate with this
+ * MediaDescrambler instance.
+ *
+ * @throws IllegalStateException if the descrambler instance is not valid,
+ * or IllegalArgumentException if the sessionId is not valid.
+ */
+ public final void setMediaCasSession(@NonNull byte[] sessionId) {
+ validateInternalStates();
+
+ try {
+ mIDescrambler.setMediaCasSession(sessionId);
+ } catch (RemoteException e) {
+ cleanupAndRethrowIllegalState();
+ }
+ }
+
+ /**
+ * Descramble a ByteBuffer of data described by a
+ * {@link android.media.MediaCodec.CryptoInfo} structure.
+ *
+ * @param srcBuf ByteBuffer containing the scrambled data.
+ * @param srcPos position within src where the scrambled data starts.
+ * @param dstBuf ByteBuffer to descramble into. If null, descrambling will happen
+ * in-place and src will be used as dst.
+ * @param dstPos position within dst to put the descrambled data.
+ * @param cryptoInfo a {@link android.media.MediaCodec.CryptoInfo} structure
+ * describing the subsamples contained in src.
+ *
+ * @return number of bytes that have been successfully descrambled, with negative
+ * values indicating errors.
+ *
+ * @throws IllegalStateException if the descrambler instance is not valid.
+ */
+ /*
+ * TODO: throw DRM-specific exception if decrambling is failing.
+ */
+ public final int descramble(
+ @NonNull ByteBuffer srcBuf, int srcPos, ByteBuffer dstBuf, int dstPos,
+ @NonNull MediaCodec.CryptoInfo cryptoInfo) {
+ validateInternalStates();
+
+ if (cryptoInfo.numSubSamples <= 0) {
+ throw new IllegalArgumentException(
+ "Invalid CryptoInfo: invalid numSubSamples=" + cryptoInfo.numSubSamples);
+ } else if (cryptoInfo.numBytesOfClearData == null
+ && cryptoInfo.numBytesOfEncryptedData == null) {
+ throw new IllegalArgumentException(
+ "Invalid CryptoInfo: clearData and encryptedData size arrays are both null!");
+ } else if (cryptoInfo.numBytesOfClearData != null
+ && cryptoInfo.numBytesOfClearData.length < cryptoInfo.numSubSamples) {
+ throw new IllegalArgumentException(
+ "Invalid CryptoInfo: numBytesOfClearData is too small!");
+ } else if (cryptoInfo.numBytesOfEncryptedData != null
+ && cryptoInfo.numBytesOfEncryptedData.length < cryptoInfo.numSubSamples) {
+ throw new IllegalArgumentException(
+ "Invalid CryptoInfo: numBytesOfEncryptedData is too small!");
+ } else if (cryptoInfo.key == null || cryptoInfo.key.length != 16) {
+ throw new IllegalArgumentException(
+ "Invalid CryptoInfo: key array is invalid!");
+ }
+
+ return native_descramble(
+ cryptoInfo.key[0],
+ cryptoInfo.numSubSamples,
+ cryptoInfo.numBytesOfClearData,
+ cryptoInfo.numBytesOfEncryptedData,
+ srcBuf, srcPos, dstBuf, dstPos);
+ }
+
+ public final void release() {
+ if (mIDescrambler != null) {
+ try {
+ mIDescrambler.release();
+ } catch (RemoteException e) {
+ } finally {
+ mIDescrambler = null;
+ }
+ }
+ native_release();
+ }
+
+ @Override
+ protected void finalize() {
+ release();
+ }
+
+ private static native final void native_init();
+ private native final void native_setup(@NonNull IBinder decramblerBinder);
+ private native final void native_release();
+ private native final int native_descramble(
+ byte key, int numSubSamples, int[] numBytesOfClearData, int[] numBytesOfEncryptedData,
+ @NonNull ByteBuffer srcBuf, int srcOffset, ByteBuffer dstBuf, int dstOffset);
+
+ static {
+ System.loadLibrary("media_jni");
+ native_init();
+ }
+
+ private long mNativeContext;
+}
\ No newline at end of file
diff --git a/media/java/android/media/MediaExtractor.java b/media/java/android/media/MediaExtractor.java
index 2ca36ea..01ae36f 100644
--- a/media/java/android/media/MediaExtractor.java
+++ b/media/java/android/media/MediaExtractor.java
@@ -247,6 +247,22 @@
public native final void setDataSource(
@NonNull FileDescriptor fd, long offset, long length) throws IOException;
+ /**
+ * Sets the MediaCas instance to use. This should be called after a
+ * successful setDataSource() if at least one track reports mime type
+ * of {@link android.media.MediaFormat#MIMETYPE_AUDIO_SCRAMBLED}
+ * or {@link android.media.MediaFormat#MIMETYPE_VIDEO_SCRAMBLED}.
+ * Stream parsing will not proceed until a valid MediaCas object
+ * is provided.
+ *
+ * @param mediaCas the MediaCas object to use.
+ */
+ public final void setMediaCas(@NonNull MediaCas mediaCas) {
+ nativeSetMediaCas(mediaCas.getBinder());
+ }
+
+ private native final void nativeSetMediaCas(@NonNull IBinder casBinder);
+
@Override
protected void finalize() {
native_finalize();
@@ -290,6 +306,31 @@
return initDataMap.get(schemeUuid);
}
};
+ } else if (formatMap.containsKey("mime")
+ && "video/mp2ts".equals(formatMap.get("mime"))) {
+ final Map<UUID, DrmInitData.SchemeInitData> initDataMap =
+ new HashMap<UUID, DrmInitData.SchemeInitData>();
+
+ int numTracks = getTrackCount();
+ for (int i = 0; i < numTracks; ++i) {
+ Map<String, Object> trackFormatMap = getTrackFormatNative(i);
+ if (!trackFormatMap.containsKey("cas")) {
+ continue;
+ }
+ ByteBuffer buf = (ByteBuffer) trackFormatMap.get("cas");
+ buf.rewind();
+ final byte[] data = new byte[buf.remaining()];
+ buf.get(data);
+ initDataMap.put(new UUID(0, i), new DrmInitData.SchemeInitData("cas", data));
+ }
+ if (initDataMap.isEmpty()) {
+ return null;
+ }
+ return new DrmInitData() {
+ public SchemeInitData get(UUID schemeUuid) {
+ return initDataMap.get(schemeUuid);
+ }
+ };
} else {
int numTracks = getTrackCount();
for (int i = 0; i < numTracks; ++i) {
@@ -307,8 +348,8 @@
}
};
}
+ return null;
}
- return null;
}
/**
@@ -557,12 +598,22 @@
*/
public static final int SAMPLE_FLAG_ENCRYPTED = 2;
+ /**
+ * This indicates that the buffer only contains part of a frame,
+ * and the decoder should batch the data until a buffer without
+ * this flag appears before decoding the frame.
+ *
+ * @see MediaCodec#BUFFER_FLAG_PARTIAL_FRAME
+ */
+ public static final int SAMPLE_FLAG_PARTIAL_FRAME = 4;
+
/** @hide */
@IntDef(
flag = true,
value = {
SAMPLE_FLAG_SYNC,
SAMPLE_FLAG_ENCRYPTED,
+ SAMPLE_FLAG_PARTIAL_FRAME,
})
@Retention(RetentionPolicy.SOURCE)
public @interface SampleFlag {}
diff --git a/media/java/android/media/MediaFormat.java b/media/java/android/media/MediaFormat.java
index d74aa81..e77c00b 100644
--- a/media/java/android/media/MediaFormat.java
+++ b/media/java/android/media/MediaFormat.java
@@ -53,6 +53,7 @@
* time-interval between key frames.
* Float support added in {@link android.os.Build.VERSION_CODES#N_MR1}</td></tr>
* <tr><td>{@link #KEY_INTRA_REFRESH_PERIOD}</td><td>Integer</td><td><b>encoder-only</b>, optional</td></tr>
+ * <tr><td>{@link #KEY_LATENCY}</td><td>Integer</td><td><b>encoder-only</b>, optional</td></tr>
* <tr><td>{@link #KEY_MAX_WIDTH}</td><td>Integer</td><td><b>decoder-only</b>, optional, max-resolution width</td></tr>
* <tr><td>{@link #KEY_MAX_HEIGHT}</td><td>Integer</td><td><b>decoder-only</b>, optional, max-resolution height</td></tr>
* <tr><td>{@link #KEY_REPEAT_PREVIOUS_FRAME_AFTER}</td><td>Long</td><td><b>encoder in surface-mode
@@ -105,6 +106,8 @@
public static final String MIMETYPE_VIDEO_H263 = "video/3gpp";
public static final String MIMETYPE_VIDEO_MPEG2 = "video/mpeg2";
public static final String MIMETYPE_VIDEO_RAW = "video/raw";
+ public static final String MIMETYPE_VIDEO_DOLBY_VISION = "video/dolby-vision";
+ public static final String MIMETYPE_VIDEO_SCRAMBLED = "video/scrambled";
public static final String MIMETYPE_AUDIO_AMR_NB = "audio/3gpp";
public static final String MIMETYPE_AUDIO_AMR_WB = "audio/amr-wb";
@@ -120,7 +123,7 @@
public static final String MIMETYPE_AUDIO_MSGSM = "audio/gsm";
public static final String MIMETYPE_AUDIO_AC3 = "audio/ac3";
public static final String MIMETYPE_AUDIO_EAC3 = "audio/eac3";
- public static final String MIMETYPE_VIDEO_DOLBY_VISION = "video/dolby-vision";
+ public static final String MIMETYPE_AUDIO_SCRAMBLED = "audio/scrambled";
/**
* MIME type for WebVTT subtitle data.
@@ -575,6 +578,18 @@
public static final String KEY_LEVEL = "level";
/**
+ * An optional key describing the desired encoder latency in frames. This is an optional
+ * parameter that applies only to video encoders. If encoder supports it, it should ouput
+ * at least one output frame after being queued the specified number of frames. This key
+ * is ignored if the video encoder does not support the latency feature. Use the output
+ * format to verify that this feature was enabled and the actual value used by the encoder.
+ * <p>
+ * If the key is not specified, the default latency will be implenmentation specific.
+ * The associated value is an integer.
+ */
+ public static final String KEY_LATENCY = "latency";
+
+ /**
* A key describing the desired clockwise rotation on an output surface.
* This key is only used when the codec is configured using an output surface.
* The associated value is an integer, representing degrees. Supported values
diff --git a/media/java/android/media/MediaMuxer.java b/media/java/android/media/MediaMuxer.java
index aacce91..832b297 100644
--- a/media/java/android/media/MediaMuxer.java
+++ b/media/java/android/media/MediaMuxer.java
@@ -68,44 +68,46 @@
<h4>Metadata Track</h4>
<p>
- Metadata is usefule in carrying extra information that correlated with video or audio to
- facilate offline processing, e.g. gyro signals from the sensor. Meatadata track is only
- supported in MP4 format. When adding a metadata track, track's mime format must start with
- prefix "application/", e.g. "applicaton/gyro". Metadata's format/layout will be defined by
- the application. The generated MP4 file uses TextMetaDataSampleEntry defined in section 12.3.3.2
- of the ISOBMFF to signal the metadata's mime format. When using {@link android.media.MediaExtractor}
- to extract the file with metadata track, the mime format of the metadata will be extracted into
- {@link android.media.MediaFormat}.
+ Per-frame metadata is useful in carrying extra information that correlated with video or audio to
+ facilitate offline processing, e.g. gyro signals from the sensor could help video stabilization when
+ doing offline processing. Metaadata track is only supported in MP4 container. When adding a new
+ metadata track, track's mime format must start with prefix "application/", e.g. "applicaton/gyro".
+ Metadata's format/layout will be defined by the application. Writing metadata is nearly the same as
+ writing video/audio data except that the data will not be from mediacodec. Application just needs
+ to pass the bytebuffer that contains the metadata and also the associated timestamp to the
+ {@link #writeSampleData} api. The timestamp must be in the same time base as video and audio. The
+ generated MP4 file uses TextMetaDataSampleEntry defined in section 12.3.3.2 of the ISOBMFF to signal
+ the metadata's mime format. When using{@link android.media.MediaExtractor} to extract the file with
+ metadata track, the mime format of the metadata will be extracted into {@link android.media.MediaFormat}.
<pre class=prettyprint>
MediaMuxer muxer = new MediaMuxer("temp.mp4", OutputFormat.MUXER_OUTPUT_MPEG_4);
- // More often, the MediaFormat will be retrieved from MediaCodec.getOutputFormat()
- // or MediaExtractor.getTrackFormat().
+ // SetUp Video/Audio Tracks.
MediaFormat audioFormat = new MediaFormat(...);
MediaFormat videoFormat = new MediaFormat(...);
+ int audioTrackIndex = muxer.addTrack(audioFormat);
+ int videoTrackIndex = muxer.addTrack(videoFormat);
// Setup Metadata Track
MediaFormat metadataFormat = new MediaFormat(...);
metadataFormat.setString(KEY_MIME, "application/gyro");
-
- int audioTrackIndex = muxer.addTrack(audioFormat);
- int videoTrackIndex = muxer.addTrack(videoFormat);
int metadataTrackIndex = muxer.addTrack(metadataFormat);
- ByteBuffer inputBuffer = ByteBuffer.allocate(bufferSize);
- boolean finished = false;
- BufferInfo bufferInfo = new BufferInfo();
muxer.start();
- while(!finished) {
- // getInputBuffer() will fill the inputBuffer with one frame of encoded
- // sample from either MediaCodec or MediaExtractor, set isAudioSample to
- // true when the sample is audio data, set up all the fields of bufferInfo,
- // and return true if there are no more samples.
- finished = getInputBuffer(inputBuffer, sampleType, bufferInfo);
- if (!finished) {
- int currentTrackIndex = getTrackIndex(sampleType);
- muxer.writeSampleData(currentTrackIndex, inputBuffer, bufferInfo);
- }
+ while(..) {
+ // Allocate bytebuffer and write gyro data(x,y,z) into it.
+ ByteBuffer metaData = ByteBuffer.allocate(bufferSize);
+ metaData.putFloat(x);
+ metaData.putFloat(y);
+ metaData.putFloat(z);
+ BufferInfo metaInfo = new BufferInfo();
+ // Associate this metadata with the video frame by setting
+ // the same timestamp as the video frame.
+ metaInfo.presentationTimeUs = currentVideoTrackTimeUs;
+ metaInfo.offset = 0;
+ metaInfo.flags = 0;
+ metaInfo.size = bufferSize;
+ muxer.writeSampleData(metadataTrackIndex, metaData, metaInfo);
};
muxer.stop();
muxer.release();
diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java
index 5008a5f..fb37f9f 100644
--- a/media/java/android/media/MediaPlayer.java
+++ b/media/java/android/media/MediaPlayer.java
@@ -579,6 +579,7 @@
*/
public class MediaPlayer extends PlayerBase
implements SubtitleController.Listener
+ , VolumeAutomation
{
/**
Constant to retrieve only the new metadata since the last
@@ -1250,6 +1251,11 @@
public void prepare() throws IOException, IllegalStateException {
_prepare();
scanInternalSubtitleTracks();
+
+ // DrmInfo, if any, has been resolved by now.
+ synchronized (mDrmLock) {
+ mDrmInfoResolved = true;
+ }
}
private native void _prepare() throws IOException, IllegalStateException;
@@ -1373,6 +1379,12 @@
return native_getVolumeShaperState(id);
}
+ @Override
+ public @NonNull VolumeShaper createVolumeShaper(
+ @NonNull VolumeShaper.Configuration configuration) {
+ return new VolumeShaper(configuration, this);
+ }
+
private native int native_applyVolumeShaper(
@NonNull VolumeShaper.Configuration configuration,
@NonNull VolumeShaper.Operation operation);
@@ -3142,12 +3154,6 @@
sendMessage(msg2);
}
- // MEDIA_DRM_INFO is fired (if available) before MEDIA_PREPARED.
- // An empty mDrmInfo indicates prepared is done but the source is not DRM protected.
- // Setting this before the callback so onPreparedListener can call getDrmInfo to
- // get the right state
- mDrmInfoResolved = true;
-
OnPreparedListener onPreparedListener = mOnPreparedListener;
if (onPreparedListener != null)
onPreparedListener.onPrepared(mMediaPlayer);
@@ -3159,12 +3165,14 @@
if (msg.obj == null) {
Log.w(TAG, "MEDIA_DRM_INFO msg.obj=NULL");
} else if (msg.obj instanceof Parcel) {
- Parcel parcel = (Parcel)msg.obj;
- DrmInfo drmInfo = new DrmInfo(parcel);
+ // The parcel was parsed already in postEventFromNative
+ DrmInfo drmInfo = null;
OnDrmInfoHandlerDelegate onDrmInfoHandlerDelegate;
synchronized (mDrmLock) {
- mDrmInfo = drmInfo.makeCopy();
+ if (mOnDrmInfoHandlerDelegate != null && mDrmInfo != null) {
+ drmInfo = mDrmInfo.makeCopy();
+ }
// local copy while keeping the lock
onDrmInfoHandlerDelegate = mOnDrmInfoHandlerDelegate;
}
@@ -3359,10 +3367,43 @@
return;
}
- if (what == MEDIA_INFO && arg1 == MEDIA_INFO_STARTED_AS_NEXT) {
- // this acquires the wakelock if needed, and sets the client side state
- mp.start();
+ switch (what) {
+ case MEDIA_INFO:
+ if (arg1 == MEDIA_INFO_STARTED_AS_NEXT) {
+ // this acquires the wakelock if needed, and sets the client side state
+ mp.start();
+ }
+ break;
+
+ case MEDIA_DRM_INFO:
+ // We need to derive mDrmInfo before prepare() returns so processing it here
+ // before the notification is sent to EventHandler below. EventHandler runs in the
+ // notification looper so its handleMessage might process the event after prepare()
+ // has returned.
+ Log.v(TAG, "postEventFromNative MEDIA_DRM_INFO");
+ if (obj instanceof Parcel) {
+ Parcel parcel = (Parcel)obj;
+ DrmInfo drmInfo = new DrmInfo(parcel);
+ synchronized (mp.mDrmLock) {
+ mp.mDrmInfo = drmInfo;
+ }
+ } else {
+ Log.w(TAG, "MEDIA_DRM_INFO msg.obj of unexpected type " + obj);
+ }
+ break;
+
+ case MEDIA_PREPARED:
+ // By this time, we've learned about DrmInfo's presence or absence. This is meant
+ // mainly for prepareAsync() use case. For prepare(), this still can run to a race
+ // condition b/c MediaPlayerNative releases the prepare() lock before calling notify
+ // so we also set mDrmInfoResolved in prepare().
+ synchronized (mp.mDrmLock) {
+ mp.mDrmInfoResolved = true;
+ }
+ break;
+
}
+
if (mp.mEventHandler != null) {
Message m = mp.mEventHandler.obtainMessage(what, arg1, arg2, obj);
mp.mEventHandler.sendMessage(m);
@@ -4086,16 +4127,16 @@
* If the device has not been provisioned before, this call also provisions the device
* which involves accessing the provisioning server and can take a variable time to
* complete depending on the network connectivity.
- * If OnDrmPreparedListener is registered, prepareDrm() runs in non-blocking
+ * If {@code OnDrmPreparedListener} is registered, prepareDrm() runs in non-blocking
* mode by launching the provisioning in the background and returning. The listener
* will be called when provisioning and preperation has finished. If a
- * OnDrmPreparedListener is not registered, prepareDrm() waits till provisioning
+ * {@code OnDrmPreparedListener} is not registered, prepareDrm() waits till provisioning
* and preperation has finished, i.e., runs in blocking mode.
* <p>
- * If OnDrmPreparedListener is registered, it is called to indicated the DRM session
- * being ready regardless of blocking or non-blocking mode. The application should
- * not make any assumption about its call sequence (e.g., before or after prepareDrm
- * returns) or the thread context that will execute the listener.
+ * If {@code OnDrmPreparedListener} is registered, it is called to indicate the DRM
+ * session being ready. The application should not make any assumption about its call
+ * sequence (e.g., before or after prepareDrm returns), or the thread context that will
+ * execute the listener (unless the listener is registered with a handler thread).
* <p>
*
* @param uuid The UUID of the crypto scheme.
diff --git a/media/java/android/media/PlayerBase.java b/media/java/android/media/PlayerBase.java
index b397b45..1f5986f 100644
--- a/media/java/android/media/PlayerBase.java
+++ b/media/java/android/media/PlayerBase.java
@@ -58,7 +58,7 @@
protected float mAuxEffectSendLevel = 0.0f;
// for AppOps
- private IAppOpsService mAppOps;
+ private IAppOpsService mAppOps; // may be null
private IAppOpsCallback mAppOpsCallback;
private boolean mHasAppOpsPlayAudio = true; // sync'd on mLock
private final Object mLock = new Object();
@@ -251,7 +251,9 @@
Log.e(TAG, "Error talking to audio service, the player will still be tracked", e);
}
try {
- mAppOps.stopWatchingMode(mAppOpsCallback);
+ if (mAppOps != null) {
+ mAppOps.stopWatchingMode(mAppOpsCallback);
+ }
} catch (RemoteException e) {
// nothing to do here, the object is supposed to be released anyway
}
@@ -264,9 +266,12 @@
void updateAppOpsPlayAudio_sync() {
boolean oldHasAppOpsPlayAudio = mHasAppOpsPlayAudio;
try {
- final int mode = mAppOps.checkAudioOperation(AppOpsManager.OP_PLAY_AUDIO,
+ int mode = AppOpsManager.MODE_IGNORED;
+ if (mAppOps != null) {
+ mode = mAppOps.checkAudioOperation(AppOpsManager.OP_PLAY_AUDIO,
mAttributes.getUsage(),
Process.myUid(), ActivityThread.currentPackageName());
+ }
mHasAppOpsPlayAudio = (mode == AppOpsManager.MODE_ALLOWED);
} catch (RemoteException e) {
mHasAppOpsPlayAudio = false;
diff --git a/media/java/android/media/RingtoneManager.java b/media/java/android/media/RingtoneManager.java
index 8a1027b..e774c71 100644
--- a/media/java/android/media/RingtoneManager.java
+++ b/media/java/android/media/RingtoneManager.java
@@ -103,10 +103,6 @@
*/
public static final int TYPE_ALL = TYPE_RINGTONE | TYPE_NOTIFICATION | TYPE_ALARM;
- private static final int[] RINGTONE_TYPES = {
- TYPE_RINGTONE, TYPE_NOTIFICATION, TYPE_ALARM
- };
-
// </attr>
/**
@@ -773,30 +769,17 @@
}
/**
- * Disables Settings.System.SYNC_PARENT_SOUNDS, copying the parent's ringtones to the current
- * profile
+ * Disables Settings.System.SYNC_PARENT_SOUNDS.
*
* @hide
*/
- @RequiresPermission(Manifest.permission.WRITE_SECURE_SETTINGS)
public static void disableSyncFromParent(Context userContext) {
- // Must disable sync first so that ringtone copy below doesn't get redirected to parent
- Settings.Secure.putIntForUser(userContext.getContentResolver(),
- Settings.Secure.SYNC_PARENT_SOUNDS, 0 /* false */, userContext.getUserId());
-
- // Copy ringtones from parent profile
- UserManager um = UserManager.get(userContext);
- UserInfo parentInfo = um.getProfileParent(userContext.getUserId());
- if (parentInfo != null) {
- final Context targetContext = createPackageContextAsUser(userContext, parentInfo.id);
- if (targetContext != null) {
- for (int ringtoneType : RINGTONE_TYPES) {
- Uri ringtoneUri = getActualDefaultRingtoneUri(targetContext, ringtoneType);
- // Add user id of parent so that custom ringtones can be read and played
- RingtoneManager.setActualDefaultRingtoneUri(userContext, ringtoneType,
- maybeAddUserId(ringtoneUri, parentInfo.id));
- }
- }
+ IBinder b = ServiceManager.getService(Context.AUDIO_SERVICE);
+ IAudioService audioService = IAudioService.Stub.asInterface(b);
+ try {
+ audioService.disableRingtoneSync(userContext.getUserId());
+ } catch (RemoteException e) {
+ Log.e(TAG, "Unable to disable ringtone sync.");
}
}
@@ -851,22 +834,15 @@
* @see #getActualDefaultRingtoneUri(Context, int)
*/
public static void setActualDefaultRingtoneUri(Context context, int type, Uri ringtoneUri) {
- final ContentResolver resolver = context.getContentResolver();
-
- if (Settings.Secure.getString(resolver, Settings.Secure.SYNC_PARENT_SOUNDS).equals("1")) {
- // Sync is enabled, so we need to disable it
- IBinder b = ServiceManager.getService(Context.AUDIO_SERVICE);
- IAudioService audioService = IAudioService.Stub.asInterface(b);
- try {
- audioService.disableRingtoneSync();
- } catch (RemoteException e) {
- Log.e(TAG, "Unable to disable ringtone sync.");
- return;
- }
- }
-
String setting = getSettingForType(type);
if (setting == null) return;
+
+ final ContentResolver resolver = context.getContentResolver();
+ if (Settings.Secure.getIntForUser(resolver, Settings.Secure.SYNC_PARENT_SOUNDS, 0,
+ context.getUserId()) == 1) {
+ // Parent sound override is enabled. Disable it using the audio service.
+ disableSyncFromParent(context);
+ }
if(!isInternalRingtoneUri(ringtoneUri)) {
ringtoneUri = ContentProvider.maybeAddUserId(ringtoneUri, context.getUserId());
}
diff --git a/media/java/android/media/UnsupportedCasException.java b/media/java/android/media/UnsupportedCasException.java
new file mode 100644
index 0000000..3167637
--- /dev/null
+++ b/media/java/android/media/UnsupportedCasException.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2017 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.media;
+
+/**
+ * Exception thrown when an attempt is made to construct a MediaCas object
+ * using a CA_system_id that is not supported by the device
+ */
+public final class UnsupportedCasException extends MediaCasException {
+ public UnsupportedCasException(String detailMessage) {
+ super(detailMessage);
+ }
+}
diff --git a/media/java/android/media/VolumeAutomation.java b/media/java/android/media/VolumeAutomation.java
new file mode 100644
index 0000000..dff8801
--- /dev/null
+++ b/media/java/android/media/VolumeAutomation.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2017 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.media;
+
+import android.annotation.NonNull;
+import android.media.VolumeShaper.Configuration;
+
+/**
+ * {@code VolumeAutomation} defines an interface for automatic volume control
+ * of {@link AudioTrack} and {@link MediaPlayer} objects.
+ */
+public interface VolumeAutomation {
+ /**
+ * Returns a {@link VolumeShaper} object that can be used modify the volume envelope
+ * of the player or track.
+ *
+ * @param configuration the {@link VolumeShaper.Configuration configuration}
+ * that specifies the curve and duration to use.
+ * @return a {@code VolumeShaper} object
+ * @throws IllegalArgumentException if the configuration is not allowed by the player.
+ * @throws IllegalStateException if too many VolumeShapers are requested or the state of
+ * the player does not permit its creation (e.g. player is released).
+ */
+ public @NonNull VolumeShaper createVolumeShaper(
+ @NonNull VolumeShaper.Configuration configuration);
+}
diff --git a/media/java/android/media/VolumeShaper.java b/media/java/android/media/VolumeShaper.java
index 4a2c4d8..cb27d10 100644
--- a/media/java/android/media/VolumeShaper.java
+++ b/media/java/android/media/VolumeShaper.java
@@ -23,78 +23,25 @@
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.lang.AutoCloseable;
import java.lang.ref.WeakReference;
import java.util.Objects;
/**
- * TODO: remove @hide
* The {@code VolumeShaper} class is used to automatically control audio volume during media
- * playback, allowing for simple implementation of transition effects and ducking.
+ * playback, allowing simple implementation of transition effects and ducking.
*
* The {@link VolumeShaper} appears as an additional scaling on the audio output,
- * and can be used independently of track or stream volume controls.
+ * and adjusts independently of track or stream volume controls.
*/
-public final class VolumeShaper {
+public final class VolumeShaper implements AutoCloseable {
/* member variables */
private int mId;
private final WeakReference<PlayerBase> mWeakPlayerBase;
- private final WeakReference<PlayerProxy> mWeakPlayerProxy;
- private PlayerProxy mPlayerProxy;
-
- /**
- * Constructs a {@code VolumeShaper} from a {@link VolumeShaper.Configuration} and an
- * {@link AudioTrack}.
- *
- * @param configuration
- * @param audioTrack
- */
- public VolumeShaper(@NonNull Configuration configuration, @NonNull AudioTrack audioTrack) {
- this(configuration, (PlayerBase)audioTrack);
- }
-
- /**
- * Constructs a {@code VolumeShaper} from a {@link VolumeShaper.Configuration} and a
- * {@link MediaPlayer}.
- *
- * @param configuration
- * @param mediaPlayer
- */
- public VolumeShaper(@NonNull Configuration configuration, @NonNull MediaPlayer mediaPlayer) {
- this(configuration, (PlayerBase)mediaPlayer);
- }
/* package */ VolumeShaper(
@NonNull Configuration configuration, @NonNull PlayerBase playerBase) {
mWeakPlayerBase = new WeakReference<PlayerBase>(playerBase);
- mPlayerProxy = null;
- mWeakPlayerProxy = null;
- mId = applyPlayer(configuration, new Operation.Builder().defer().build());
- }
-
- /**
- * @hide
- * Constructs a {@code VolumeShaper} from a {@link VolumeShaper.Configuration} and a
- * {@code PlayerProxy} object. The PlayerProxy object requires that the configuration
- * be set with a system VolumeShaper id (this is a reserved value).
- *
- * @param configuration
- * @param playerProxy
- */
- public VolumeShaper(
- @NonNull Configuration configuration,
- @NonNull PlayerProxy playerProxy,
- boolean keepReference) {
- if (configuration.getId() < 0) {
- throw new IllegalArgumentException("playerProxy configuration id must be specified");
- }
- if (keepReference) {
- mPlayerProxy = playerProxy;
- mWeakPlayerProxy = null;
- } else {
- mWeakPlayerProxy = new WeakReference<PlayerProxy>(playerProxy);
- mPlayerProxy = null;
- }
- mWeakPlayerBase = null;
mId = applyPlayer(configuration, new Operation.Builder().defer().build());
}
@@ -104,7 +51,7 @@
/**
* Applies the {@link VolumeShaper.Operation} to the {@code VolumeShaper}.
- * @param operation
+ * @param operation the {@code operation} to apply.
*/
public void apply(@NonNull Operation operation) {
/* void */ applyPlayer(new VolumeShaper.Configuration(mId), operation);
@@ -112,17 +59,16 @@
/**
* Replaces the current {@code VolumeShaper}
- * configuration with a new configuration.
+ * {@code configuration} with a new {@code configuration}.
*
- * This can be used to dynamically change the {@code VolumeShaper}
- * configuration by joining several
- * {@code VolumeShaper} configurations together.
- * This is useful if the user changes the volume while the
- * {@code VolumeShaper} is in effect.
+ * This allows the user to change the volume shape
+ * while the existing {@code VolumeShaper} is in effect.
*
- * @param configuration
- * @param operation
- * @param join
+ * @param configuration the new {@code configuration} to use.
+ * @param operation the operation to apply to the {@code VolumeShaper}
+ * @param join if true, match the start volume of the
+ * new {@code configuration} to the current volume of the existing
+ * {@code VolumeShaper}, to avoid discontinuity.
*/
public void replace(
@NonNull Configuration configuration, @NonNull Operation operation, boolean join) {
@@ -141,10 +87,11 @@
}
/**
- * Releases the {@code VolumeShaper}. Any volume scale due to the
+ * Releases the {@code VolumeShaper} object; any volume scale due to the
* {@code VolumeShaper} is removed.
*/
- public void release() {
+ @Override
+ public void close() {
try {
/* void */ applyPlayer(
new VolumeShaper.Configuration(mId),
@@ -155,15 +102,11 @@
if (mWeakPlayerBase != null) {
mWeakPlayerBase.clear();
}
- if (mWeakPlayerProxy != null) {
- mWeakPlayerProxy.clear();
- }
- mPlayerProxy = null;
}
@Override
protected void finalize() {
- release(); // ensure we remove the native volume shaper
+ close(); // ensure we remove the native volume shaper
}
/**
@@ -177,20 +120,7 @@
@NonNull VolumeShaper.Configuration configuration,
@NonNull VolumeShaper.Operation operation) {
final int id;
- if (mPlayerProxy != null || mWeakPlayerProxy != null) {
- // The PlayerProxy accepts only one way transactions so
- // the Configuration must have an id set to one of the system
- // ids (a positive value less than 16).
- PlayerProxy player = mWeakPlayerProxy != null ? mWeakPlayerProxy.get() : mPlayerProxy;
- if (player == null) {
- throw new IllegalStateException("player deallocated");
- }
- id = configuration.getId();
- if (id < 0) {
- throw new IllegalArgumentException("proxy requires configuration with id");
- }
- player.applyVolumeShaper(configuration, operation);
- } else if (mWeakPlayerBase != null) {
+ if (mWeakPlayerBase != null) {
PlayerBase player = mWeakPlayerBase.get();
if (player == null) {
throw new IllegalStateException("player deallocated");
@@ -220,9 +150,7 @@
*/
private @NonNull VolumeShaper.State getStatePlayer(int id) {
final VolumeShaper.State state;
- if (mPlayerProxy != null || mWeakPlayerProxy != null) {
- throw new IllegalStateException("getStatePlayer not permitted through proxy");
- } else if (mWeakPlayerBase != null) {
+ if (mWeakPlayerBase != null) {
PlayerBase player = mWeakPlayerBase.get();
if (player == null) {
throw new IllegalStateException("player deallocated");
@@ -238,11 +166,17 @@
}
/**
- * The {@code VolumeShaper.Configuration} class contains curve shape
- * and parameter information for constructing a {@code VolumeShaper}.
- * This curve shape and parameter information is specified
- * on {@code VolumeShaper} creation
- * and may be replaced through {@link VolumeShaper#replace}.
+ * The {@code VolumeShaper.Configuration} class contains curve
+ * and duration information.
+ * It is constructed by the {@link VolumeShaper.Configuration.Builder}.
+ * <p>
+ * A {@code VolumeShaper.Configuration} is used by
+ * {@link VolumeAutomation#createVolumeShaper(Configuration)
+ * VolumeAutomation#createVolumeShaper(Configuration)} to create
+ * a {@code VolumeShaper} and
+ * by {@link VolumeShaper#replace(Configuration, Operation, boolean)
+ * VolumeShaper#replace(Configuration, Operation, boolean)}
+ * to replace an existing {@code configuration}.
*/
public static final class Configuration implements Parcelable {
private static final int MAXIMUM_CURVE_POINTS = 16;
@@ -310,9 +244,9 @@
/**
* Cubic interpolated volume curve
- * with local monotonicity preservation.
+ * that preserves local monotonicity.
* So long as the control points are locally monotonic,
- * the curve interpolation will also be locally monotonic.
+ * the curve interpolation between those points are monotonic.
* This is useful for cubic spline interpolated
* volume ramps and ducks.
*/
@@ -328,6 +262,7 @@
public @interface OptionFlag {}
/**
+ * @hide
* Use a dB full scale volume range for the volume curve.
*<p>
* The volume scale is typically from 0.f to 1.f on a linear scale;
@@ -337,6 +272,7 @@
public static final int OPTION_FLAG_VOLUME_IN_DBFS = (1 << 0);
/**
+ * @hide
* Use clock time instead of media time.
*<p>
* The default implementation of {@code VolumeShaper} is to apply
@@ -354,7 +290,8 @@
/**
* A one second linear ramp from silence to full volume.
- * Use {@link VolumeShaper.Builder#reflectTimes()} to generate
+ * Use {@link VolumeShaper.Builder#reflectTimes()}
+ * or {@link VolumeShaper.Builder#invertVolumes()} to generate
* the matching linear duck.
*/
public static final Configuration LINEAR_RAMP = new VolumeShaper.Configuration.Builder()
@@ -366,7 +303,8 @@
/**
* A one second cubic ramp from silence to full volume.
- * Use {@link VolumeShaper.Builder#reflectTimes()} to generate
+ * Use {@link VolumeShaper.Builder#reflectTimes()}
+ * or {@link VolumeShaper.Builder#invertVolumes()} to generate
* the matching cubic duck.
*/
public static final Configuration CUBIC_RAMP = new VolumeShaper.Configuration.Builder()
@@ -377,17 +315,19 @@
.build();
/**
- * A one second sine curve for energy preserving cross fades.
+ * A one second sine curve
+ * from silence to full volume for energy preserving cross fades.
* Use {@link VolumeShaper.Builder#reflectTimes()} to generate
* the matching cosine duck.
*/
public static final Configuration SINE_RAMP;
/**
- * A one second sine-squared s-curve ramp.
+ * A one second sine-squared s-curve ramp
+ * from silence to full volume.
* Use {@link VolumeShaper.Builder#reflectTimes()}
* or {@link VolumeShaper.Builder#invertVolumes()} to generate
- * the matching s-curve duck.
+ * the matching sine-squared s-curve duck.
*/
public static final Configuration SCURVE_RAMP;
@@ -510,6 +450,7 @@
};
/**
+ * @hide
* Constructs a volume shaper from an id.
*
* This is an opaque handle for controlling a {@code VolumeShaper} that has
@@ -522,7 +463,7 @@
* @param id
* @throws IllegalArgumentException if id is negative.
*/
- private Configuration(int id) {
+ public Configuration(int id) {
if (id < 0) {
throw new IllegalArgumentException("negative id " + id);
}
@@ -557,6 +498,7 @@
}
/**
+ * @hide
* Returns the {@code VolumeShaper} type.
*/
public @Type int getType() {
@@ -579,6 +521,7 @@
}
/**
+ * @hide
* Returns the option flags
*/
public @OptionFlag int getOptionFlags() {
@@ -590,7 +533,7 @@
}
/**
- * Returns the duration of the effect in milliseconds.
+ * Returns the duration of the volume shape in milliseconds.
*/
public double getDurationMs() {
return mDurationMs;
@@ -712,21 +655,22 @@
private int mType = TYPE_SCALE;
private int mId = -1; // invalid
private int mInterpolatorType = INTERPOLATOR_TYPE_CUBIC;
- private int mOptionFlags = 0;
+ private int mOptionFlags = OPTION_FLAG_CLOCK_TIME;
private double mDurationMs = 1000.;
private float[] mTimes = null;
private float[] mVolumes = null;
/**
- * Constructs a new Builder with the defaults.
+ * Constructs a new {@code Builder} with the defaults.
*/
public Builder() {
}
/**
- * Constructs a new Builder from a given {@code VolumeShaper.Configuration}
+ * Constructs a new {@code Builder} with settings
+ * copied from a given {@code VolumeShaper.Configuration}.
* @param configuration prototypical configuration
- * which will be reused in the new Builder.
+ * which will be reused in the new {@code Builder}.
*/
public Builder(@NonNull Configuration configuration) {
mType = configuration.getType();
@@ -740,8 +684,6 @@
/**
* @hide
- * TODO make SystemApi
- *
* Set the id for system defined shapers.
* @param id
* @return
@@ -757,7 +699,11 @@
* If omitted the interplator type is {@link #INTERPOLATOR_TYPE_CUBIC}.
*
* @param interpolatorType method of interpolation used for the volume curve.
- * @return the same Builder instance.
+ * One of {@link #INTERPOLATOR_TYPE_STEP},
+ * {@link #INTERPOLATOR_TYPE_LINEAR},
+ * {@link #INTERPOLATOR_TYPE_CUBIC},
+ * {@link #INTERPOLATOR_TYPE_CUBIC_MONOTONIC}.
+ * @return the same {@code Builder} instance.
* @throws IllegalArgumentException if {@code interpolatorType} is not valid.
*/
public @NonNull Builder setInterpolatorType(@InterpolatorType int interpolatorType) {
@@ -776,6 +722,7 @@
}
/**
+ * @hide
* Sets the optional flags
*
* If omitted, flags are 0. If {@link #OPTION_FLAG_VOLUME_IN_DBFS} has
@@ -783,7 +730,7 @@
* volume domain has changed.
*
* @param optionFlags new value to replace the old {@code optionFlags}.
- * @return the same Builder instance.
+ * @return the same {@code Builder} instance.
* @throws IllegalArgumentException if flag is not recognized.
*/
public @NonNull Builder setOptionFlags(@OptionFlag int optionFlags) {
@@ -800,8 +747,9 @@
* If omitted, the default duration is 1 second.
*
* @param durationMs
- * @return the same Builder instance.
- * @throws IllegalArgumentException if duration is not positive.
+ * @return the same {@code Builder} instance.
+ * @throws IllegalArgumentException if {@code durationMs}
+ * is not strictly positive.
*/
public @NonNull Builder setDurationMs(double durationMs) {
if (durationMs <= 0.) {
@@ -823,19 +771,23 @@
* and no greater than {@link VolumeShaper.Configuration#getMaximumCurvePoints()}.
* <p>
* The volume curve is normalized as follows:
- * (1) time (x) coordinates should be monotonically increasing, from 0.f to 1.f;
- * (2) volume (y) coordinates must be within 0.f to 1.f for linear and be non-positive
- * for log scaling.
+ * time (x) coordinates should be monotonically increasing, from 0.f to 1.f;
+ * volume (y) coordinates must be within 0.f to 1.f.
* <p>
- * The time scale is set by {@link #setDurationMs} in seconds.
+ * The time scale is set by {@link #setDurationMs}.
* <p>
* @param times an array of float values representing
* the time line of the volume curve.
* @param volumes an array of float values representing
* the amplitude of the volume curve.
- * @return the same Builder instance.
+ * @return the same {@code Builder} instance.
* @throws IllegalArgumentException if {@code times} or {@code volumes} is invalid.
*/
+
+ /* Note: volume (y) coordinates must be non-positive for log scaling,
+ * if {@link VolumeShaper.Configuration#OPTION_FLAG_VOLUME_IN_DBFS} is set.
+ */
+
public @NonNull Builder setCurve(@NonNull float[] times, @NonNull float[] volumes) {
String error = checkCurveForErrors(
times, volumes, (mOptionFlags & OPTION_FLAG_VOLUME_IN_DBFS) != 0);
@@ -852,7 +804,7 @@
* the shaper changes volume from the end
* to the start.
*
- * @return the same Builder instance.
+ * @return the same {@code Builder} instance.
*/
public @NonNull Builder reflectTimes() {
int i;
@@ -871,7 +823,7 @@
* Inverts the volume curve so that the max volume
* becomes the min volume and vice versa.
*
- * @return the same Builder instance.
+ * @return the same {@code Builder} instance.
*/
public @NonNull Builder invertVolumes() {
if (mVolumes.length >= 2) {
@@ -899,8 +851,9 @@
* Keeps the start volume the same.
* This works best if the volume curve is monotonic.
*
- * @return the same Builder instance.
- * @throws IllegalArgumentException if volume is not valid.
+ * @param volume the target end volume to use.
+ * @return the same {@code Builder} instance.
+ * @throws IllegalArgumentException if {@code volume} is not valid.
*/
public @NonNull Builder scaleToEndVolume(float volume) {
final boolean log = (mOptionFlags & OPTION_FLAG_VOLUME_IN_DBFS) != 0;
@@ -930,8 +883,9 @@
* Keeps the end volume the same.
* This works best if the volume curve is monotonic.
*
- * @return the same Builder instance.
- * @throws IllegalArgumentException if volume is not valid.
+ * @param volume the target start volume to use.
+ * @return the same {@code Builder} instance.
+ * @throws IllegalArgumentException if {@code volume} is not valid.
*/
public @NonNull Builder scaleToStartVolume(float volume) {
final boolean log = (mOptionFlags & OPTION_FLAG_VOLUME_IN_DBFS) != 0;
@@ -978,6 +932,8 @@
public static final class Operation implements Parcelable {
/**
* Forward playback from current volume time position.
+ * At the end of the {@code VolumeShaper} curve,
+ * the last volume value persists.
*/
public static final Operation PLAY =
new VolumeShaper.Operation.Builder()
@@ -985,6 +941,8 @@
/**
* Reverse playback from current volume time position.
+ * When the position reaches the start of the {@code VolumeShaper} curve,
+ * the first volume value persists.
*/
public static final Operation REVERSE =
new VolumeShaper.Operation.Builder()
@@ -1039,6 +997,13 @@
*/
private static final int FLAG_DEFER = 1 << 3;
+ /**
+ * Use the id specified in the configuration, creating
+ * VolumeShaper as needed; the configuration should be
+ * TYPE_SCALE.
+ */
+ private static final int FLAG_CREATE_IF_NEEDED = 1 << 4;
+
private static final int FLAG_PUBLIC_ALL = FLAG_REVERSE | FLAG_TERMINATE;
private final int mFlags;
@@ -1126,15 +1091,13 @@
}
/**
- * Replaces the previous {@code VolumeShaper}.
+ * Replaces the previous {@code VolumeShaper} specified by id.
* It has no other effect if the {@code VolumeShaper} is
- * already expired. If the replaceId is the same as the id associated with
- * the {@code VolumeShaper} in a {@code setVolumeShaper()} call,
- * an error is returned.
- * @param handle is a previous volumeShaper {@code VolumeShaper}.
- * @param join the start to match the current volume of the previous
- * shaper.
- * @return the same Builder instance.
+ * already expired.
+ * @param id the id of the previous {@code VolumeShaper}.
+ * @param join if true, match the volume of the previous
+ * shaper to the start volume of the new {@code VolumeShaper}.
+ * @return the same {@code Builder} instance.
*/
public @NonNull Builder replace(int id, boolean join) {
mReplaceId = id;
@@ -1148,7 +1111,7 @@
/**
* Defers all operations.
- * @return the same Builder instance.
+ * @return the same {@code Builder} instance.
*/
public @NonNull Builder defer() {
mFlags |= FLAG_DEFER;
@@ -1158,7 +1121,7 @@
/**
* Terminates the VolumeShaper.
* Do not call directly, use {@link VolumeShaper#release()}.
- * @return the same Builder instance.
+ * @return the same {@code Builder} instance.
*/
public @NonNull Builder terminate() {
mFlags |= FLAG_TERMINATE;
@@ -1167,7 +1130,7 @@
/**
* Reverses direction.
- * @return the same Builder instance.
+ * @return the same {@code Builder} instance.
*/
public @NonNull Builder reverse() {
mFlags ^= FLAG_REVERSE;
@@ -1175,11 +1138,22 @@
}
/**
+ * Use the id specified in the configuration, creating
+ * VolumeShaper as needed; the configuration should be
+ * TYPE_SCALE.
+ * @return the same {@code Builder} instance.
+ */
+ public @NonNull Builder createIfNeeded() {
+ mFlags |= FLAG_CREATE_IF_NEEDED;
+ return this;
+ }
+
+ /**
* Sets the operation flag. Do not call this directly but one of the
* other builder methods.
*
* @param flags new value for {@code flags}, consisting of ORed flags.
- * @return the same Builder instance.
+ * @return the same {@code Builder} instance.
*/
private @NonNull Builder setFlags(@Flag int flags) {
if ((flags & ~FLAG_PUBLIC_ALL) != 0) {
diff --git a/media/java/android/media/session/ICallback.aidl b/media/java/android/media/session/ICallback.aidl
new file mode 100644
index 0000000..322bffa
--- /dev/null
+++ b/media/java/android/media/session/ICallback.aidl
@@ -0,0 +1,35 @@
+/* Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media.session;
+
+import android.app.PendingIntent;
+import android.content.ComponentName;
+import android.media.session.MediaSession;
+import android.view.KeyEvent;
+
+/**
+ * @hide
+ */
+oneway interface ICallback {
+ void onMediaKeyEventDispatchedToMediaSession(in KeyEvent event,
+ in MediaSession.Token sessionToken);
+ void onMediaKeyEventDispatchedToMediaButtonReceiver(in KeyEvent event,
+ in ComponentName mediaButtonReceiver);
+
+ void onAddressedPlayerChangedToMediaSession(in MediaSession.Token sessionToken);
+ void onAddressedPlayerChangedToMediaButtonReceiver(in ComponentName mediaButtonReceiver);
+}
+
diff --git a/media/java/android/media/session/ISessionManager.aidl b/media/java/android/media/session/ISessionManager.aidl
index 8a98773..5fcb430 100644
--- a/media/java/android/media/session/ISessionManager.aidl
+++ b/media/java/android/media/session/ISessionManager.aidl
@@ -18,8 +18,9 @@
import android.content.ComponentName;
import android.media.IRemoteVolumeController;
import android.media.session.IActiveSessionsListener;
-import android.media.session.IOnVolumeKeyLongPressListener;
+import android.media.session.ICallback;
import android.media.session.IOnMediaKeyListener;
+import android.media.session.IOnVolumeKeyLongPressListener;
import android.media.session.ISession;
import android.media.session.ISessionCallback;
import android.os.Bundle;
@@ -45,7 +46,7 @@
// For PhoneWindowManager to precheck media keys
boolean isGlobalPriorityActive();
+ void setCallback(in ICallback callback);
void setOnVolumeKeyLongPressListener(in IOnVolumeKeyLongPressListener listener);
void setOnMediaKeyListener(in IOnMediaKeyListener listener);
}
-
diff --git a/media/java/android/media/session/MediaSessionManager.java b/media/java/android/media/session/MediaSessionManager.java
index 80d2a0c..83793ae 100644
--- a/media/java/android/media/session/MediaSessionManager.java
+++ b/media/java/android/media/session/MediaSessionManager.java
@@ -71,6 +71,7 @@
private Context mContext;
+ private CallbackImpl mCallback;
private OnVolumeKeyLongPressListenerImpl mOnVolumeKeyLongPressListener;
private OnMediaKeyListenerImpl mOnMediaKeyListener;
@@ -411,6 +412,36 @@
}
/**
+ * Set a {@link Callback}.
+ *
+ * <p>System can only have a single callback, and the callback can only be set by
+ * Bluetooth service process.
+ *
+ * @param callback A {@link Callback}. {@code null} to reset.
+ * @param handler The handler on which the callback should be invoked, or {@code null}
+ * if the callback should be invoked on the calling thread's looper.
+ * @hide
+ */
+ public void setCallback(@Nullable Callback callback, @Nullable Handler handler) {
+ synchronized (mLock) {
+ try {
+ if (callback == null) {
+ mCallback = null;
+ mService.setCallback(null);
+ } else {
+ if (handler == null) {
+ handler = new Handler();
+ }
+ mCallback = new CallbackImpl(callback, handler);
+ mService.setCallback(mCallback);
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "Failed to set media key callback", e);
+ }
+ }
+ }
+
+ /**
* Listens for changes to the list of active sessions. This can be added
* using {@link #addOnActiveSessionsChangedListener}.
*/
@@ -439,12 +470,65 @@
public interface OnMediaKeyListener {
/**
* Called when the media key is pressed.
+ * <p>If the listener consumes the initial down event (i.e. ACTION_DOWN with
+ * repeat count zero), it must also comsume all following key events.
+ * (i.e. ACTION_DOWN with repeat count more than zero, and ACTION_UP).
* <p>If it takes more than 1s to return, the key event will be sent to
* other media sessions.
*/
boolean onMediaKey(KeyEvent event);
}
+ /**
+ * Callbacks for the media session service.
+ *
+ * <p>Called when a media key event is dispatched or the addressed player is changed.
+ * The addressed player is either the media session or the media button receiver that will
+ * receive media key events.
+ * @hide
+ */
+ public static abstract class Callback {
+ /**
+ * Called when a media key event is dispatched to the media session
+ * through the media session service.
+ *
+ * @param event Dispatched media key event.
+ * @param sessionToken The media session's token.
+ */
+ public abstract void onMediaKeyEventDispatched(KeyEvent event,
+ MediaSession.Token sessionToken);
+
+ /**
+ * Called when a media key event is dispatched to the media button receiver
+ * through the media session service.
+ * <p>MediaSessionService may broadcast key events to the media button receiver
+ * when reviving playback after the media session is released.
+ *
+ * @param event Dispatched media key event.
+ * @param mediaButtonReceiver The media button receiver.
+ */
+ public abstract void onMediaKeyEventDispatched(KeyEvent event,
+ ComponentName mediaButtonReceiver);
+
+ /**
+ * Called when the addressed player is changed to a media session.
+ * <p>One of the {@ #onAddressedPlayerChanged} will be also called immediately after
+ * {@link #setCallback} if the addressed player exists.
+ *
+ * @param sessionToken The media session's token.
+ */
+ public abstract void onAddressedPlayerChanged(MediaSession.Token sessionToken);
+
+ /**
+ * Called when the addressed player is changed to the media button receiver.
+ * <p>One of the {@ #onAddressedPlayerChanged} will be also called immediately after
+ * {@link #setCallback} if the addressed player exists.
+ *
+ * @param mediaButtonReceiver The media button receiver.
+ */
+ public abstract void onAddressedPlayerChanged(ComponentName mediaButtonReceiver);
+ }
+
private static final class SessionsChangedWrapper {
private Context mContext;
private OnActiveSessionsChangedListener mListener;
@@ -534,9 +618,64 @@
public void run() {
boolean handled = mListener.onMediaKey(event);
Log.d(TAG, "The media key listener is returned " + handled);
- result.send(
- handled ? RESULT_MEDIA_KEY_HANDLED : RESULT_MEDIA_KEY_NOT_HANDLED,
- null);
+ if (result != null) {
+ result.send(
+ handled ? RESULT_MEDIA_KEY_HANDLED : RESULT_MEDIA_KEY_NOT_HANDLED,
+ null);
+ }
+ }
+ });
+ }
+ }
+
+ private static final class CallbackImpl extends ICallback.Stub {
+ private final Callback mCallback;
+ private final Handler mHandler;
+
+ public CallbackImpl(@NonNull Callback callback, @NonNull Handler handler) {
+ mCallback = callback;
+ mHandler = handler;
+ }
+
+ @Override
+ public void onMediaKeyEventDispatchedToMediaSession(KeyEvent event,
+ MediaSession.Token sessionToken) {
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ mCallback.onMediaKeyEventDispatched(event, sessionToken);
+ }
+ });
+ }
+
+ @Override
+ public void onMediaKeyEventDispatchedToMediaButtonReceiver(KeyEvent event,
+ ComponentName mediaButtonReceiver) {
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ mCallback.onMediaKeyEventDispatched(event, mediaButtonReceiver);
+ }
+ });
+ }
+
+ @Override
+ public void onAddressedPlayerChangedToMediaSession(MediaSession.Token sessionToken) {
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ mCallback.onAddressedPlayerChanged(sessionToken);
+ }
+ });
+ }
+
+ @Override
+ public void onAddressedPlayerChangedToMediaButtonReceiver(
+ ComponentName mediaButtonReceiver) {
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ mCallback.onAddressedPlayerChanged(mediaButtonReceiver);
}
});
}
diff --git a/media/java/android/media/tv/TvContract.java b/media/java/android/media/tv/TvContract.java
index 6d8296a..6e15d8d 100644
--- a/media/java/android/media/tv/TvContract.java
+++ b/media/java/android/media/tv/TvContract.java
@@ -25,6 +25,7 @@
import android.content.ContentUris;
import android.content.Intent;
import android.net.Uri;
+import android.os.Bundle;
import android.os.IBinder;
import android.provider.BaseColumns;
import android.text.TextUtils;
@@ -69,9 +70,171 @@
private static final String PATH_PROGRAM = "program";
private static final String PATH_RECORDED_PROGRAM = "recorded_program";
private static final String PATH_PREVIEW_PROGRAM = "preview_program";
+ private static final String PATH_WATCH_NEXT_PROGRAM = "watch_next_program";
private static final String PATH_PASSTHROUGH = "passthrough";
/**
+ * Activity Action: sent by an application telling the system to set the given channel as
+ * browsable. This is only relevant to channels with {@link Channels#TYPE_PREVIEW} type.
+ *
+ * <p>The intent must contain the following bundle parameters:
+ * <ul>
+ * <li>{@link #EXTRA_CHANNEL_ID}: ID for the {@link Channels#TYPE_PREVIEW} channel as a long
+ * integer.</li>
+ * <li>{@link #EXTRA_PACKAGE_NAME}: the package name of the requesting application.</li>
+ * </ul>
+ */
+ public static final String ACTION_MAKE_CHANNEL_BROWSABLE =
+ "android.media.tv.action.MAKE_CHANNEL_BROWSABLE";
+
+ /**
+ * Broadcast Action: sent by the system to tell the target TV input that one of its preview
+ * program's browsable state is disabled, i.e., it will no longer be shown to users, which, for
+ * example, might be a result of users' interaction with UI. The input is expected to delete the
+ * preview program from the content provider.
+ *
+ * <p>The intent must contain the following bundle parameter:
+ * <ul>
+ * <li>{@link #EXTRA_PREVIEW_PROGRAM_ID}: the disabled preview program ID.</li>
+ * </ul>
+ */
+ public static final String ACTION_PREVIEW_PROGRAM_BROWSABLE_DISABLED =
+ "android.media.tv.action.PREVIEW_PROGRAM_BROWSABLE_DISABLED";
+
+ /**
+ * Broadcast Action: sent by the system to tell the target TV input that one of its "watch next"
+ * program's browsable state is disabled, i.e., it will no longer be shown to users, which, for
+ * example, might be a result of users' interaction with UI. The input is expected to delete the
+ * "watch next" program from the content provider.
+ *
+ * <p>The intent must contain the following bundle parameter:
+ * <ul>
+ * <li>{@link #EXTRA_WATCH_NEXT_PROGRAM_ID}: the disabled "watch next" program ID.</li>
+ * </ul>
+ */
+ public static final String ACTION_WATCH_NEXT_PROGRAM_BROWSABLE_DISABLED =
+ "android.media.tv.action.WATCH_NEXT_PROGRAM_BROWSABLE_DISABLED";
+
+ /**
+ * Broadcast Action: sent by the system to tell the target TV input that one of its existing
+ * preview programs is added to the watch next programs table by user.
+ *
+ * <p>The intent must contain the following bundle parameters:
+ * <ul>
+ * <li>{@link #EXTRA_PREVIEW_PROGRAM_ID}: the ID of the existing preview program.</li>
+ * <li>{@link #EXTRA_WATCH_NEXT_PROGRAM_ID}: the ID of the new watch next program.</li>
+ * </ul>
+ */
+ public static final String ACTION_PREVIEW_PROGRAM_ADDED_TO_WATCH_NEXT =
+ "android.media.tv.action.PREVIEW_PROGRAM_ADDED_TO_WATCH_NEXT";
+
+ /** The key for a bundle parameter containing a channel ID as a long integer */
+ public static final String EXTRA_CHANNEL_ID = "android.media.tv.extra.CHANNEL_ID";
+
+ /** The key for a bundle parameter containing a package name as a string. */
+ public static final String EXTRA_PACKAGE_NAME = "android.media.tv.extra.PACKAGE_NAME";
+
+ /** The key for a bundle parameter containing a program ID as a long integer. */
+ public static final String EXTRA_PREVIEW_PROGRAM_ID =
+ "android.media.tv.extra.PREVIEW_PROGRAM_ID";
+
+ /** The key for a bundle parameter containing a watch next program ID as a long integer. */
+ public static final String EXTRA_WATCH_NEXT_PROGRAM_ID =
+ "android.media.tv.extra.WATCH_NEXT_PROGRAM_ID";
+
+ /**
+ * The method name to get existing columns in the given table of the specified content provider.
+ *
+ * <p>The method caller must provide the following parameter:
+ * <ul>
+ * <li>{@code arg}: The content URI of the target table as a {@link String}.</li>
+ * </ul>
+
+ * <p>On success, the returned {@link android.os.Bundle} will include existing column names
+ * with the key {@link #EXTRA_EXISTING_COLUMN_NAMES}. Otherwise, the return value will be {@code null}.
+ *
+ * @see ContentResolver#call(Uri, String, String, Bundle)
+ * @see #EXTRA_EXISTING_COLUMN_NAMES
+ * @hide
+ */
+ @SystemApi
+ public static final String METHOD_GET_COLUMNS = "get_columns";
+
+ /**
+ * The method name to add a new column in the given table of the specified content provider.
+ *
+ * <p>The method caller must provide the following parameter:
+ * <ul>
+ * <li>{@code arg}: The content URI of the target table as a {@link String}.</li>
+ * <li>{@code extra}: Name, data type, and default value of the new column in a Bundle:
+ * <ul>
+ * <li>{@link #EXTRA_COLUMN_NAME} the column name as a {@link String}.</li>
+ * <li>{@link #EXTRA_DATA_TYPE} the data type as a {@link String}.</li>
+ * <li>{@link #EXTRA_DEFAULT_VALUE} the default value as a {@link String}.
+ * (optional)</li>
+ * </ul>
+ * </li>
+ * </ul>
+ *
+ * <p>On success, the returned {@link android.os.Bundle} will include current colum names after
+ * the addition operation with the key {@link #EXTRA_EXISTING_COLUMN_NAMES}. Otherwise, the
+ * return value will be {@code null}.
+ *
+ * @see ContentResolver#call(Uri, String, String, Bundle)
+ * @see #EXTRA_COLUMN_NAME
+ * @see #EXTRA_DATA_TYPE
+ * @see #EXTRA_DEFAULT_VALUE
+ * @see #EXTRA_EXISTING_COLUMN_NAMES
+ * @hide
+ */
+ @SystemApi
+ public static final String METHOD_ADD_COLUMN = "add_column";
+
+ /**
+ * The key for a returned {@link Bundle} value containing existing column names in the given
+ * table as an {@link ArrayList} of {@link String}.
+ *
+ * @see #METHOD_GET_COLUMNS
+ * @see #METHOD_ADD_COLUMN
+ * @hide
+ */
+ @SystemApi
+ public static final String EXTRA_EXISTING_COLUMN_NAMES =
+ "android.media.tv.extra.EXISTING_COLUMN_NAMES";
+
+ /**
+ * The key for a {@link Bundle} parameter containing the new column name to be added in the
+ * given table as a non-empty {@link CharSequence}.
+ *
+ * @see #METHOD_ADD_COLUMN
+ * @hide
+ */
+ @SystemApi
+ public static final String EXTRA_COLUMN_NAME = "android.media.tv.extra.COLUMN_NAME";
+
+ /**
+ * The key for a {@link Bundle} parameter containing the data type of the new column to be added
+ * in the given table as a non-empty {@link CharSequence}, which should be one of the following
+ * values: {@code "TEXT"}, {@code "INTEGER"}, {@code "REAL"}, or {@code "BLOB"}.
+ *
+ * @see #METHOD_ADD_COLUMN
+ * @hide
+ */
+ @SystemApi
+ public static final String EXTRA_DATA_TYPE = "android.media.tv.extra.DATA_TYPE";
+
+ /**
+ * The key for a {@link Bundle} parameter containing the default value of the new column to be
+ * added in the given table as a {@link CharSequence}, which represents a valid default value
+ * according to the data type provided with {@link #EXTRA_DATA_TYPE}.
+ *
+ * @see #METHOD_ADD_COLUMN
+ * @hide
+ */
+ @SystemApi
+ public static final String EXTRA_DEFAULT_VALUE = "android.media.tv.extra.DEFAULT_VALUE";
+
+ /**
* An optional query, update or delete URI parameter that allows the caller to specify TV input
* ID to filter channels.
* @hide
@@ -328,6 +491,15 @@
}
/**
+ * Builds a URI that points to a specific watch next program.
+ *
+ * @param watchNextProgramId The ID of the watch next program to point to.
+ */
+ public static final Uri buildWatchNextProgramUri(long watchNextProgramId) {
+ return ContentUris.withAppendedId(WatchNextPrograms.CONTENT_URI, watchNextProgramId);
+ }
+
+ /**
* Builds a URI that points to a specific program the user watched.
*
* @param watchedProgramId The ID of the watched program to point to.
@@ -399,17 +571,6 @@
*/
public interface BaseProgramColumns extends BaseTvColumns {
/**
- * The ID of the TV channel that provides this TV program.
- *
- * <p>This is a part of the channel URI and matches to {@link BaseColumns#_ID}.
- *
- * <p>This is a required field.
- *
- * <p>Type: INTEGER (long)
- */
- public static final String COLUMN_CHANNEL_ID = "channel_id";
-
- /**
* The title of this TV program.
*
* <p>If this program is an episodic TV show, it is recommended that the title is the series
@@ -673,6 +834,591 @@
public static final String COLUMN_VERSION_NUMBER = "version_number";
}
+ /**
+ * Common base for the tables of preview programs.
+ */
+ public interface BasePreviewProgramColumns extends BaseProgramColumns {
+
+ /** @hide */
+ @StringDef({
+ TYPE_MOVIE,
+ TYPE_TV_SERIES,
+ TYPE_TV_SEASON,
+ TYPE_TV_EPISODE,
+ TYPE_CLIP,
+ TYPE_EVENT,
+ TYPE_CHANNEL,
+ TYPE_TRACK,
+ TYPE_ALBUM,
+ TYPE_ARTIST,
+ TYPE_PLAYLIST,
+ TYPE_STATION,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface Type {}
+
+ /**
+ * The program type for movie.
+ *
+ * @see #COLUMN_TYPE
+ */
+ public static final String TYPE_MOVIE = "TYPE_MOVIE";
+
+ /**
+ * The program type for TV series.
+ *
+ * @see #COLUMN_TYPE
+ */
+ public static final String TYPE_TV_SERIES = "TYPE_TV_SERIES";
+
+ /**
+ * The program type for TV season.
+ *
+ * @see #COLUMN_TYPE
+ */
+ public static final String TYPE_TV_SEASON = "TYPE_TV_SEASON";
+
+ /**
+ * The program type for TV episode.
+ *
+ * @see #COLUMN_TYPE
+ */
+ public static final String TYPE_TV_EPISODE = "TYPE_TV_EPISODE";
+
+ /**
+ * The program type for clip.
+ *
+ * @see #COLUMN_TYPE
+ */
+ public static final String TYPE_CLIP = "TYPE_CLIP";
+
+ /**
+ * The program type for event.
+ *
+ * @see #COLUMN_TYPE
+ */
+ public static final String TYPE_EVENT = "TYPE_EVENT";
+
+ /**
+ * The program type for channel.
+ *
+ * @see #COLUMN_TYPE
+ */
+ public static final String TYPE_CHANNEL = "TYPE_CHANNEL";
+
+ /**
+ * The program type for track.
+ *
+ * @see #COLUMN_TYPE
+ */
+ public static final String TYPE_TRACK = "TYPE_TRACK";
+
+ /**
+ * The program type for album.
+ *
+ * @see #COLUMN_TYPE
+ */
+ public static final String TYPE_ALBUM = "TYPE_ALBUM";
+
+ /**
+ * The program type for artist.
+ *
+ * @see #COLUMN_TYPE
+ */
+ public static final String TYPE_ARTIST = "TYPE_ARTIST";
+
+ /**
+ * The program type for playlist.
+ *
+ * @see #COLUMN_TYPE
+ */
+ public static final String TYPE_PLAYLIST = "TYPE_PLAYLIST";
+
+ /**
+ * The program type for station.
+ *
+ * @see #COLUMN_TYPE
+ */
+ public static final String TYPE_STATION = "TYPE_STATION";
+
+ /** @hide */
+ @StringDef({
+ ASPECT_RATIO_16_9,
+ ASPECT_RATIO_3_2,
+ ASPECT_RATIO_1_1,
+ ASPECT_RATIO_2_3,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface AspectRatio {}
+
+ /**
+ * The aspect ratio for 16:9.
+ *
+ * @see #COLUMN_POSTER_ART_ASPECT_RATIO
+ * @see #COLUMN_THUMBNAIL_ASPECT_RATIO
+ */
+ public static final String ASPECT_RATIO_16_9 = "ASPECT_RATIO_16_9";
+
+ /**
+ * The aspect ratio for 3:2.
+ *
+ * @see #COLUMN_POSTER_ART_ASPECT_RATIO
+ * @see #COLUMN_THUMBNAIL_ASPECT_RATIO
+ */
+ public static final String ASPECT_RATIO_3_2 = "ASPECT_RATIO_3_2";
+
+ /**
+ * The aspect ratio for 1:1.
+ *
+ * @see #COLUMN_POSTER_ART_ASPECT_RATIO
+ * @see #COLUMN_THUMBNAIL_ASPECT_RATIO
+ */
+ public static final String ASPECT_RATIO_1_1 = "ASPECT_RATIO_1_1";
+
+ /**
+ * The aspect ratio for 2:3.
+ *
+ * @see #COLUMN_POSTER_ART_ASPECT_RATIO
+ * @see #COLUMN_THUMBNAIL_ASPECT_RATIO
+ */
+ public static final String ASPECT_RATIO_2_3 = "ASPECT_RATIO_2_3";
+
+ /** @hide */
+ @StringDef({
+ AVAILABILITY_AVAILABLE,
+ AVAILABILITY_FREE_WITH_SUBSCRIPTION,
+ AVAILABILITY_PAID_CONTENT,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface Availability {}
+
+ /**
+ * The availability for "available to this user".
+ *
+ * @see #COLUMN_AVAILABILITY
+ */
+ public static final String AVAILABILITY_AVAILABLE = "AVAILABILITY_AVAILABLE";
+
+ /**
+ * The availability for "free with subscription".
+ *
+ * @see #COLUMN_AVAILABILITY
+ */
+ public static final String AVAILABILITY_FREE_WITH_SUBSCRIPTION =
+ "AVAILABILITY_FREE_WITH_SUBSCRIPTION";
+
+ /**
+ * The availability for "paid content, either to-own or rental
+ * (user has not purchased/rented).
+ *
+ * @see #COLUMN_AVAILABILITY
+ */
+ public static final String AVAILABILITY_PAID_CONTENT = "AVAILABILITY_PAID_CONTENT";
+
+ /** @hide */
+ @StringDef({
+ INTERACTION_TYPE_LISTENS,
+ INTERACTION_TYPE_FOLLOWERS,
+ INTERACTION_TYPE_FANS,
+ INTERACTION_TYPE_LIKES,
+ INTERACTION_TYPE_THUMBS,
+ INTERACTION_TYPE_VIEWS,
+ INTERACTION_TYPE_VIEWERS,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface InteractionType {}
+
+ /**
+ * The interaction type for "listens".
+ *
+ * @see #COLUMN_INTERACTION_TYPE
+ */
+ public static final String INTERACTION_TYPE_LISTENS = "INTERACTION_TYPE_LISTENS";
+
+ /**
+ * The interaction type for "followers".
+ *
+ * @see #COLUMN_INTERACTION_TYPE
+ */
+ public static final String INTERACTION_TYPE_FOLLOWERS = "INTERACTION_TYPE_FOLLOWERS";
+
+ /**
+ * The interaction type for "fans".
+ *
+ * @see #COLUMN_INTERACTION_TYPE
+ */
+ public static final String INTERACTION_TYPE_FANS = "INTERACTION_TYPE_FANS";
+
+ /**
+ * The interaction type for "likes".
+ *
+ * @see #COLUMN_INTERACTION_TYPE
+ */
+ public static final String INTERACTION_TYPE_LIKES = "INTERACTION_TYPE_LIKES";
+
+ /**
+ * The interaction type for "thumbs".
+ *
+ * @see #COLUMN_INTERACTION_TYPE
+ */
+ public static final String INTERACTION_TYPE_THUMBS = "INTERACTION_TYPE_THUMBS";
+
+ /**
+ * The interaction type for "views".
+ *
+ * @see #COLUMN_INTERACTION_TYPE
+ */
+ public static final String INTERACTION_TYPE_VIEWS = "INTERACTION_TYPE_VIEWS";
+
+ /**
+ * The interaction type for "viewers".
+ *
+ * @see #COLUMN_INTERACTION_TYPE
+ */
+ public static final String INTERACTION_TYPE_VIEWERS = "INTERACTION_TYPE_VIEWERS";
+
+ /** @hide */
+ @StringDef({
+ REVIEW_RATING_STYLE_STARS,
+ REVIEW_RATING_STYLE_THUMBS_UP_DOWN,
+ REVIEW_RATING_STYLE_PERCENTAGE,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface ReviewRatingStyle {}
+
+ /**
+ * The review rating style for five star rating.
+ *
+ * @see #COLUMN_REVIEW_RATING_STYLE
+ */
+ public static final String REVIEW_RATING_STYLE_STARS = "REVIEW_RATING_STYLE_STARS";
+
+ /**
+ * The review rating style for thumbs-up and thumbs-down rating.
+ *
+ * @see #COLUMN_REVIEW_RATING_STYLE
+ */
+ public static final String REVIEW_RATING_STYLE_THUMBS_UP_DOWN =
+ "REVIEW_RATING_STYLE_THUMBS_UP_DOWN";
+
+ /**
+ * The review rating style for 0 to 100 point system.
+ *
+ * @see #COLUMN_REVIEW_RATING_STYLE
+ */
+ public static final String REVIEW_RATING_STYLE_PERCENTAGE =
+ "REVIEW_RATING_STYLE_PERCENTAGE";
+
+ /**
+ * The type of this program content.
+ *
+ * <p>The value should match one of the followings:
+ * {@link #TYPE_MOVIE},
+ * {@link #TYPE_TV_SERIES},
+ * {@link #TYPE_TV_SEASON},
+ * {@link #TYPE_TV_EPISODE},
+ * {@link #TYPE_CLIP},
+ * {@link #TYPE_EVENT},
+ * {@link #TYPE_CHANNEL},
+ * {@link #TYPE_TRACK},
+ * {@link #TYPE_ALBUM},
+ * {@link #TYPE_ARTIST},
+ * {@link #TYPE_PLAYLIST}, and
+ * {@link #TYPE_STATION}.
+ *
+ * <p>This is a required field if the program is from a {@link Channels#TYPE_PREVIEW}
+ * channel.
+ *
+ * <p>Type: TEXT
+ */
+ public static final String COLUMN_TYPE = "type";
+
+ /**
+ * The aspect ratio of the poster art for this TV program.
+ *
+ * <p>The value should match one of the followings:
+ * {@link #ASPECT_RATIO_16_9},
+ * {@link #ASPECT_RATIO_3_2},
+ * {@link #ASPECT_RATIO_1_1}, and
+ * {@link #ASPECT_RATIO_2_3}.
+ *
+ * <p>Type: TEXT
+ */
+ public static final String COLUMN_POSTER_ART_ASPECT_RATIO = "poster_art_aspect_ratio";
+
+ /**
+ * The aspect ratio of the thumbnail for this TV program.
+ *
+ * <p>The value should match one of the followings:
+ * {@link #ASPECT_RATIO_16_9},
+ * {@link #ASPECT_RATIO_3_2},
+ * {@link #ASPECT_RATIO_1_1}, and
+ * {@link #ASPECT_RATIO_2_3}.
+ *
+ * <p>Type: TEXT
+ */
+ public static final String COLUMN_THUMBNAIL_ASPECT_RATIO = "poster_thumbnail_aspect_ratio";
+
+ /**
+ * The URI for the logo of this TV program.
+ *
+ * <p>This is a small badge shown on top of the poster art or thumbnail representing the
+ * source of the content.
+ *
+ * <p>The data in the column must be a URL, or a URI in one of the following formats:
+ *
+ * <ul>
+ * <li>content ({@link android.content.ContentResolver#SCHEME_CONTENT})</li>
+ * <li>android.resource ({@link android.content.ContentResolver#SCHEME_ANDROID_RESOURCE})
+ * </li>
+ * <li>file ({@link android.content.ContentResolver#SCHEME_FILE})</li>
+ * </ul>
+ *
+ * <p>Can be empty.
+ *
+ * <p>Type: TEXT
+ */
+ public static final String COLUMN_LOGO_URI = "logo_uri";
+
+ /**
+ * The availability of this TV program.
+ *
+ * <p>The value should match one of the followings:
+ * {@link #AVAILABILITY_AVAILABLE},
+ * {@link #AVAILABILITY_FREE_WITH_SUBSCRIPTION}, and
+ * {@link #AVAILABILITY_PAID_CONTENT}.
+ *
+ * <p>Type: TEXT
+ */
+ public static final String COLUMN_AVAILABILITY = "availability";
+
+ /**
+ * The starting price of this TV program.
+ *
+ * <p>This indicates the lowest regular acquisition cost of the content. It is only used
+ * if the availability of the program is {@link #AVAILABILITY_PAID_CONTENT}.
+ *
+ * <p>Type: TEXT
+ * @see #COLUMN_OFFER_PRICE
+ */
+ public static final String COLUMN_STARTING_PRICE = "starting_price";
+
+ /**
+ * The offer price of this TV program.
+ *
+ * <p>This is the promotional cost of the content. It is only used if the availability of
+ * the program is {@link #AVAILABILITY_PAID_CONTENT}.
+ *
+ * <p>Type: TEXT
+ * @see #COLUMN_STARTING_PRICE
+ */
+ public static final String COLUMN_OFFER_PRICE = "offer_price";
+
+ /**
+ * The release date of this TV program.
+ *
+ * <p>The value should be in the form of either "yyyy-MM-dd" or "yyyy".
+ *
+ * <p>Type: TEXT
+ */
+ public static final String COLUMN_RELEASE_DATE = "release_date";
+
+ /**
+ * The count of the items included in this TV program.
+ *
+ * <p>This is only relevant if the program represents a collection of items such as series,
+ * episodes, or music tracks.
+ *
+ * <p>Type: INTEGER
+ */
+ public static final String COLUMN_ITEM_COUNT = "item_count";
+
+ /**
+ * The flag indicating whether this TV program is live or not.
+ *
+ * <p>A value of 1 indicates that the content is airing and should be consumed now, a value
+ * of 0 indicates that the content is off the air and does not need to be consumed at the
+ * present time. If not specified, the value is set to 0 (not live) by default.
+ *
+ * <p>Type: INTEGER (boolean)
+ */
+ public static final String COLUMN_LIVE = "live";
+
+ /**
+ * The internal ID used by individual TV input services.
+ *
+ * <p>This is internal to the provider that inserted it, and should not be decoded by other
+ * apps.
+ *
+ * <p>Can be empty.
+ *
+ * <p>Type: TEXT
+ */
+ public static final String COLUMN_INTERNAL_PROVIDER_ID = "internal_provider_id";
+
+ /**
+ * The URI for the preview video.
+ *
+ * <p>This is only relevant to {@link Channels#TYPE_PREVIEW}. The data in the column must be
+ * a URL, or a URI in one of the following formats:
+ *
+ * <ul>
+ * <li>content ({@link android.content.ContentResolver#SCHEME_CONTENT})</li>
+ * <li>android.resource ({@link android.content.ContentResolver#SCHEME_ANDROID_RESOURCE})
+ * </li>
+ * <li>file ({@link android.content.ContentResolver#SCHEME_FILE})</li>
+ * </ul>
+ *
+ * <p>Can be empty.
+ *
+ * <p>Type: TEXT
+ */
+ public static final String COLUMN_PREVIEW_VIDEO_URI = "preview_video_uri";
+
+ /**
+ * The last playback position (in milliseconds) of the preview video.
+ *
+ * <p>This is only relevant to {@link Channels#TYPE_PREVIEW}.
+ *
+ * <p>Can be empty.
+ *
+ * <p>Type: INTEGER
+ */
+ public static final String COLUMN_LAST_PLAYBACK_POSITION_MILLIS =
+ "last_playback_position_millis";
+
+ /**
+ * The duration (in milliseconds) of the preview video.
+ *
+ * <p>This is only relevant to {@link Channels#TYPE_PREVIEW}.
+ *
+ * <p>Can be empty.
+ *
+ * <p>Type: INTEGER
+ */
+ public static final String COLUMN_DURATION_MILLIS = "duration_millis";
+
+ /**
+ * The intent URI which is launched when the preview video is selected.
+ *
+ * <p>The URI is created using {@link Intent#toUri} with {@link Intent#URI_INTENT_SCHEME}
+ * and converted back to the original intent with {@link Intent#parseUri}. The intent is
+ * launched when the user selects the preview video item.
+ *
+ * <p>Can be empty.
+ *
+ * <p>Type: TEXT
+ */
+ public static final String COLUMN_APP_LINK_INTENT_URI =
+ "app_link_intent_uri";
+
+ /**
+ * The flag indicating whether this program is transient or not.
+ *
+ * <p>A value of 1 indicates that the channel will be automatically removed by the system on
+ * reboot, and a value of 0 indicates that the channel is persistent across reboot. If not
+ * specified, this value is set to 0 (not transient) by default.
+ *
+ * <p>Type: INTEGER (boolean)
+ * @see Channels#COLUMN_TRANSIENT
+ * @hide
+ */
+ @SystemApi
+ public static final String COLUMN_TRANSIENT = "transient";
+
+ /**
+ * The type of interaction for this TV program.
+ *
+ * <p> The value should match one of the followings:
+ * {@link #INTERACTION_TYPE_LISTENS},
+ * {@link #INTERACTION_TYPE_FOLLOWERS},
+ * {@link #INTERACTION_TYPE_FANS},
+ * {@link #INTERACTION_TYPE_LIKES},
+ * {@link #INTERACTION_TYPE_THUMBS},
+ * {@link #INTERACTION_TYPE_VIEWS}, and
+ * {@link #INTERACTION_TYPE_VIEWERS}.
+ *
+ * <p>Type: TEXT
+ * @see #COLUMN_INTERACTION_COUNT
+ */
+ public static final String COLUMN_INTERACTION_TYPE = "interaction_type";
+
+ /**
+ * The interaction count for this program.
+ *
+ * <p>This indicates the number of times interaction has happened.
+ *
+ * <p>Type: INTEGER (long)
+ * @see #COLUMN_INTERACTION_TYPE
+ */
+ public static final String COLUMN_INTERACTION_COUNT = "interaction_count";
+
+ /**
+ * The author or artist of this content.
+ *
+ * <p>Type: TEXT
+ */
+ public static final String COLUMN_AUTHOR = "author";
+
+ /**
+ * The review rating score style used for {@link #COLUMN_REVIEW_RATING}.
+ *
+ * <p> The value should match one of the followings: {@link #REVIEW_RATING_STYLE_STARS},
+ * {@link #REVIEW_RATING_STYLE_THUMBS_UP_DOWN}, and {@link #REVIEW_RATING_STYLE_PERCENTAGE}.
+ *
+ * <p>Type: TEXT
+ * @see #COLUMN_REVIEW_RATING
+ */
+ public static final String COLUMN_REVIEW_RATING_STYLE = "review_rating_style";
+
+ /**
+ * The review rating score for this program.
+ *
+ * <p>The format of the value is dependent on {@link #COLUMN_REVIEW_RATING_STYLE}. If the
+ * style is {@link #REVIEW_RATING_STYLE_STARS}, the value should be a real number between
+ * 0.0 and 5.0. (e.g. "4.5") If the style is {@link #REVIEW_RATING_STYLE_THUMBS_UP_DOWN},
+ * the value should be two integers, one for thumbs-up count and the other for thumbs-down
+ * count, with a comma between them. (e.g. "200,40") If the style is
+ * {@link #REVIEW_RATING_STYLE_PERCENTAGE}, the value shoule be a real number between 0 and
+ * 100. (e.g. "99.9")
+ *
+ * <p>Type: TEXT
+ * @see #COLUMN_REVIEW_RATING_STYLE
+ */
+ public static final String COLUMN_REVIEW_RATING = "review_rating";
+
+ /**
+ * The flag indicating whether this TV program is browsable or not.
+ *
+ * <p>This column can only be set by applications having proper system permission. For
+ * other applications, this is a read-only column.
+ *
+ * <p>A value of 1 indicates that the program is browsable and can be shown to users in
+ * the UI. A value of 0 indicates that the program should be hidden from users and the
+ * application who changes this value to 0 should send
+ * {@link #ACTION_WATCH_NEXT_PROGRAM_BROWSABLE_DISABLED} to the owner of the program
+ * to notify this change.
+ *
+ * <p>This value is set to 1 (browsable) by default.
+ *
+ * <p>Type: INTEGER (boolean)
+ */
+ public static final String COLUMN_BROWSABLE = "browsable";
+
+ /**
+ * The content ID of this TV program.
+ *
+ * <p>A public ID of the content which allows the application to apply the same operation to
+ * all the program copies in different channels.
+ *
+ * <p>Can be empty.
+ *
+ * <p>Type: TEXT
+ */
+ public static final String COLUMN_CONTENT_ID = "content_id";
+
+ }
+
/** Column definitions for the TV channels table. */
public static final class Channels implements BaseTvColumns {
@@ -1186,14 +1932,15 @@
/**
* The flag indicating whether this TV channel is browsable or not.
*
+ * <p>This column can only be set by applications having proper system permission. For
+ * other applications, this is a read-only column.
+ *
* <p>A value of 1 indicates the channel is included in the channel list that applications
* use to browse channels, a value of 0 indicates the channel is not included in the list.
* If not specified, this value is set to 0 (not browsable) by default.
*
* <p>Type: INTEGER (boolean)
- * @hide
*/
- @SystemApi
public static final String COLUMN_BROWSABLE = "browsable";
/**
@@ -1494,6 +2241,17 @@
public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/program";
/**
+ * The ID of the TV channel that provides this TV program.
+ *
+ * <p>This is a part of the channel URI and matches to {@link BaseColumns#_ID}.
+ *
+ * <p>This is a required field.
+ *
+ * <p>Type: INTEGER (long)
+ */
+ public static final String COLUMN_CHANNEL_ID = "channel_id";
+
+ /**
* The season number of this TV program for episodic TV shows.
*
* <p>Can be empty.
@@ -1797,6 +2555,17 @@
public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/recorded_program";
/**
+ * The ID of the TV channel that provides this recorded program.
+ *
+ * <p>This is a part of the channel URI and matches to {@link BaseColumns#_ID}.
+ *
+ * <p>This is a required field.
+ *
+ * <p>Type: INTEGER (long)
+ */
+ public static final String COLUMN_CHANNEL_ID = "channel_id";
+
+ /**
* The ID of the TV input service that is associated with this recorded program.
*
* <p>Use {@link #buildInputId} to build the ID.
@@ -1895,7 +2664,7 @@
/**
* Column definitions for the preview TV programs table.
*/
- public static final class PreviewPrograms implements BaseProgramColumns {
+ public static final class PreviewPrograms implements BasePreviewProgramColumns {
/** The content:// style URI for this table. */
public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/"
@@ -1907,522 +2676,16 @@
/** The MIME type of a single preview TV program. */
public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/preview_program";
- /** @hide */
- @StringDef({
- TYPE_MOVIE,
- TYPE_TV_SERIES,
- TYPE_TV_SEASON,
- TYPE_TV_EPISODE,
- TYPE_CLIP,
- TYPE_EVENT,
- TYPE_CHANNEL,
- TYPE_TRACK,
- TYPE_ALBUM,
- TYPE_ARTIST,
- TYPE_PLAYLIST,
- TYPE_STATION,
- })
- @Retention(RetentionPolicy.SOURCE)
- public @interface Type {}
-
/**
- * The program type for movie.
+ * The ID of the TV channel that provides this TV program.
*
- * @see #COLUMN_TYPE
+ * <p>This is a part of the channel URI and matches to {@link BaseColumns#_ID}.
+ *
+ * <p>This is a required field.
+ *
+ * <p>Type: INTEGER (long)
*/
- public static final String TYPE_MOVIE = "TYPE_MOVIE";
-
- /**
- * The program type for TV series.
- *
- * @see #COLUMN_TYPE
- */
- public static final String TYPE_TV_SERIES = "TYPE_TV_SERIES";
-
- /**
- * The program type for TV season.
- *
- * @see #COLUMN_TYPE
- */
- public static final String TYPE_TV_SEASON = "TYPE_TV_SEASON";
-
- /**
- * The program type for TV episode.
- *
- * @see #COLUMN_TYPE
- */
- public static final String TYPE_TV_EPISODE = "TYPE_TV_EPISODE";
-
- /**
- * The program type for clip.
- *
- * @see #COLUMN_TYPE
- */
- public static final String TYPE_CLIP = "TYPE_CLIP";
-
- /**
- * The program type for event.
- *
- * @see #COLUMN_TYPE
- */
- public static final String TYPE_EVENT = "TYPE_EVENT";
-
- /**
- * The program type for channel.
- *
- * @see #COLUMN_TYPE
- */
- public static final String TYPE_CHANNEL = "TYPE_CHANNEL";
-
- /**
- * The program type for track.
- *
- * @see #COLUMN_TYPE
- */
- public static final String TYPE_TRACK = "TYPE_TRACK";
-
- /**
- * The program type for album.
- *
- * @see #COLUMN_TYPE
- */
- public static final String TYPE_ALBUM = "TYPE_ALBUM";
-
- /**
- * The program type for artist.
- *
- * @see #COLUMN_TYPE
- */
- public static final String TYPE_ARTIST = "TYPE_ARTIST";
-
- /**
- * The program type for playlist.
- *
- * @see #COLUMN_TYPE
- */
- public static final String TYPE_PLAYLIST = "TYPE_PLAYLIST";
-
- /**
- * The program type for station.
- *
- * @see #COLUMN_TYPE
- */
- public static final String TYPE_STATION = "TYPE_STATION";
-
- /** @hide */
- @StringDef({
- WATCH_NEXT_TYPE_CONTINUE,
- WATCH_NEXT_TYPE_NEXT,
- WATCH_NEXT_TYPE_NEW,
- })
- @Retention(RetentionPolicy.SOURCE)
- public @interface WatchNextType {}
-
- /**
- * The watch next type for CONTINUE.
- *
- * @see #COLUMN_WATCH_NEXT_TYPE
- */
- public static final String WATCH_NEXT_TYPE_CONTINUE = "WATCH_NEXT_TYPE_CONTINUE";
-
- /**
- * The watch next type for NEXT.
- *
- * @see #COLUMN_WATCH_NEXT_TYPE
- */
- public static final String WATCH_NEXT_TYPE_NEXT = "WATCH_NEXT_TYPE_NEXT";
-
- /**
- * The watch next type for NEW.
- *
- * @see #COLUMN_WATCH_NEXT_TYPE
- */
- public static final String WATCH_NEXT_TYPE_NEW = "WATCH_NEXT_TYPE_NEW";
-
- /** @hide */
- @StringDef({
- ASPECT_RATIO_16_9,
- ASPECT_RATIO_3_2,
- ASPECT_RATIO_1_1,
- ASPECT_RATIO_2_3,
- })
- @Retention(RetentionPolicy.SOURCE)
- public @interface AspectRatio {}
-
- /**
- * The aspect ratio for 16:9.
- *
- * @see #COLUMN_POSTER_ART_ASPECT_RATIO
- * @see #COLUMN_THUMBNAIL_ASPECT_RATIO
- */
- public static final String ASPECT_RATIO_16_9 = "ASPECT_RATIO_16_9";
-
- /**
- * The aspect ratio for 3:2.
- *
- * @see #COLUMN_POSTER_ART_ASPECT_RATIO
- * @see #COLUMN_THUMBNAIL_ASPECT_RATIO
- */
- public static final String ASPECT_RATIO_3_2 = "ASPECT_RATIO_3_2";
-
- /**
- * The aspect ratio for 1:1.
- *
- * @see #COLUMN_POSTER_ART_ASPECT_RATIO
- * @see #COLUMN_THUMBNAIL_ASPECT_RATIO
- */
- public static final String ASPECT_RATIO_1_1 = "ASPECT_RATIO_1_1";
-
- /**
- * The aspect ratio for 2:3.
- *
- * @see #COLUMN_POSTER_ART_ASPECT_RATIO
- * @see #COLUMN_THUMBNAIL_ASPECT_RATIO
- */
- public static final String ASPECT_RATIO_2_3 = "ASPECT_RATIO_2_3";
-
- /** @hide */
- @StringDef({
- AVAILABILITY_AVAILABLE,
- AVAILABILITY_FREE_WITH_SUBSCRIPTION,
- AVAILABILITY_PAID_CONTENT,
- })
- @Retention(RetentionPolicy.SOURCE)
- public @interface Availability {}
-
- /**
- * The availability for "available to this user".
- *
- * @see #COLUMN_AVAILABILITY
- */
- public static final String AVAILABILITY_AVAILABLE = "AVAILABILITY_AVAILABLE";
-
- /**
- * The availability for "free with subscription".
- *
- * @see #COLUMN_AVAILABILITY
- */
- public static final String AVAILABILITY_FREE_WITH_SUBSCRIPTION =
- "AVAILABILITY_FREE_WITH_SUBSCRIPTION";
-
- /**
- * The availability for "paid content, either to-own or rental
- * (user has not purchased/rented).
- *
- * @see #COLUMN_AVAILABILITY
- */
- public static final String AVAILABILITY_PAID_CONTENT = "AVAILABILITY_PAID_CONTENT";
-
- /** @hide */
- @StringDef({
- INTERACTION_TYPE_LISTENS,
- INTERACTION_TYPE_FOLLOWERS,
- INTERACTION_TYPE_FANS,
- INTERACTION_TYPE_LIKES,
- INTERACTION_TYPE_THUMBS,
- INTERACTION_TYPE_VIEWS,
- INTERACTION_TYPE_VIEWERS,
- })
- @Retention(RetentionPolicy.SOURCE)
- public @interface InteractionType {}
-
- /**
- * The interaction type for "listens".
- *
- * @see #COLUMN_INTERACTION_TYPE
- */
- public static final String INTERACTION_TYPE_LISTENS = "INTERACTION_TYPE_LISTENS";
-
- /**
- * The interaction type for "followers".
- *
- * @see #COLUMN_INTERACTION_TYPE
- */
- public static final String INTERACTION_TYPE_FOLLOWERS = "INTERACTION_TYPE_FOLLOWERS";
-
- /**
- * The interaction type for "fans".
- *
- * @see #COLUMN_INTERACTION_TYPE
- */
- public static final String INTERACTION_TYPE_FANS = "INTERACTION_TYPE_FANS";
-
- /**
- * The interaction type for "likes".
- *
- * @see #COLUMN_INTERACTION_TYPE
- */
- public static final String INTERACTION_TYPE_LIKES = "INTERACTION_TYPE_LIKES";
-
- /**
- * The interaction type for "thumbs".
- *
- * @see #COLUMN_INTERACTION_TYPE
- */
- public static final String INTERACTION_TYPE_THUMBS = "INTERACTION_TYPE_THUMBS";
-
- /**
- * The interaction type for "views".
- *
- * @see #COLUMN_INTERACTION_TYPE
- */
- public static final String INTERACTION_TYPE_VIEWS = "INTERACTION_TYPE_VIEWS";
-
- /**
- * The interaction type for "viewers".
- *
- * @see #COLUMN_INTERACTION_TYPE
- */
- public static final String INTERACTION_TYPE_VIEWERS = "INTERACTION_TYPE_VIEWERS";
-
- /** @hide */
- @StringDef({
- REVIEW_RATING_STYLE_STARS,
- REVIEW_RATING_STYLE_THUMBS_UP_DOWN,
- REVIEW_RATING_STYLE_PERCENTAGE,
- })
- @Retention(RetentionPolicy.SOURCE)
- public @interface ReviewRatingStyle {}
-
- /**
- * The review rating style for five star rating.
- *
- * @see #COLUMN_REVIEW_RATING_STYLE
- */
- public static final String REVIEW_RATING_STYLE_STARS = "REVIEW_RATING_STYLE_STARS";
-
- /**
- * The review rating style for thumbs-up and thumbs-down rating.
- *
- * @see #COLUMN_REVIEW_RATING_STYLE
- */
- public static final String REVIEW_RATING_STYLE_THUMBS_UP_DOWN =
- "REVIEW_RATING_STYLE_THUMBS_UP_DOWN";
-
- /**
- * The review rating style for 0 to 100 point system.
- *
- * @see #COLUMN_REVIEW_RATING_STYLE
- */
- public static final String REVIEW_RATING_STYLE_PERCENTAGE =
- "REVIEW_RATING_STYLE_PERCENTAGE";
-
- /**
- * The type of this program content.
- *
- * <p>The value should match one of the followings:
- * {@link #TYPE_MOVIE},
- * {@link #TYPE_TV_SERIES},
- * {@link #TYPE_TV_SEASON},
- * {@link #TYPE_TV_EPISODE},
- * {@link #TYPE_CLIP},
- * {@link #TYPE_EVENT},
- * {@link #TYPE_CHANNEL},
- * {@link #TYPE_TRACK},
- * {@link #TYPE_ALBUM},
- * {@link #TYPE_ARTIST},
- * {@link #TYPE_PLAYLIST}, and
- * {@link #TYPE_STATION}.
- *
- * <p>This is a required field if the program is from a {@link Channels#TYPE_PREVIEW}
- * channel.
- *
- * <p>Type: TEXT
- */
- public static final String COLUMN_TYPE = "type";
-
- /**
- * The "watch next" type of this program content.
- *
- * <p>The value should match one of the followings:
- * {@link #WATCH_NEXT_TYPE_CONTINUE},
- * {@link #WATCH_NEXT_TYPE_NEXT}, and
- * {@link #WATCH_NEXT_TYPE_NEW}.
- *
- * <p>Can be empty.
- *
- * <p>Type: TEXT
- */
- public static final String COLUMN_WATCH_NEXT_TYPE = "watch_next_type";
-
- /**
- * The aspect ratio of the poster art for this TV program.
- *
- * <p>The value should match one of the followings:
- * {@link #ASPECT_RATIO_16_9},
- * {@link #ASPECT_RATIO_3_2},
- * {@link #ASPECT_RATIO_1_1}, and
- * {@link #ASPECT_RATIO_2_3}.
- *
- * <p>Type: TEXT
- */
- public static final String COLUMN_POSTER_ART_ASPECT_RATIO = "poster_art_aspect_ratio";
-
- /**
- * The aspect ratio of the thumbnail for this TV program.
- *
- * <p>The value should match one of the followings:
- * {@link #ASPECT_RATIO_16_9},
- * {@link #ASPECT_RATIO_3_2},
- * {@link #ASPECT_RATIO_1_1}, and
- * {@link #ASPECT_RATIO_2_3}.
- *
- * <p>Type: TEXT
- */
- public static final String COLUMN_THUMBNAIL_ASPECT_RATIO = "poster_thumbnail_aspect_ratio";
-
- /**
- * The URI for the logo of this TV program.
- *
- * <p>This is a small badge shown on top of the poster art or thumbnail representing the
- * source of the content.
- *
- * <p>The data in the column must be a URL, or a URI in one of the following formats:
- *
- * <ul>
- * <li>content ({@link android.content.ContentResolver#SCHEME_CONTENT})</li>
- * <li>android.resource ({@link android.content.ContentResolver#SCHEME_ANDROID_RESOURCE})
- * </li>
- * <li>file ({@link android.content.ContentResolver#SCHEME_FILE})</li>
- * </ul>
- *
- * <p>Can be empty.
- *
- * <p>Type: TEXT
- */
- public static final String COLUMN_LOGO_URI = "logo_uri";
-
- /**
- * The availability of this TV program.
- *
- * <p>The value should match one of the followings:
- * {@link #AVAILABILITY_AVAILABLE},
- * {@link #AVAILABILITY_FREE_WITH_SUBSCRIPTION}, and
- * {@link #AVAILABILITY_PAID_CONTENT}.
- *
- * <p>Type: TEXT
- */
- public static final String COLUMN_AVAILABILITY = "availability";
-
- /**
- * The starting price of this TV program.
- *
- * <p>This indicates the lowest regular acquisition cost of the content. It is only used
- * if the availability of the program is {@link #AVAILABILITY_PAID_CONTENT}.
- *
- * <p>Type: TEXT
- * @see #COLUMN_OFFER_PRICE
- */
- public static final String COLUMN_STARTING_PRICE = "starting_price";
-
- /**
- * The offer price of this TV program.
- *
- * <p>This is the promotional cost of the content. It is only used if the availability of
- * the program is {@link #AVAILABILITY_PAID_CONTENT}.
- *
- * <p>Type: TEXT
- * @see #COLUMN_STARTING_PRICE
- */
- public static final String COLUMN_OFFER_PRICE = "offer_price";
-
- /**
- * The release date of this TV program.
- *
- * <p>The value should be in the form of either "yyyy-MM-dd" or "yyyy".
- *
- * <p>Type: TEXT
- */
- public static final String COLUMN_RELEASE_DATE = "release_date";
-
- /**
- * The count of the items included in this TV program.
- *
- * <p>This is only relevant if the program represents a collection of items such as series,
- * episodes, or music tracks.
- *
- * <p>Type: INTEGER
- */
- public static final String COLUMN_ITEM_COUNT = "item_count";
-
- /**
- * The flag indicating whether this TV program is live or not.
- *
- * <p>A value of 1 indicates that the content is airing and should be consumed now, a value
- * of 0 indicates that the content is off the air and does not need to be consumed at the
- * present time. If not specified, the value is set to 0 (not live) by default.
- *
- * <p>Type: INTEGER (boolean)
- */
- public static final String COLUMN_LIVE = "live";
-
- /**
- * The internal ID used by individual TV input services.
- *
- * <p>This is internal to the provider that inserted it, and should not be decoded by other
- * apps.
- *
- * <p>Can be empty.
- *
- * <p>Type: TEXT
- */
- public static final String COLUMN_INTERNAL_PROVIDER_ID = "internal_provider_id";
-
- /**
- * The URI for the preview video.
- *
- * <p>This is only relevant to {@link Channels#TYPE_PREVIEW}. The data in the column must be
- * a URL, or a URI in one of the following formats:
- *
- * <ul>
- * <li>content ({@link android.content.ContentResolver#SCHEME_CONTENT})</li>
- * <li>android.resource ({@link android.content.ContentResolver#SCHEME_ANDROID_RESOURCE})
- * </li>
- * <li>file ({@link android.content.ContentResolver#SCHEME_FILE})</li>
- * </ul>
- *
- * <p>Can be empty.
- *
- * <p>Type: TEXT
- */
- public static final String COLUMN_PREVIEW_VIDEO_URI = "preview_video_uri";
-
- /**
- * The last playback position (in milliseconds) of the preview video.
- *
- * <p>This is only relevant to {@link Channels#TYPE_PREVIEW}.
- *
- * <p>Can be empty.
- *
- * <p>Type: INTEGER
- */
- public static final String COLUMN_LAST_PLAYBACK_POSITION_MILLIS =
- "last_playback_position_millis";
-
- /**
- * The duration (in milliseconds) of the preview video.
- *
- * <p>This is only relevant to {@link Channels#TYPE_PREVIEW}.
- *
- * <p>Can be empty.
- *
- * <p>Type: INTEGER
- */
- public static final String COLUMN_DURATION_MILLIS = "duration_millis";
-
- /**
- * The intent URI which is launched when the preview video is selected.
- *
- * <p>The URI is created using {@link Intent#toUri} with {@link Intent#URI_INTENT_SCHEME}
- * and converted back to the original intent with {@link Intent#parseUri}. The intent is
- * launched when the user selects the preview video item.
- *
- * <p>Can be empty.
- *
- * <p>Type: TEXT
- */
- public static final String COLUMN_APP_LINK_INTENT_URI =
- "app_link_intent_uri";
+ public static final String COLUMN_CHANNEL_ID = "channel_id";
/**
* The weight of the preview program within the channel.
@@ -2438,100 +2701,107 @@
*/
public static final String COLUMN_WEIGHT = "weight";
- /**
- * The flag indicating whether this program is transient or not.
- *
- * <p>A value of 1 indicates that the channel will be automatically removed by the system on
- * reboot, and a value of 0 indicates that the channel is persistent across reboot. If not
- * specified, this value is set to 0 (not transient) by default.
- *
- * <p>Type: INTEGER (boolean)
- * @see Channels#COLUMN_TRANSIENT
- * @hide
- */
- @SystemApi
- public static final String COLUMN_TRANSIENT = "transient";
+ private PreviewPrograms() {}
+ }
+
+ /**
+ * Column definitions for the "watch next" TV programs table.
+ */
+ public static final class WatchNextPrograms implements BasePreviewProgramColumns {
+
+ /** The content:// style URI for this table. */
+ public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/"
+ + PATH_WATCH_NEXT_PROGRAM);
+
+ /** The MIME type of a directory of "watch next" TV programs. */
+ public static final String CONTENT_TYPE = "vnd.android.cursor.dir/watch_next_program";
+
+ /** The MIME type of a single preview TV program. */
+ public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/watch_next_program";
+
+ /** @hide */
+ @StringDef({
+ WATCH_NEXT_TYPE_CONTINUE,
+ WATCH_NEXT_TYPE_NEXT,
+ WATCH_NEXT_TYPE_NEW,
+ WATCH_NEXT_TYPE_WATCHLIST,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface WatchNextType {}
/**
- * The type of interaction for this TV program.
+ * The watch next type for CONTINUE. Use this type when the user has already watched more
+ * than 1 minute of this content.
*
- * <p> The value should match one of the followings:
- * {@link #INTERACTION_TYPE_LISTENS},
- * {@link #INTERACTION_TYPE_FOLLOWERS},
- * {@link #INTERACTION_TYPE_FANS},
- * {@link #INTERACTION_TYPE_LIKES},
- * {@link #INTERACTION_TYPE_THUMBS},
- * {@link #INTERACTION_TYPE_VIEWS}, and
- * {@link #INTERACTION_TYPE_VIEWERS}.
+ * @see #COLUMN_WATCH_NEXT_TYPE
+ */
+ public static final String WATCH_NEXT_TYPE_CONTINUE = "WATCH_NEXT_TYPE_CONTINUE";
+
+ /**
+ * The watch next type for NEXT. Use this type when the user has watched one or more
+ * complete episodes from some episodic content, but there remains more than one episode
+ * remaining or there is one last episode remaining, but it is not “new” in that it was
+ * released before the user started watching the show.
+ *
+ * @see #COLUMN_WATCH_NEXT_TYPE
+ */
+ public static final String WATCH_NEXT_TYPE_NEXT = "WATCH_NEXT_TYPE_NEXT";
+
+ /**
+ * The watch next type for NEW. Use this type when the user had watched all of the available
+ * episodes from some episodic content, but a new episode became available since the user
+ * started watching the first episode and now there is exactly one unwatched episode. This
+ * could also work for recorded events in a series e.g. soccer matches or football games.
+ *
+ * @see #COLUMN_WATCH_NEXT_TYPE
+ */
+ public static final String WATCH_NEXT_TYPE_NEW = "WATCH_NEXT_TYPE_NEW";
+
+ /**
+ * The watch next type for WATCHLIST. Use this type when the user has elected to explicitly
+ * add a movie, event or series to a “watchlist” as a manual way of curating what they
+ * want to watch next.
+ *
+ * @see #COLUMN_WATCH_NEXT_TYPE
+ */
+ public static final String WATCH_NEXT_TYPE_WATCHLIST = "WATCH_NEXT_TYPE_WATCHLIST";
+
+ /**
+ * The "watch next" type of this program content.
+ *
+ * <p>The value should match one of the followings:
+ * {@link #WATCH_NEXT_TYPE_CONTINUE},
+ * {@link #WATCH_NEXT_TYPE_NEXT},
+ * {@link #WATCH_NEXT_TYPE_NEW}, and
+ * {@link #WATCH_NEXT_TYPE_WATCHLIST}.
+ *
+ * <p>This is a required field.
*
* <p>Type: TEXT
- * @see #COLUMN_INTERACTION_COUNT
*/
- public static final String COLUMN_INTERACTION_TYPE = "interaction_type";
+ public static final String COLUMN_WATCH_NEXT_TYPE = "watch_next_type";
/**
- * The interaction count for this program.
+ * The last UTC time that the user engaged in this TV program, in milliseconds since the
+ * epoch. This is a hint for the application that is used for ordering of "watch next"
+ * programs.
*
- * <p>This indicates the number of times interaction has happened.
+ * <p>The meaning of the value varies depending on the {@link #COLUMN_WATCH_NEXT_TYPE}:
+ * <ul>
+ * <li>{@link #WATCH_NEXT_TYPE_CONTINUE}: the date that the user was last watching the
+ * content.</li>
+ * <li>{@link #WATCH_NEXT_TYPE_NEXT}: the date of the last episode watched.</li>
+ * <li>{@link #WATCH_NEXT_TYPE_NEW}: the release date of the new episode.</li>
+ * <li>{@link #WATCH_NEXT_TYPE_WATCHLIST}: the date the item was added to the Watchlist.
+ * </li>
+ * </ul>
+ *
+ * <p>This is a required field.
*
* <p>Type: INTEGER (long)
- * @see #COLUMN_INTERACTION_TYPE
*/
- public static final String COLUMN_INTERACTION_COUNT = "interaction_count";
-
- /**
- * The author or artist of this content.
- *
- * <p>Type: TEXT
- */
- public static final String COLUMN_AUTHOR = "author";
-
- /**
- * The review rating score style used for {@link #COLUMN_REVIEW_RATING}.
- *
- * <p> The value should match one of the followings: {@link #REVIEW_RATING_STYLE_STARS},
- * {@link #REVIEW_RATING_STYLE_THUMBS_UP_DOWN}, and {@link #REVIEW_RATING_STYLE_PERCENTAGE}.
- *
- * <p>Type: TEXT
- * @see #COLUMN_REVIEW_RATING
- */
- public static final String COLUMN_REVIEW_RATING_STYLE = "review_rating_style";
-
- /**
- * The review rating score for this program.
- *
- * <p>The format of the value is dependent on {@link #COLUMN_REVIEW_RATING_STYLE}. If the
- * style is {@link #REVIEW_RATING_STYLE_STARS}, the value should be a real number between
- * 0.0 and 5.0. (e.g. "4.5") If the style is {@link #REVIEW_RATING_STYLE_THUMBS_UP_DOWN},
- * the value should be two integers, one for thumbs-up count and the other for thumbs-down
- * count, with a comma between them. (e.g. "200,40") If the style is
- * {@link #REVIEW_RATING_STYLE_PERCENTAGE}, the value shoule be a real number between 0 and
- * 100. (e.g. "99.9")
- *
- * <p>Type: TEXT
- * @see #COLUMN_REVIEW_RATING_STYLE
- */
- public static final String COLUMN_REVIEW_RATING = "review_rating";
-
- /**
- * The flag indicating whether this TV program is browsable or not.
- *
- * <p>This column can only be set by system apps. For other applications, it is a read-only
- * column. Trying to modify it may cause {@link SecurityException}.
- *
- * <p>A value of 1 indicates that the program is browsable and can be shown to users in
- * the UI. A value of 0 indicates that the program should be hidden from users and the
- * application who changes this value to 0 should send
- * {@link TvInputManager#ACTION_PROGRAM_BROWSABLE_DISABLED} to the owner of the program
- * to notify this change.
- *
- * <p>This value is set to 1 (browsable) by default.
- *
- * <p>Type: INTEGER (boolean)
- */
- public static final String COLUMN_BROWSABLE = "browsable";
-
- private PreviewPrograms() {}
+ public static final String COLUMN_LAST_ENGAGEMENT_TIME_UTC_MILLIS =
+ "last_engagement_time_utc_millis";
}
/**
diff --git a/media/java/android/media/tv/TvInputManager.java b/media/java/android/media/tv/TvInputManager.java
index 4c2b031..1eae8db 100644
--- a/media/java/android/media/tv/TvInputManager.java
+++ b/media/java/android/media/tv/TvInputManager.java
@@ -324,40 +324,6 @@
public static final String ACTION_VIEW_RECORDING_SCHEDULES =
"android.media.tv.action.VIEW_RECORDING_SCHEDULES";
- /**
- * Action sent by the system to tell the target TV input that one of its program's browsable
- * state is disabled, i.e., it will no longer be shown to users, which, for example, might
- * be a result of users' interaction with UI.
- *
- * <p>The intent must contain the following bundle parameter:
- * <ul>
- * <li>{@link #EXTRA_PROGRAM_ID} the program ID as a long integer.
- * </ul>
- */
- public static final String ACTION_PROGRAM_BROWSABLE_DISABLED =
- "android.media.tv.action.PROGRAM_BROWSABLE_DISABLED";
-
- /**
- * Action sent by an application telling the system to set the given channel as browsable.
- *
- * <p>The intent must contain the following bundle parameters:
- * <ul>
- * <li>{@link #EXTRA_CHANNEL_ID} the channel ID as a long integer.
- * <li>{@link #EXTRA_PACKAGE_NAME} the package name of the requesting application.
- * </ul>
- */
- public static final String ACTION_MAKE_CHANNEL_BROWSABLE
- = "android.media.tv.action.MAKE_CHANNEL_BROWSABLE";
-
- /** The key for a bundle parameter containing a channel ID as a long integer */
- public static final String EXTRA_CHANNEL_ID = "android.media.tv.extra.CHANNEL_ID";
-
- /** The key for a bundle parameter containing a package name as a string. */
- public static final String EXTRA_PACKAGE_NAME = "android.media.tv.extra.PACKAGE_NAME";
-
- /** The key for a bundle parameter containing a program ID as a long integer */
- public static final String EXTRA_PROGRAM_ID = "android.media.tv.extra.PROGRAM_ID";
-
private final ITvInputManager mService;
private final Object mLock = new Object();
diff --git a/media/java/android/media/tv/TvView.java b/media/java/android/media/tv/TvView.java
index aee9d38e..e5af357 100644
--- a/media/java/android/media/tv/TvView.java
+++ b/media/java/android/media/tv/TvView.java
@@ -776,8 +776,8 @@
mSurface = null;
mSurfaceView = new SurfaceView(getContext(), mAttrs, mDefStyleAttr) {
@Override
- protected void updateWindow() {
- super.updateWindow();
+ protected void updateSurface() {
+ super.updateSurface();
relayoutSessionOverlayView();
}};
// The surface view's content should be treated as secure all the time.
diff --git a/media/jni/Android.mk b/media/jni/Android.mk
index f69313c..861ed0a 100644
--- a/media/jni/Android.mk
+++ b/media/jni/Android.mk
@@ -8,6 +8,7 @@
android_media_MediaCodec.cpp \
android_media_MediaCodecList.cpp \
android_media_MediaDataSource.cpp \
+ android_media_MediaDescrambler.cpp \
android_media_MediaDrm.cpp \
android_media_MediaExtractor.cpp \
android_media_MediaHTTPConnection.cpp \
diff --git a/media/jni/android_media_MediaCodec.cpp b/media/jni/android_media_MediaCodec.cpp
index 6f9883c..293e5dd 100644
--- a/media/jni/android_media_MediaCodec.cpp
+++ b/media/jni/android_media_MediaCodec.cpp
@@ -25,9 +25,12 @@
#include "android_media_Utils.h"
#include "android_runtime/AndroidRuntime.h"
#include "android_runtime/android_view_Surface.h"
+#include "android_util_Binder.h"
#include "jni.h"
#include "JNIHelp.h"
+#include <android/media/IDescrambler.h>
+
#include <cutils/compiler.h>
#include <gui/Surface.h>
@@ -269,6 +272,7 @@
const sp<AMessage> &format,
const sp<IGraphicBufferProducer> &bufferProducer,
const sp<ICrypto> &crypto,
+ const sp<IDescrambler> &descrambler,
int flags) {
sp<Surface> client;
if (bufferProducer != NULL) {
@@ -278,7 +282,8 @@
mSurfaceTextureClient.clear();
}
- return mCodec->configure(format, mSurfaceTextureClient, crypto, flags);
+ return mCodec->configure(
+ format, mSurfaceTextureClient, crypto, descrambler, flags);
}
status_t JMediaCodec::setSurface(
@@ -967,6 +972,7 @@
jobjectArray keys, jobjectArray values,
jobject jsurface,
jobject jcrypto,
+ jobject descramblerBinderObj,
jint flags) {
sp<JMediaCodec> codec = getMediaCodec(env, thiz);
@@ -1002,7 +1008,13 @@
crypto = JCrypto::GetCrypto(env, jcrypto);
}
- err = codec->configure(format, bufferProducer, crypto, flags);
+ sp<IDescrambler> descrambler;
+ if (descramblerBinderObj != NULL) {
+ sp<IBinder> binder = ibinderForJavaObject(env, descramblerBinderObj);
+ descrambler = interface_cast<IDescrambler>(binder);
+ }
+
+ err = codec->configure(format, bufferProducer, crypto, descrambler, flags);
throwExceptionAsNecessary(env, err);
}
@@ -1942,7 +1954,7 @@
{ "native_configure",
"([Ljava/lang/String;[Ljava/lang/Object;Landroid/view/Surface;"
- "Landroid/media/MediaCrypto;I)V",
+ "Landroid/media/MediaCrypto;Landroid/os/IBinder;I)V",
(void *)android_media_MediaCodec_native_configure },
{ "native_setSurface",
diff --git a/media/jni/android_media_MediaCodec.h b/media/jni/android_media_MediaCodec.h
index b3b1b3a..a8c76c5 100644
--- a/media/jni/android_media_MediaCodec.h
+++ b/media/jni/android_media_MediaCodec.h
@@ -35,6 +35,10 @@
struct MediaCodec;
struct PersistentSurface;
class Surface;
+namespace media {
+class IDescrambler;
+};
+using namespace media;
struct JMediaCodec : public AHandler {
JMediaCodec(
@@ -54,6 +58,7 @@
const sp<AMessage> &format,
const sp<IGraphicBufferProducer> &bufferProducer,
const sp<ICrypto> &crypto,
+ const sp<IDescrambler> &descrambler,
int flags);
status_t setSurface(
diff --git a/media/jni/android_media_MediaDescrambler.cpp b/media/jni/android_media_MediaDescrambler.cpp
new file mode 100644
index 0000000..7585664
--- /dev/null
+++ b/media/jni/android_media_MediaDescrambler.cpp
@@ -0,0 +1,325 @@
+/*
+ * Copyright 2017, 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.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "MediaDescrambler-JNI"
+#include <utils/Log.h>
+
+#include "android_media_MediaDescrambler.h"
+#include "android_runtime/AndroidRuntime.h"
+#include "android_util_Binder.h"
+#include "JNIHelp.h"
+
+#include <android/media/IDescrambler.h>
+#include <binder/MemoryDealer.h>
+#include <media/stagefright/foundation/ADebug.h>
+#include <nativehelper/ScopedLocalRef.h>
+
+namespace android {
+using media::MediaDescrambler::DescrambleInfo;
+
+struct fields_t {
+ jfieldID context;
+};
+
+static fields_t gFields;
+
+static sp<JDescrambler> getDescrambler(JNIEnv *env, jobject thiz) {
+ return (JDescrambler *)env->GetLongField(thiz, gFields.context);
+}
+
+static void setDescrambler(
+ JNIEnv *env, jobject thiz, const sp<JDescrambler> &descrambler) {
+ sp<JDescrambler> old = (JDescrambler *)env->GetLongField(thiz, gFields.context);
+ if (descrambler != NULL) {
+ descrambler->incStrong(thiz);
+ }
+ if (old != NULL) {
+ old->decStrong(thiz);
+ }
+ env->SetLongField(thiz, gFields.context, (jlong)descrambler.get());
+}
+
+static status_t getBufferAndSize(
+ JNIEnv *env, jobject byteBuf, jint offset, size_t length,
+ void **outPtr, jbyteArray *outByteArray) {
+ void *ptr = env->GetDirectBufferAddress(byteBuf);
+
+ size_t bufSize;
+ jbyteArray byteArray = NULL;
+
+ ScopedLocalRef<jclass> byteBufClass(env, env->FindClass("java/nio/ByteBuffer"));
+ CHECK(byteBufClass.get() != NULL);
+
+ if (ptr == NULL) {
+ jmethodID arrayID =
+ env->GetMethodID(byteBufClass.get(), "array", "()[B");
+ CHECK(arrayID != NULL);
+
+ byteArray =
+ (jbyteArray)env->CallObjectMethod(byteBuf, arrayID);
+
+ if (byteArray == NULL) {
+ return INVALID_OPERATION;
+ }
+
+ jboolean isCopy;
+ ptr = env->GetByteArrayElements(byteArray, &isCopy);
+
+ bufSize = (size_t) env->GetArrayLength(byteArray);
+ } else {
+ bufSize = (size_t) env->GetDirectBufferCapacity(byteBuf);
+ }
+
+ if (length + offset > bufSize) {
+ if (byteArray != NULL) {
+ env->ReleaseByteArrayElements(byteArray, (jbyte *)ptr, 0);
+ }
+
+ return -ERANGE;
+ }
+
+ *outPtr = ptr;
+ *outByteArray = byteArray;
+
+ return OK;
+}
+
+JDescrambler::JDescrambler(JNIEnv *env, jobject descramblerBinderObj) {
+ sp<IDescrambler> cas;
+ if (descramblerBinderObj != NULL) {
+ sp<IBinder> binder = ibinderForJavaObject(env, descramblerBinderObj);
+ mDescrambler = interface_cast<IDescrambler>(binder);
+ }
+}
+
+JDescrambler::~JDescrambler() {
+ // Don't call release() here, it's called by Java class
+ mDescrambler.clear();
+ mMem.clear();
+ mDealer.clear();
+}
+
+void JDescrambler::ensureBufferCapacity(size_t neededSize) {
+ if (mMem != NULL && mMem->size() >= neededSize) {
+ return;
+ }
+
+ ALOGV("ensureBufferCapacity: current size %zu, new size %zu",
+ mMem == NULL ? 0 : mMem->size(), neededSize);
+
+ size_t alignment = MemoryDealer::getAllocationAlignment();
+ neededSize = (neededSize + (alignment - 1)) & ~(alignment - 1);
+ // Align to multiples of 64K.
+ neededSize = (neededSize + 65535) & ~65535;
+ mDealer = new MemoryDealer(neededSize, "JDescrambler");
+ mMem = mDealer->allocate(neededSize);
+}
+
+ssize_t JDescrambler::descramble(
+ jbyte key,
+ size_t numSubSamples,
+ ssize_t totalLength,
+ DescramblerPlugin::SubSample *subSamples,
+ const void *srcPtr,
+ jint srcOffset,
+ void *dstPtr,
+ jint dstOffset) {
+ // TODO: IDescrambler::descramble() is re-entrant, however because we
+ // only have 1 shared mem buffer, we can only do 1 descramble at a time.
+ // Concurrency might be improved by allowing on-demand allocation of up
+ // to 2 shared mem buffers.
+ Mutex::Autolock autolock(mSharedMemLock);
+
+ ensureBufferCapacity(totalLength);
+
+ memcpy(mMem->pointer(),
+ (const void*)((const uint8_t*)srcPtr + srcOffset), totalLength);
+
+ DescrambleInfo info;
+ info.dstType = DescrambleInfo::kDestinationTypeVmPointer;
+ info.numSubSamples = numSubSamples;
+ info.scramblingControl = (DescramblerPlugin::ScramblingControl) key;
+ info.subSamples = subSamples;
+ info.srcMem = mMem;
+ info.srcOffset = 0;
+ info.dstPtr = NULL;
+ info.dstOffset = 0;
+
+ int32_t result;
+ binder::Status status = mDescrambler->descramble(info, &result);
+
+ if (!status.isOk() || result > totalLength) {
+ return -1;
+ }
+ if (result > 0) {
+ memcpy((void*)((uint8_t*)dstPtr + dstOffset), mMem->pointer(), result);
+ }
+ return result;
+}
+
+} // namespace android
+
+using namespace android;
+
+static void android_media_MediaDescrambler_native_release(JNIEnv *env, jobject thiz) {
+ setDescrambler(env, thiz, NULL);
+}
+
+static void android_media_MediaDescrambler_native_init(JNIEnv *env) {
+ ScopedLocalRef<jclass> clazz(
+ env, env->FindClass("android/media/MediaDescrambler"));
+ CHECK(clazz.get() != NULL);
+
+ gFields.context = env->GetFieldID(clazz.get(), "mNativeContext", "J");
+ CHECK(gFields.context != NULL);
+}
+
+static void android_media_MediaDescrambler_native_setup(
+ JNIEnv *env, jobject thiz, jobject descramblerBinderObj) {
+ setDescrambler(env, thiz, new JDescrambler(env, descramblerBinderObj));
+}
+
+static ssize_t getSubSampleInfo(JNIEnv *env, jint numSubSamples,
+ jintArray numBytesOfClearDataObj, jintArray numBytesOfEncryptedDataObj,
+ DescramblerPlugin::SubSample **outSubSamples) {
+
+ if (numSubSamples <= 0 || numSubSamples >=
+ (signed)(INT32_MAX / sizeof(DescramblerPlugin::SubSample)) ) {
+ // subSamples array may silently overflow if number of samples are
+ // too large. Use INT32_MAX as maximum allocation size may be less
+ // than SIZE_MAX on some platforms.
+ ALOGE("numSubSamples is invalid!");
+ return -1;
+ }
+
+ jboolean isCopy;
+ ssize_t totalSize = 0;
+
+ jint *numBytesOfClearData =
+ (numBytesOfClearDataObj == NULL)
+ ? NULL
+ : env->GetIntArrayElements(numBytesOfClearDataObj, &isCopy);
+
+ jint *numBytesOfEncryptedData =
+ (numBytesOfEncryptedDataObj == NULL)
+ ? NULL
+ : env->GetIntArrayElements(numBytesOfEncryptedDataObj, &isCopy);
+
+ DescramblerPlugin::SubSample *subSamples =
+ new(std::nothrow) DescramblerPlugin::SubSample[numSubSamples];
+
+ if (subSamples == NULL) {
+ ALOGE("Failed to allocate SubSample array!");
+ return -1;
+ }
+
+ for (jint i = 0; i < numSubSamples; ++i) {
+ subSamples[i].mNumBytesOfClearData =
+ (numBytesOfClearData == NULL) ? 0 : numBytesOfClearData[i];
+
+ subSamples[i].mNumBytesOfEncryptedData =
+ (numBytesOfEncryptedData == NULL)
+ ? 0 : numBytesOfEncryptedData[i];
+
+ totalSize += subSamples[i].mNumBytesOfClearData +
+ subSamples[i].mNumBytesOfEncryptedData;
+ }
+
+ if (numBytesOfEncryptedData != NULL) {
+ env->ReleaseIntArrayElements(
+ numBytesOfEncryptedDataObj, numBytesOfEncryptedData, 0);
+ numBytesOfEncryptedData = NULL;
+ }
+
+ if (numBytesOfClearData != NULL) {
+ env->ReleaseIntArrayElements(
+ numBytesOfClearDataObj, numBytesOfClearData, 0);
+ numBytesOfClearData = NULL;
+ }
+
+ *outSubSamples = subSamples;
+
+ return totalSize;
+}
+
+static jint android_media_MediaDescrambler_native_descramble(
+ JNIEnv *env, jobject thiz, jbyte key, jint numSubSamples,
+ jintArray numBytesOfClearDataObj, jintArray numBytesOfEncryptedDataObj,
+ jobject srcBuf, jint srcOffset, jobject dstBuf, jint dstOffset) {
+ sp<JDescrambler> descrambler = getDescrambler(env, thiz);
+ if (descrambler == NULL) {
+ jniThrowException(env, "java/lang/IllegalStateException", NULL);
+ return -1;
+ }
+
+ DescramblerPlugin::SubSample *subSamples = NULL;
+ ssize_t totalLength = getSubSampleInfo(
+ env, numSubSamples, numBytesOfClearDataObj,
+ numBytesOfEncryptedDataObj, &subSamples);
+ if (totalLength < 0) {
+ jniThrowException(env, "java/lang/IllegalArgumentException",
+ "Invalid sub sample info!");
+ return -1;
+ }
+
+ ssize_t result = -1;
+ void *srcPtr = NULL, *dstPtr = NULL;
+ jbyteArray srcArray = NULL, dstArray = NULL;
+ status_t err = getBufferAndSize(
+ env, srcBuf, srcOffset, totalLength, &srcPtr, &srcArray);
+
+ if (err == OK) {
+ if (dstBuf == NULL) {
+ dstPtr = srcPtr;
+ } else {
+ err = getBufferAndSize(
+ env, dstBuf, dstOffset, totalLength, &dstPtr, &dstArray);
+ }
+ }
+
+ if (err == OK) {
+ result = descrambler->descramble(
+ key, numSubSamples, totalLength, subSamples,
+ srcPtr, srcOffset, dstPtr, dstOffset);
+ }
+
+ delete[] subSamples;
+ if (srcArray != NULL) {
+ env->ReleaseByteArrayElements(srcArray, (jbyte *)srcPtr, 0);
+ }
+ if (dstArray != NULL) {
+ env->ReleaseByteArrayElements(dstArray, (jbyte *)dstPtr, 0);
+ }
+ return result;
+}
+
+static const JNINativeMethod gMethods[] = {
+ { "native_release", "()V",
+ (void *)android_media_MediaDescrambler_native_release },
+ { "native_init", "()V",
+ (void *)android_media_MediaDescrambler_native_init },
+ { "native_setup", "(Landroid/os/IBinder;)V",
+ (void *)android_media_MediaDescrambler_native_setup },
+ { "native_descramble", "(BI[I[ILjava/nio/ByteBuffer;ILjava/nio/ByteBuffer;I)I",
+ (void *)android_media_MediaDescrambler_native_descramble },
+};
+
+int register_android_media_Descrambler(JNIEnv *env) {
+ return AndroidRuntime::registerNativeMethods(env,
+ "android/media/MediaDescrambler", gMethods, NELEM(gMethods));
+}
+
diff --git a/media/jni/android_media_MediaDescrambler.h b/media/jni/android_media_MediaDescrambler.h
new file mode 100644
index 0000000..e944a90
--- /dev/null
+++ b/media/jni/android_media_MediaDescrambler.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2017, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _ANDROID_MEDIA_DESCRAMBLER_H_
+#define _ANDROID_MEDIA_DESCRAMBLER_H_
+
+#include "jni.h"
+
+#include <media/cas/DescramblerAPI.h>
+#include <media/stagefright/foundation/ABase.h>
+#include <utils/Mutex.h>
+#include <utils/RefBase.h>
+
+namespace android {
+class IMemory;
+class MemoryDealer;
+namespace media {
+class IDescrambler;
+};
+using namespace media;
+
+struct JDescrambler : public RefBase {
+ JDescrambler(JNIEnv *env, jobject descramberBinderObj);
+
+ ssize_t descramble(
+ jbyte key,
+ size_t numSubSamples,
+ ssize_t totalLength,
+ DescramblerPlugin::SubSample *subSamples,
+ const void *srcPtr,
+ jint srcOffset,
+ void *dstPtr,
+ jint dstOffset);
+
+protected:
+ virtual ~JDescrambler();
+
+private:
+ sp<IDescrambler> mDescrambler;
+ sp<IMemory> mMem;
+ sp<MemoryDealer> mDealer;
+ Mutex mSharedMemLock;
+
+ void ensureBufferCapacity(size_t neededSize);
+
+ DISALLOW_EVIL_CONSTRUCTORS(JDescrambler);
+};
+
+} // namespace android
+
+#endif // _ANDROID_MEDIA_DESCRAMBLER_H_
diff --git a/media/jni/android_media_MediaExtractor.cpp b/media/jni/android_media_MediaExtractor.cpp
index 2008f8d..3c33493 100644
--- a/media/jni/android_media_MediaExtractor.cpp
+++ b/media/jni/android_media_MediaExtractor.cpp
@@ -37,6 +37,7 @@
#include <media/stagefright/MediaErrors.h>
#include <media/stagefright/MetaData.h>
#include <media/stagefright/NuMediaExtractor.h>
+#include <android/media/ICas.h>
#include <nativehelper/ScopedLocalRef.h>
@@ -88,6 +89,10 @@
return mImpl->setDataSource(datasource);
}
+status_t JMediaExtractor::setMediaCas(const sp<ICas> &cas) {
+ return mImpl->setMediaCas(cas);
+}
+
size_t JMediaExtractor::countTracks() const {
return mImpl->countTracks();
}
@@ -734,6 +739,36 @@
}
}
+static void android_media_MediaExtractor_setMediaCas(
+ JNIEnv *env, jobject thiz, jobject casBinderObj) {
+ sp<JMediaExtractor> extractor = getMediaExtractor(env, thiz);
+
+ if (extractor == NULL) {
+ jniThrowException(env, "java/lang/IllegalStateException", NULL);
+ return;
+ }
+
+ if (casBinderObj == NULL) {
+ jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
+ return;
+ }
+
+ sp<ICas> cas;
+ if (casBinderObj != NULL) {
+ sp<IBinder> binder = ibinderForJavaObject(env, casBinderObj);
+ cas = interface_cast<ICas>(binder);
+ }
+ status_t err = extractor->setMediaCas(cas);
+
+ if (err != OK) {
+ cas.clear();
+ jniThrowException(
+ env,
+ "java/io/IllegalArgumentException",
+ "Failed to set MediaCas on extractor.");
+ }
+}
+
static jlong android_media_MediaExtractor_getCachedDurationUs(
JNIEnv *env, jobject thiz) {
sp<JMediaExtractor> extractor = getMediaExtractor(env, thiz);
@@ -861,6 +896,9 @@
{ "setDataSource", "(Landroid/media/MediaDataSource;)V",
(void *)android_media_MediaExtractor_setDataSourceCallback },
+ { "nativeSetMediaCas", "(Landroid/os/IBinder;)V",
+ (void *)android_media_MediaExtractor_setMediaCas },
+
{ "getCachedDuration", "()J",
(void *)android_media_MediaExtractor_getCachedDurationUs },
diff --git a/media/jni/android_media_MediaExtractor.h b/media/jni/android_media_MediaExtractor.h
index c747ef5..3d8c50b 100644
--- a/media/jni/android_media_MediaExtractor.h
+++ b/media/jni/android_media_MediaExtractor.h
@@ -28,6 +28,10 @@
#include "jni.h"
namespace android {
+namespace media {
+class ICas;
+};
+using namespace media;
struct IMediaHTTPService;
class MetaData;
@@ -44,6 +48,8 @@
status_t setDataSource(int fd, off64_t offset, off64_t size);
status_t setDataSource(const sp<DataSource> &source);
+ status_t setMediaCas(const sp<ICas> &cas);
+
size_t countTracks() const;
status_t getTrackFormat(size_t index, jobject *format) const;
diff --git a/media/jni/android_media_MediaPlayer.cpp b/media/jni/android_media_MediaPlayer.cpp
index 636727e..27724a1 100644
--- a/media/jni/android_media_MediaPlayer.cpp
+++ b/media/jni/android_media_MediaPlayer.cpp
@@ -1445,6 +1445,7 @@
extern int register_android_media_ImageWriter(JNIEnv *env);
extern int register_android_media_Crypto(JNIEnv *env);
extern int register_android_media_Drm(JNIEnv *env);
+extern int register_android_media_Descrambler(JNIEnv *env);
extern int register_android_media_MediaCodec(JNIEnv *env);
extern int register_android_media_MediaExtractor(JNIEnv *env);
extern int register_android_media_MediaCodecList(JNIEnv *env);
@@ -1561,6 +1562,11 @@
goto bail;
}
+ if (register_android_media_Descrambler(env) < 0) {
+ ALOGE("ERROR: MediaDescrambler native registration failed");
+ goto bail;
+ }
+
if (register_android_media_MediaHTTPConnection(env) < 0) {
ALOGE("ERROR: MediaHTTPConnection native registration failed");
goto bail;
diff --git a/native/android/Android.mk b/native/android/Android.mk
index 69544f5..57f996c 100644
--- a/native/android/Android.mk
+++ b/native/android/Android.mk
@@ -11,16 +11,15 @@
asset_manager.cpp \
choreographer.cpp \
configuration.cpp \
- hardware_buffer.cpp \
hardware_buffer_jni.cpp \
input.cpp \
looper.cpp \
native_activity.cpp \
- native_window.cpp \
native_window_jni.cpp \
net.c \
obb.cpp \
sensor.cpp \
+ sharedmem.cpp \
storage_manager.cpp \
trace.cpp \
@@ -38,7 +37,10 @@
LOCAL_STATIC_LIBRARIES := \
libstorage \
- libarect
+ libarect \
+
+LOCAL_WHOLE_STATIC_LIBRARIES := \
+ libnativewindow
LOCAL_C_INCLUDES += \
frameworks/base/native/include \
@@ -46,7 +48,9 @@
bionic/libc/dns/include \
system/netd/include \
-LOCAL_EXPORT_STATIC_LIBRARY_HEADERS := libarect
+LOCAL_EXPORT_STATIC_LIBRARY_HEADERS := \
+ libarect \
+ libnativewindow \
LOCAL_MODULE := libandroid
diff --git a/native/android/hardware_buffer.cpp b/native/android/hardware_buffer.cpp
deleted file mode 100644
index 77ebd52..0000000
--- a/native/android/hardware_buffer.cpp
+++ /dev/null
@@ -1,302 +0,0 @@
-/*
- * Copyright (C) 2017 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.
- */
-
-#define LOG_TAG "AHardwareBuffer"
-
-#include <android/hardware_buffer.h>
-
-#include <errno.h>
-#include <sys/socket.h>
-
-#include <memory>
-
-#include <cutils/native_handle.h>
-
-#include <utils/Log.h>
-
-#include <ui/GraphicBuffer.h>
-
-#include <binder/IServiceManager.h>
-#include <gui/ISurfaceComposer.h>
-#include <gui/IGraphicBufferAlloc.h>
-
-#include <android_runtime/android_hardware_HardwareBuffer.h>
-
-
-static constexpr int kDataBufferSize = 64 * sizeof(int); // 64 ints
-
-using namespace android;
-
-static inline const GraphicBuffer* AHardwareBuffer_to_GraphicBuffer(
- const AHardwareBuffer* buffer) {
- return reinterpret_cast<const GraphicBuffer*>(buffer);
-}
-
-static inline GraphicBuffer* AHardwareBuffer_to_GraphicBuffer(
- AHardwareBuffer* buffer) {
- return reinterpret_cast<GraphicBuffer*>(buffer);
-}
-
-static inline AHardwareBuffer* GraphicBuffer_to_AHardwareBuffer(
- GraphicBuffer* buffer) {
- return reinterpret_cast<AHardwareBuffer*>(buffer);
-}
-
-// ----------------------------------------------------------------------------
-// Public functions
-// ----------------------------------------------------------------------------
-
-int AHardwareBuffer_allocate(const AHardwareBuffer_Desc* desc,
- AHardwareBuffer** outBuffer) {
- if (!outBuffer || !desc) return BAD_VALUE;
-
- // The holder is used to destroy the buffer if an error occurs.
- sp<IServiceManager> sm = defaultServiceManager();
- if (sm == nullptr) {
- ALOGE("Unable to connect to ServiceManager");
- return PERMISSION_DENIED;
- }
-
- // Get the SurfaceFlingerService.
- sp<ISurfaceComposer> composer = interface_cast<ISurfaceComposer>(
- sm->getService(String16("SurfaceFlinger")));
- if (composer == nullptr) {
- ALOGE("Unable to connect to surface composer");
- return PERMISSION_DENIED;
- }
- // Get an IGraphicBufferAlloc to create the buffer.
- sp<IGraphicBufferAlloc> allocator = composer->createGraphicBufferAlloc();
- if (allocator == nullptr) {
- ALOGE("Unable to obtain a buffer allocator");
- return PERMISSION_DENIED;
- }
-
- int format = android_hardware_HardwareBuffer_convertToPixelFormat(
- desc->format);
- if (format == 0) {
- ALOGE("Invalid pixel format");
- return BAD_VALUE;
- }
-
- if (desc->format == AHARDWAREBUFFER_FORMAT_BLOB && desc->height != 1) {
- ALOGE("Height must be 1 when using the AHARDWAREBUFFER_FORMAT_BLOB "
- "format");
- return BAD_VALUE;
- }
-
- status_t err;
- uint64_t producerUsage = 0;
- uint64_t consumerUsage = 0;
- android_hardware_HardwareBuffer_convertToGrallocUsageBits(desc->usage0,
- desc->usage1, &producerUsage, &consumerUsage);
- sp<GraphicBuffer> gbuffer = allocator->createGraphicBuffer(desc->width,
- desc->height, format, desc->layers, producerUsage, consumerUsage,
- std::string("AHardwareBuffer pid [") + std::to_string(getpid()) +
- "]", &err);
- if (err != NO_ERROR) {
- return err;
- }
-
- *outBuffer = GraphicBuffer_to_AHardwareBuffer(gbuffer.get());
- // Ensure the buffer doesn't get destroyed with the sp<> goes away.
- AHardwareBuffer_acquire(*outBuffer);
- return NO_ERROR;
-}
-
-void AHardwareBuffer_acquire(AHardwareBuffer* buffer) {
- AHardwareBuffer_to_GraphicBuffer(buffer)->incStrong(
- (void*)AHardwareBuffer_acquire);
-}
-
-void AHardwareBuffer_release(AHardwareBuffer* buffer) {
- AHardwareBuffer_to_GraphicBuffer(buffer)->decStrong(
- (void*)AHardwareBuffer_acquire);
-}
-
-void AHardwareBuffer_describe(const AHardwareBuffer* buffer,
- AHardwareBuffer_Desc* outDesc) {
- if (!buffer || !outDesc) return;
-
- const GraphicBuffer* gbuffer = AHardwareBuffer_to_GraphicBuffer(buffer);
-
- outDesc->width = gbuffer->getWidth();
- outDesc->height = gbuffer->getHeight();
- outDesc->layers = gbuffer->getLayerCount();
- outDesc->usage0 =
- android_hardware_HardwareBuffer_convertFromGrallocUsageBits(
- gbuffer->getUsage(), gbuffer->getUsage());
- outDesc->usage1 = 0;
- outDesc->format = android_hardware_HardwareBuffer_convertFromPixelFormat(
- static_cast<uint32_t>(gbuffer->getPixelFormat()));
-}
-
-int AHardwareBuffer_lock(AHardwareBuffer* buffer, uint64_t usage0,
- int32_t fence, const ARect* rect, void** outVirtualAddress) {
- if (!buffer) return BAD_VALUE;
-
- if (usage0 & ~(AHARDWAREBUFFER_USAGE0_CPU_READ_OFTEN |
- AHARDWAREBUFFER_USAGE0_CPU_WRITE_OFTEN)) {
- ALOGE("Invalid usage flags passed to AHardwareBuffer_lock; only "
- " AHARDWAREBUFFER_USAGE0_CPU_* flags are allowed");
- return BAD_VALUE;
- }
-
- uint64_t producerUsage = 0;
- uint64_t consumerUsage = 0;
- android_hardware_HardwareBuffer_convertToGrallocUsageBits(usage0, 0,
- &producerUsage, &consumerUsage);
- GraphicBuffer* gBuffer = AHardwareBuffer_to_GraphicBuffer(buffer);
- Rect bounds;
- if (!rect) {
- bounds.set(Rect(gBuffer->getWidth(), gBuffer->getHeight()));
- } else {
- bounds.set(Rect(rect->left, rect->top, rect->right, rect->bottom));
- }
- return gBuffer->lockAsync(producerUsage, consumerUsage, bounds,
- outVirtualAddress, fence);
-}
-
-int AHardwareBuffer_unlock(AHardwareBuffer* buffer, int32_t* fence) {
- if (!buffer) return BAD_VALUE;
-
- GraphicBuffer* gBuffer = AHardwareBuffer_to_GraphicBuffer(buffer);
- return gBuffer->unlockAsync(fence);
-}
-
-int AHardwareBuffer_sendHandleToUnixSocket(const AHardwareBuffer* buffer,
- int socketFd) {
- if (!buffer) return BAD_VALUE;
- const GraphicBuffer* gBuffer = AHardwareBuffer_to_GraphicBuffer(buffer);
-
- size_t flattenedSize = gBuffer->getFlattenedSize();
- size_t fdCount = gBuffer->getFdCount();
-
- std::unique_ptr<uint8_t[]> data(new uint8_t[flattenedSize]);
- std::unique_ptr<int[]> fds(new int[fdCount]);
-
- // Make copies of needed items since flatten modifies them, and we don't
- // want to send anything if there's an error during flatten.
- size_t flattenedSizeCopy = flattenedSize;
- size_t fdCountCopy = fdCount;
- void* dataStart = data.get();
- int* fdsStart = fds.get();
- status_t err = gBuffer->flatten(dataStart, flattenedSizeCopy, fdsStart,
- fdCountCopy);
- if (err != NO_ERROR) {
- return err;
- }
-
- struct iovec iov[1];
- iov[0].iov_base = data.get();
- iov[0].iov_len = flattenedSize;
-
- char buf[CMSG_SPACE(kDataBufferSize)];
- struct msghdr msg = {
- .msg_control = buf,
- .msg_controllen = sizeof(buf),
- .msg_iov = &iov[0],
- .msg_iovlen = 1,
- };
-
- struct cmsghdr* cmsg = CMSG_FIRSTHDR(&msg);
- cmsg->cmsg_level = SOL_SOCKET;
- cmsg->cmsg_type = SCM_RIGHTS;
- cmsg->cmsg_len = CMSG_LEN(sizeof(int) * fdCount);
- int* fdData = reinterpret_cast<int*>(CMSG_DATA(cmsg));
- memcpy(fdData, fds.get(), sizeof(int) * fdCount);
- msg.msg_controllen = cmsg->cmsg_len;
-
- int result = sendmsg(socketFd, &msg, 0);
- if (result <= 0) {
- ALOGE("Error writing AHardwareBuffer to socket: error %#x (%s)",
- result, strerror(errno));
- return result;
- }
- return NO_ERROR;
-}
-
-int AHardwareBuffer_recvHandleFromUnixSocket(int socketFd,
- AHardwareBuffer** outBuffer) {
- if (!outBuffer) return BAD_VALUE;
-
- char dataBuf[CMSG_SPACE(kDataBufferSize)];
- char fdBuf[CMSG_SPACE(kDataBufferSize)];
- struct iovec iov[1];
- iov[0].iov_base = dataBuf;
- iov[0].iov_len = sizeof(dataBuf);
-
- struct msghdr msg = {
- .msg_control = fdBuf,
- .msg_controllen = sizeof(fdBuf),
- .msg_iov = &iov[0],
- .msg_iovlen = 1,
- };
-
- int result = recvmsg(socketFd, &msg, 0);
- if (result <= 0) {
- ALOGE("Error reading AHardwareBuffer from socket: error %#x (%s)",
- result, strerror(errno));
- return result;
- }
-
- if (msg.msg_iovlen != 1) {
- ALOGE("Error reading AHardwareBuffer from socket: bad data length");
- return INVALID_OPERATION;
- }
-
- if (msg.msg_controllen % sizeof(int) != 0) {
- ALOGE("Error reading AHardwareBuffer from socket: bad fd length");
- return INVALID_OPERATION;
- }
-
- size_t dataLen = msg.msg_iov[0].iov_len;
- const void* data = static_cast<const void*>(msg.msg_iov[0].iov_base);
- if (!data) {
- ALOGE("Error reading AHardwareBuffer from socket: no buffer data");
- return INVALID_OPERATION;
- }
-
- struct cmsghdr* cmsg = CMSG_FIRSTHDR(&msg);
- if (!cmsg) {
- ALOGE("Error reading AHardwareBuffer from socket: no fd header");
- return INVALID_OPERATION;
- }
-
- size_t fdCount = msg.msg_controllen >> 2;
- const int* fdData = reinterpret_cast<const int*>(CMSG_DATA(cmsg));
- if (!fdData) {
- ALOGE("Error reading AHardwareBuffer from socket: no fd data");
- return INVALID_OPERATION;
- }
-
- GraphicBuffer* gBuffer = new GraphicBuffer();
- status_t err = gBuffer->unflatten(data, dataLen, fdData, fdCount);
- if (err != NO_ERROR) {
- return err;
- }
- *outBuffer = GraphicBuffer_to_AHardwareBuffer(gBuffer);
- // Ensure the buffer has a positive ref-count.
- AHardwareBuffer_acquire(*outBuffer);
-
- return NO_ERROR;
-}
-
-const struct native_handle* AHardwareBuffer_getNativeHandle(
- const AHardwareBuffer* buffer) {
- if (!buffer) return nullptr;
- const GraphicBuffer* gbuffer = AHardwareBuffer_to_GraphicBuffer(buffer);
- return gbuffer->handle;
-}
diff --git a/native/android/libandroid.map.txt b/native/android/libandroid.map.txt
index f9e8fda..1b1f28c 100644
--- a/native/android/libandroid.map.txt
+++ b/native/android/libandroid.map.txt
@@ -170,14 +170,20 @@
ASensorEventQueue_getEvents;
ASensorEventQueue_hasEvents;
ASensorEventQueue_setEventRate;
+ ASensorManager_configureDirectReport; # introduced=26
ASensorManager_createEventQueue;
+ ASensorManager_createHardwareBufferDirectChannel; # introduced=26
+ ASensorManager_createSharedMemoryDirectChannel; # introduced=26
+ ASensorManager_destroyDirectChannel; # introduced=26
ASensorManager_destroyEventQueue;
ASensorManager_getDefaultSensor;
ASensorManager_getDefaultSensorEx; # introduced=21
ASensorManager_getInstance;
+ ASensorManager_getInstanceForPackage; # introduced=26
ASensorManager_getSensorList;
ASensor_getFifoMaxEventCount; # introduced=21
ASensor_getFifoReservedEventCount; # introduced=21
+ ASensor_getHighestDirectReportRateLevel; # introduced=26
ASensor_getMinDelay;
ASensor_getName;
ASensor_getReportingMode; # introduced=21
@@ -185,7 +191,11 @@
ASensor_getStringType; # introduced=21
ASensor_getType;
ASensor_getVendor;
+ ASensor_isDirectChannelTypeSupported; # introduced=26
ASensor_isWakeUpSensor; # introduced=21
+ ASharedMemory_create; # introduced=26
+ ASharedMemory_getSize; # introduced=26
+ ASharedMemory_setProt; # introduced=26
AStorageManager_delete;
AStorageManager_getMountedObbPath;
AStorageManager_isObbMounted;
diff --git a/native/android/native_window.cpp b/native/android/native_window.cpp
deleted file mode 100644
index 8c080d7..0000000
--- a/native/android/native_window.cpp
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * Copyright (C) 2010 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.
- */
-
-#define LOG_TAG "Surface"
-
-#include <android/native_window.h>
-#include <system/window.h>
-
-void ANativeWindow_acquire(ANativeWindow* window) {
- window->incStrong((void*)ANativeWindow_acquire);
-}
-
-void ANativeWindow_release(ANativeWindow* window) {
- window->decStrong((void*)ANativeWindow_acquire);
-}
-
-static int32_t getWindowProp(ANativeWindow* window, int what) {
- int value;
- int res = window->query(window, what, &value);
- return res < 0 ? res : value;
-}
-
-int32_t ANativeWindow_getWidth(ANativeWindow* window) {
- return getWindowProp(window, NATIVE_WINDOW_WIDTH);
-}
-
-int32_t ANativeWindow_getHeight(ANativeWindow* window) {
- return getWindowProp(window, NATIVE_WINDOW_HEIGHT);
-}
-
-int32_t ANativeWindow_getFormat(ANativeWindow* window) {
- return getWindowProp(window, NATIVE_WINDOW_FORMAT);
-}
-
-int32_t ANativeWindow_setBuffersGeometry(ANativeWindow* window, int32_t width,
- int32_t height, int32_t format) {
- int32_t err = native_window_set_buffers_format(window, format);
- if (!err) {
- err = native_window_set_buffers_user_dimensions(window, width, height);
- if (!err) {
- int mode = NATIVE_WINDOW_SCALING_MODE_FREEZE;
- if (width && height) {
- mode = NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW;
- }
- err = native_window_set_scaling_mode(window, mode);
- }
- }
- return err;
-}
-
-int32_t ANativeWindow_lock(ANativeWindow* window, ANativeWindow_Buffer* outBuffer,
- ARect* inOutDirtyBounds) {
- return window->perform(window, NATIVE_WINDOW_LOCK, outBuffer, inOutDirtyBounds);
-}
-
-int32_t ANativeWindow_unlockAndPost(ANativeWindow* window) {
- return window->perform(window, NATIVE_WINDOW_UNLOCK_AND_POST);
-}
diff --git a/native/android/sensor.cpp b/native/android/sensor.cpp
index 5cfe300..c7bc885 100644
--- a/native/android/sensor.cpp
+++ b/native/android/sensor.cpp
@@ -17,16 +17,17 @@
#define LOG_TAG "sensor"
#include <utils/Log.h>
+#include <android/hardware_buffer.h>
#include <android/looper.h>
#include <android/sensor.h>
-
-#include <utils/RefBase.h>
-#include <utils/Looper.h>
-#include <utils/Timers.h>
-
+#include <android/sharedmem.h>
+#include <cutils/native_handle.h>
#include <gui/Sensor.h>
#include <gui/SensorManager.h>
#include <gui/SensorEventQueue.h>
+#include <utils/Looper.h>
+#include <utils/RefBase.h>
+#include <utils/Timers.h>
#include <poll.h>
@@ -38,6 +39,22 @@
using android::String16;
/*****************************************************************************/
+#define ERROR_INVALID_PARAMETER(message) ALOGE("%s: " message, __func__)
+
+// frequently used check
+#define RETURN_IF_MANAGER_IS_NULL(retval) do {\
+ if (manager == nullptr) { \
+ ERROR_INVALID_PARAMETER("manager cannot be NULL"); \
+ return retval; \
+ } \
+ } while (false)
+#define RETURN_IF_SENSOR_IS_NULL(retval) do {\
+ if (sensor == nullptr) { \
+ ERROR_INVALID_PARAMETER("sensor cannot be NULL"); \
+ return retval; \
+ } \
+ } while (false)
+
ASensorManager* ASensorManager_getInstance()
{
return ASensorManager_getInstanceForPackage(NULL);
@@ -103,6 +120,78 @@
return 0;
}
+int ASensorManager_createSharedMemoryDirectChannel(
+ ASensorManager *manager, int fd, size_t size) {
+ RETURN_IF_MANAGER_IS_NULL(android::BAD_VALUE);
+
+ if (fd < 0) {
+ ERROR_INVALID_PARAMETER("fd is invalid.");
+ return android::BAD_VALUE;
+ }
+
+ if (size < sizeof(ASensorEvent)) {
+ ERROR_INVALID_PARAMETER("size has to be greater or equal to sizeof(ASensorEvent).");
+ }
+
+ native_handle_t *resourceHandle = native_handle_create(1 /* nFd */, 0 /* nInt */);
+ if (!resourceHandle) {
+ return android::NO_MEMORY;
+ }
+
+ resourceHandle->data[0] = fd;
+ int ret = static_cast<SensorManager *>(manager)->createDirectChannel(
+ size, ASENSOR_DIRECT_CHANNEL_TYPE_SHARED_MEMORY, resourceHandle);
+ native_handle_delete(resourceHandle);
+ return ret;
+}
+
+int ASensorManager_createHardwareBufferDirectChannel(
+ ASensorManager *manager, AHardwareBuffer const *buffer, size_t size) {
+ RETURN_IF_MANAGER_IS_NULL(android::BAD_VALUE);
+
+ if (buffer == nullptr) {
+ ERROR_INVALID_PARAMETER("buffer cannot be NULL");
+ return android::BAD_VALUE;
+ }
+
+ if (size < sizeof(ASensorEvent)) {
+ ERROR_INVALID_PARAMETER("size has to be greater or equal to sizeof(ASensorEvent).");
+ }
+
+ const native_handle_t *resourceHandle = AHardwareBuffer_getNativeHandle(buffer);
+ if (!resourceHandle) {
+ return android::NO_MEMORY;
+ }
+
+ return static_cast<SensorManager *>(manager)->createDirectChannel(
+ size, ASENSOR_DIRECT_CHANNEL_TYPE_HARDWARE_BUFFER, resourceHandle);
+}
+
+void ASensorManager_destroyDirectChannel(ASensorManager *manager, int channelId) {
+ RETURN_IF_MANAGER_IS_NULL(void());
+
+ static_cast<SensorManager *>(manager)->destroyDirectChannel(channelId);
+}
+
+int ASensorManager_configureDirectReport(
+ ASensorManager *manager, ASensor const *sensor, int channelId, int rate) {
+ RETURN_IF_MANAGER_IS_NULL(android::BAD_VALUE);
+
+ int sensorHandle;
+ if (sensor == nullptr) {
+ if (rate != ASENSOR_DIRECT_RATE_STOP) {
+ ERROR_INVALID_PARAMETER(
+ "sensor cannot be null when rate is not ASENSOR_DIRECT_RATE_STOP");
+ return android::BAD_VALUE;
+ }
+ sensorHandle = -1;
+ } else {
+ sensorHandle = static_cast<Sensor const *>(sensor)->getHandle();
+ }
+ return static_cast<SensorManager *>(manager)->configureDirectChannel(
+ channelId, sensorHandle, rate);
+}
+
/*****************************************************************************/
int ASensorEventQueue_registerSensor(ASensorEventQueue* queue, ASensor const* sensor,
@@ -211,3 +300,13 @@
{
return static_cast<Sensor const*>(sensor)->isWakeUpSensor();
}
+
+bool ASensor_isDirectChannelTypeSupported(ASensor const *sensor, int channelType) {
+ RETURN_IF_SENSOR_IS_NULL(false);
+ return static_cast<Sensor const *>(sensor)->isDirectChannelTypeSupported(channelType);
+}
+
+int ASensor_getHighestDirectReportRateLevel(ASensor const *sensor) {
+ RETURN_IF_SENSOR_IS_NULL(ASENSOR_DIRECT_RATE_STOP);
+ return static_cast<Sensor const *>(sensor)->getHighestDirectReportRateLevel();
+}
diff --git a/native/android/sharedmem.cpp b/native/android/sharedmem.cpp
new file mode 100644
index 0000000..9d029dfa
--- /dev/null
+++ b/native/android/sharedmem.cpp
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2017 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 <android/sharedmem.h>
+#include <cutils/ashmem.h>
+#include <utils/Errors.h>
+
+int ASharedMemory_create(const char *name, size_t size) {
+ if (size == 0) {
+ return android::BAD_VALUE;
+ }
+ return ashmem_create_region(name, size);
+}
+
+size_t ASharedMemory_getSize(int fd) {
+ return ashmem_valid(fd) ? ashmem_get_size_region(fd) : 0;
+}
+
+int ASharedMemory_setProt(int fd, int prot) {
+ return ashmem_set_prot_region(fd, prot);
+}
diff --git a/packages/CarrierDefaultApp/AndroidManifest.xml b/packages/CarrierDefaultApp/AndroidManifest.xml
index e2080b0..d910920 100644
--- a/packages/CarrierDefaultApp/AndroidManifest.xml
+++ b/packages/CarrierDefaultApp/AndroidManifest.xml
@@ -31,7 +31,7 @@
<application android:label="@string/app_name" >
<receiver android:name="com.android.carrierdefaultapp.CarrierDefaultBroadcastReceiver">
<intent-filter>
- <action android:name="android.intent.action.CARRIER_SIGNAL_REDIRECTED" />
+ <action android:name="com.android.internal.telephony.CARRIER_SIGNAL_REDIRECTED" />
</intent-filter>
</receiver>
<activity android:name="com.android.carrierdefaultapp.CaptivePortalLaunchActivity"
diff --git a/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java b/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
index 22a5b7f..3cc9f65e 100644
--- a/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
+++ b/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
@@ -56,6 +56,7 @@
import android.webkit.MimeTypeMap;
import com.android.internal.annotations.GuardedBy;
+import com.android.internal.content.FileSystemProvider;
import com.android.internal.util.IndentingPrintWriter;
import java.io.File;
@@ -63,15 +64,15 @@
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.PrintWriter;
+import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.Objects;
-public class ExternalStorageProvider extends DocumentsProvider {
+public class ExternalStorageProvider extends FileSystemProvider {
private static final String TAG = "ExternalStorage";
private static final boolean DEBUG = false;
- private static final boolean LOG_INOTIFY = false;
public static final String AUTHORITY = "com.android.externalstorage.documents";
@@ -105,20 +106,17 @@
private static final String ROOT_ID_HOME = "home";
private StorageManager mStorageManager;
- private Handler mHandler;
private final Object mRootsLock = new Object();
@GuardedBy("mRootsLock")
private ArrayMap<String, RootInfo> mRoots = new ArrayMap<>();
- @GuardedBy("mObservers")
- private ArrayMap<File, DirectoryObserver> mObservers = new ArrayMap<>();
-
@Override
public boolean onCreate() {
+ super.onCreate(DEFAULT_DOCUMENT_PROJECTION);
+
mStorageManager = (StorageManager) getContext().getSystemService(Context.STORAGE_SERVICE);
- mHandler = new Handler();
updateVolumes();
return true;
@@ -274,11 +272,8 @@
return projection != null ? projection : DEFAULT_ROOT_PROJECTION;
}
- private static String[] resolveDocumentProjection(String[] projection) {
- return projection != null ? projection : DEFAULT_DOCUMENT_PROJECTION;
- }
-
- private String getDocIdForFile(File file) throws FileNotFoundException {
+ @Override
+ protected String getDocIdForFile(File file) throws FileNotFoundException {
return getDocIdForFileMaybeCreate(file, false);
}
@@ -344,11 +339,8 @@
return mostSpecificRoot;
}
- private File getFileForDocId(String docId) throws FileNotFoundException {
- return getFileForDocId(docId, false);
- }
-
- private File getFileForDocId(String docId, boolean visible) throws FileNotFoundException {
+ @Override
+ protected File getFileForDocId(String docId, boolean visible) throws FileNotFoundException {
RootInfo root = getRootFromDocId(docId);
return buildFile(root, docId, visible);
}
@@ -393,48 +385,9 @@
return target;
}
- private void includeFile(MatrixCursor result, String docId, File file)
- throws FileNotFoundException {
- if (docId == null) {
- docId = getDocIdForFile(file);
- } else {
- file = getFileForDocId(docId);
- }
-
- int flags = 0;
-
- if (file.canWrite()) {
- if (file.isDirectory()) {
- flags |= Document.FLAG_DIR_SUPPORTS_CREATE;
- flags |= Document.FLAG_SUPPORTS_DELETE;
- flags |= Document.FLAG_SUPPORTS_RENAME;
- flags |= Document.FLAG_SUPPORTS_MOVE;
- } else {
- flags |= Document.FLAG_SUPPORTS_WRITE;
- flags |= Document.FLAG_SUPPORTS_DELETE;
- flags |= Document.FLAG_SUPPORTS_RENAME;
- flags |= Document.FLAG_SUPPORTS_MOVE;
- }
- }
-
- final String mimeType = getTypeForFile(file);
- final String displayName = file.getName();
- if (mimeType.startsWith("image/")) {
- flags |= Document.FLAG_SUPPORTS_THUMBNAIL;
- }
-
- final RowBuilder row = result.newRow();
- row.add(Document.COLUMN_DOCUMENT_ID, docId);
- row.add(Document.COLUMN_DISPLAY_NAME, displayName);
- row.add(Document.COLUMN_SIZE, file.length());
- row.add(Document.COLUMN_MIME_TYPE, mimeType);
- row.add(Document.COLUMN_FLAGS, flags);
-
- // Only publish dates reasonably after epoch
- long lastModified = file.lastModified();
- if (lastModified > 31536000000L) {
- row.add(Document.COLUMN_LAST_MODIFIED, lastModified);
- }
+ @Override
+ protected Uri buildNotificationUri(String docId) {
+ return DocumentsContract.buildChildDocumentsUri(AUTHORITY, docId);
}
@Override
@@ -455,22 +408,8 @@
}
@Override
- public boolean isChildDocument(String parentDocId, String docId) {
- try {
- final File parent = getFileForDocId(parentDocId).getCanonicalFile();
- final File doc = getFileForDocId(docId).getCanonicalFile();
- return FileUtils.contains(parent, doc);
- } catch (IOException e) {
- throw new IllegalArgumentException(
- "Failed to determine if " + docId + " is child of " + parentDocId + ": " + e);
- }
- }
-
- @Override
public Path findDocumentPath(String childDocId, @Nullable String parentDocId)
throws FileNotFoundException {
- LinkedList<String> path = new LinkedList<>();
-
final Pair<RootInfo, File> resolvedDocId = resolveDocId(childDocId, false);
final RootInfo root = resolvedDocId.first;
File child = resolvedDocId.second;
@@ -479,49 +418,7 @@
? root.path
: getFileForDocId(parentDocId);
- if (!child.exists()) {
- throw new FileNotFoundException(childDocId + " is not found.");
- }
-
- if (!child.getAbsolutePath().startsWith(parent.getAbsolutePath())) {
- throw new FileNotFoundException(childDocId + " is not found under " + parentDocId);
- }
-
- while (child != null && child.getAbsolutePath().startsWith(parent.getAbsolutePath())) {
- path.addFirst(getDocIdForFile(child));
-
- child = child.getParentFile();
- }
-
- return new Path(parentDocId == null ? root.rootId : null, path);
- }
-
- @Override
- public String createDocument(String docId, String mimeType, String displayName)
- throws FileNotFoundException {
- displayName = FileUtils.buildValidFatFilename(displayName);
-
- final File parent = getFileForDocId(docId);
- if (!parent.isDirectory()) {
- throw new IllegalArgumentException("Parent document isn't a directory");
- }
-
- final File file = FileUtils.buildUniqueFile(parent, mimeType, displayName);
- if (Document.MIME_TYPE_DIR.equals(mimeType)) {
- if (!file.mkdir()) {
- throw new IllegalStateException("Failed to mkdir " + file);
- }
- } else {
- try {
- if (!file.createNewFile()) {
- throw new IllegalStateException("Failed to touch " + file);
- }
- } catch (IOException e) {
- throw new IllegalStateException("Failed to touch " + file + ": " + e);
- }
- }
-
- return getDocIdForFile(file);
+ return new Path(parentDocId == null ? root.rootId : null, findDocumentPath(parent, child));
}
private Uri getDocumentUri(String path, List<UriPermission> accessUriPermissions)
@@ -587,120 +484,14 @@
}
@Override
- public String renameDocument(String docId, String displayName) throws FileNotFoundException {
- // Since this provider treats renames as generating a completely new
- // docId, we're okay with letting the MIME type change.
- displayName = FileUtils.buildValidFatFilename(displayName);
-
- final File before = getFileForDocId(docId);
- final File after = FileUtils.buildUniqueFile(before.getParentFile(), displayName);
- if (!before.renameTo(after)) {
- throw new IllegalStateException("Failed to rename to " + after);
- }
- final String afterDocId = getDocIdForFile(after);
- if (!TextUtils.equals(docId, afterDocId)) {
- return afterDocId;
- } else {
- return null;
- }
- }
-
- @Override
- public void deleteDocument(String docId) throws FileNotFoundException {
- final File file = getFileForDocId(docId);
- final File visibleFile = getFileForDocId(docId, true);
-
- final boolean isDirectory = file.isDirectory();
- if (isDirectory) {
- FileUtils.deleteContents(file);
- }
- if (!file.delete()) {
- throw new IllegalStateException("Failed to delete " + file);
- }
-
- if (visibleFile != null) {
- final ContentResolver resolver = getContext().getContentResolver();
- final Uri externalUri = MediaStore.Files.getContentUri("external");
-
- // Remove media store entries for any files inside this directory, using
- // path prefix match. Logic borrowed from MtpDatabase.
- if (isDirectory) {
- final String path = visibleFile.getAbsolutePath() + "/";
- resolver.delete(externalUri,
- "_data LIKE ?1 AND lower(substr(_data,1,?2))=lower(?3)",
- new String[] { path + "%", Integer.toString(path.length()), path });
- }
-
- // Remove media store entry for this exact file.
- final String path = visibleFile.getAbsolutePath();
- resolver.delete(externalUri,
- "_data LIKE ?1 AND lower(_data)=lower(?2)",
- new String[] { path, path });
- }
- }
-
- @Override
- public String moveDocument(String sourceDocumentId, String sourceParentDocumentId,
- String targetParentDocumentId)
- throws FileNotFoundException {
- final File before = getFileForDocId(sourceDocumentId);
- final File after = new File(getFileForDocId(targetParentDocumentId), before.getName());
-
- if (after.exists()) {
- throw new IllegalStateException("Already exists " + after);
- }
- if (!before.renameTo(after)) {
- throw new IllegalStateException("Failed to move to " + after);
- }
- return getDocIdForFile(after);
- }
-
- @Override
- public Cursor queryDocument(String documentId, String[] projection)
- throws FileNotFoundException {
- final MatrixCursor result = new MatrixCursor(resolveDocumentProjection(projection));
- includeFile(result, documentId, null);
- return result;
- }
-
- @Override
- public Cursor queryChildDocuments(
- String parentDocumentId, String[] projection, String sortOrder)
- throws FileNotFoundException {
- final File parent = getFileForDocId(parentDocumentId);
- final MatrixCursor result = new DirectoryCursor(
- resolveDocumentProjection(projection), parentDocumentId, parent);
- for (File file : parent.listFiles()) {
- includeFile(result, null, file);
- }
- return result;
- }
-
- @Override
public Cursor querySearchDocuments(String rootId, String query, String[] projection)
throws FileNotFoundException {
- final MatrixCursor result = new MatrixCursor(resolveDocumentProjection(projection));
-
- query = query.toLowerCase();
final File parent;
synchronized (mRootsLock) {
parent = mRoots.get(rootId).path;
}
- final LinkedList<File> pending = new LinkedList<>();
- pending.add(parent);
- while (!pending.isEmpty() && result.getCount() < 24) {
- final File file = pending.removeFirst();
- if (file.isDirectory()) {
- for (File child : file.listFiles()) {
- pending.add(child);
- }
- }
- if (file.getName().toLowerCase().contains(query)) {
- includeFile(result, null, file);
- }
- }
- return result;
+ return querySearchDocuments(parent, query, projection, Collections.emptySet());
}
@Override
@@ -722,48 +513,6 @@
}
@Override
- public String getDocumentType(String documentId) throws FileNotFoundException {
- final File file = getFileForDocId(documentId);
- return getTypeForFile(file);
- }
-
- @Override
- public ParcelFileDescriptor openDocument(
- String documentId, String mode, CancellationSignal signal)
- throws FileNotFoundException {
- final File file = getFileForDocId(documentId);
- final File visibleFile = getFileForDocId(documentId, true);
-
- final int pfdMode = ParcelFileDescriptor.parseMode(mode);
- if (pfdMode == ParcelFileDescriptor.MODE_READ_ONLY || visibleFile == null) {
- return ParcelFileDescriptor.open(file, pfdMode);
- } else {
- try {
- // When finished writing, kick off media scanner
- return ParcelFileDescriptor.open(file, pfdMode, mHandler, new OnCloseListener() {
- @Override
- public void onClose(IOException e) {
- final Intent intent = new Intent(
- Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
- intent.setData(Uri.fromFile(visibleFile));
- getContext().sendBroadcast(intent);
- }
- });
- } catch (IOException e) {
- throw new FileNotFoundException("Failed to open for writing: " + e);
- }
- }
- }
-
- @Override
- public AssetFileDescriptor openDocumentThumbnail(
- String documentId, Point sizeHint, CancellationSignal signal)
- throws FileNotFoundException {
- final File file = getFileForDocId(documentId);
- return DocumentsContract.openImageThumbnail(file);
- }
-
- @Override
public void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
final IndentingPrintWriter pw = new IndentingPrintWriter(writer, " ", 160);
synchronized (mRootsLock) {
@@ -826,107 +575,4 @@
}
return bundle;
}
-
- private static String getTypeForFile(File file) {
- if (file.isDirectory()) {
- return Document.MIME_TYPE_DIR;
- } else {
- return getTypeForName(file.getName());
- }
- }
-
- private static String getTypeForName(String name) {
- final int lastDot = name.lastIndexOf('.');
- if (lastDot >= 0) {
- final String extension = name.substring(lastDot + 1).toLowerCase();
- final String mime = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension);
- if (mime != null) {
- return mime;
- }
- }
-
- return "application/octet-stream";
- }
-
- private void startObserving(File file, Uri notifyUri) {
- synchronized (mObservers) {
- DirectoryObserver observer = mObservers.get(file);
- if (observer == null) {
- observer = new DirectoryObserver(
- file, getContext().getContentResolver(), notifyUri);
- observer.startWatching();
- mObservers.put(file, observer);
- }
- observer.mRefCount++;
-
- if (LOG_INOTIFY) Log.d(TAG, "after start: " + observer);
- }
- }
-
- private void stopObserving(File file) {
- synchronized (mObservers) {
- DirectoryObserver observer = mObservers.get(file);
- if (observer == null) return;
-
- observer.mRefCount--;
- if (observer.mRefCount == 0) {
- mObservers.remove(file);
- observer.stopWatching();
- }
-
- if (LOG_INOTIFY) Log.d(TAG, "after stop: " + observer);
- }
- }
-
- private static class DirectoryObserver extends FileObserver {
- private static final int NOTIFY_EVENTS = ATTRIB | CLOSE_WRITE | MOVED_FROM | MOVED_TO
- | CREATE | DELETE | DELETE_SELF | MOVE_SELF;
-
- private final File mFile;
- private final ContentResolver mResolver;
- private final Uri mNotifyUri;
-
- private int mRefCount = 0;
-
- public DirectoryObserver(File file, ContentResolver resolver, Uri notifyUri) {
- super(file.getAbsolutePath(), NOTIFY_EVENTS);
- mFile = file;
- mResolver = resolver;
- mNotifyUri = notifyUri;
- }
-
- @Override
- public void onEvent(int event, String path) {
- if ((event & NOTIFY_EVENTS) != 0) {
- if (LOG_INOTIFY) Log.d(TAG, "onEvent() " + event + " at " + path);
- mResolver.notifyChange(mNotifyUri, null, false);
- }
- }
-
- @Override
- public String toString() {
- return "DirectoryObserver{file=" + mFile.getAbsolutePath() + ", ref=" + mRefCount + "}";
- }
- }
-
- private class DirectoryCursor extends MatrixCursor {
- private final File mFile;
-
- public DirectoryCursor(String[] columnNames, String docId, File file) {
- super(columnNames);
-
- final Uri notifyUri = DocumentsContract.buildChildDocumentsUri(
- AUTHORITY, docId);
- setNotificationUri(getContext().getContentResolver(), notifyUri);
-
- mFile = file;
- startObserving(mFile, notifyUri);
- }
-
- @Override
- public void close() {
- super.close();
- stopObserving(mFile);
- }
- }
}
diff --git a/packages/PrintSpooler/res/values-hi/strings.xml b/packages/PrintSpooler/res/values-hi/strings.xml
index f36167e..36465a1 100644
--- a/packages/PrintSpooler/res/values-hi/strings.xml
+++ b/packages/PrintSpooler/res/values-hi/strings.xml
@@ -79,7 +79,7 @@
</plurals>
<string name="printing_notification_title_template" msgid="295903957762447362">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> प्रिंट हो रहा है"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> रद्द हो रहा है"</string>
- <string name="failed_notification_title_template" msgid="2256217208186530973">"प्रिंटर त्रुटि <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
+ <string name="failed_notification_title_template" msgid="2256217208186530973">"प्रिंटर गड़बड़ी <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="blocked_notification_title_template" msgid="1175435827331588646">"प्रिंटर अवरोधित <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="cancel" msgid="4373674107267141885">"अभी नहीं"</string>
<string name="restart" msgid="2472034227037808749">"पुन: आरंभ करें"</string>
diff --git a/packages/SettingsLib/res/layout/drawer_category.xml b/packages/SettingsLib/res/layout/drawer_category.xml
deleted file mode 100644
index 72cfddb..0000000
--- a/packages/SettingsLib/res/layout/drawer_category.xml
+++ /dev/null
@@ -1,38 +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.
--->
-<LinearLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:paddingTop="8dp"
- android:orientation="vertical">
-
- <View
- android:layout_width="match_parent"
- android:layout_height="1dp"
- android:background="?android:attr/listDivider" />
-
- <TextView
- style="@style/TextAppearanceSmall"
- android:id="@android:id/title"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:minHeight="48dp"
- android:paddingTop="16dp"
- android:paddingBottom="16dp"
- android:paddingStart="16dp" />
-
-</LinearLayout>
diff --git a/packages/SettingsLib/res/layout/drawer_item.xml b/packages/SettingsLib/res/layout/drawer_item.xml
deleted file mode 100644
index d492ddf..0000000
--- a/packages/SettingsLib/res/layout/drawer_item.xml
+++ /dev/null
@@ -1,44 +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.
--->
-<LinearLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/tile_item"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:minHeight="48dp"
- android:orientation="horizontal" >
-
- <ImageView
- android:id="@android:id/icon"
- android:layout_width="@dimen/drawer_icon_size"
- android:layout_height="@dimen/drawer_icon_size"
- android:layout_marginStart="@dimen/drawer_icon_margin"
- android:layout_marginEnd="@dimen/drawer_icon_margin"
- android:layout_marginTop="@dimen/drawer_item_top_bottom_margin"
- android:layout_marginBottom="@dimen/drawer_item_top_bottom_margin"
- android:scaleType="fitCenter"
- android:layout_gravity="center_vertical"
- android:tint="?android:attr/colorAccent"/>
-
- <TextView
- android:textAppearance="@style/TextAppearanceMedium"
- android:id="@android:id/title"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center_vertical"
- android:textColor="?android:attr/colorControlNormal" />
-
-</LinearLayout>
diff --git a/packages/SettingsLib/res/layout/drawer_spacer.xml b/packages/SettingsLib/res/layout/drawer_spacer.xml
deleted file mode 100644
index 98120cf..0000000
--- a/packages/SettingsLib/res/layout/drawer_spacer.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<!--
- Copyright (C) 2016 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<Space
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/spacer"
- android:layout_width="match_parent"
- android:layout_height="@dimen/drawer_spacer_height" />
diff --git a/packages/SettingsLib/res/layout/settings_with_drawer.xml b/packages/SettingsLib/res/layout/settings_with_drawer.xml
index b659cee..e9c175f 100644
--- a/packages/SettingsLib/res/layout/settings_with_drawer.xml
+++ b/packages/SettingsLib/res/layout/settings_with_drawer.xml
@@ -47,13 +47,4 @@
android:layout_height="fill_parent"
android:background="?android:attr/windowBackground" />
</LinearLayout>
- <!-- The navigation drawer -->
- <ListView android:id="@+id/left_drawer"
- android:layout_width="@dimen/drawer_width"
- android:layout_height="match_parent"
- android:layout_gravity="start"
- android:choiceMode="singleChoice"
- android:divider="@android:color/transparent"
- android:dividerHeight="0dp"
- android:background="?android:attr/colorBackground" />
</android.support.v4.widget.DrawerLayout>
diff --git a/packages/SettingsLib/res/values/arrays.xml b/packages/SettingsLib/res/values/arrays.xml
index d207c35..9ff22c7 100644
--- a/packages/SettingsLib/res/values/arrays.xml
+++ b/packages/SettingsLib/res/values/arrays.xml
@@ -538,7 +538,7 @@
<item>100</item>
</array>
<array name="batterymeter_color_values">
- <item>@*android:color/battery_saver_mode_color</item>
+ <item>?android:attr/colorError</item>
<item>@android:color/white</item>
</array>
<array name="batterymeter_bolt_points">
diff --git a/packages/SettingsLib/res/values/config.xml b/packages/SettingsLib/res/values/config.xml
index ee69b56..64f21b5 100755
--- a/packages/SettingsLib/res/values/config.xml
+++ b/packages/SettingsLib/res/values/config.xml
@@ -26,9 +26,6 @@
<!-- Whether to send a custom package name with the PSD.-->
<bool name="config_sendPackageName">false</bool>
- <!-- Whether to enable the left nav drawer in all Settings UI.-->
- <bool name="config_enable_nav_drawer">false</bool>
-
<!-- Name for the set of keys associating package names -->
<string name="config_helpPackageNameKey" translatable="false"></string>
diff --git a/packages/SettingsLib/res/values/dimens.xml b/packages/SettingsLib/res/values/dimens.xml
index aa36617..3322839 100644
--- a/packages/SettingsLib/res/values/dimens.xml
+++ b/packages/SettingsLib/res/values/dimens.xml
@@ -51,12 +51,6 @@
<dimen name="usage_graph_dot_size">.75dp</dimen>
<dimen name="usage_graph_dot_interval">7dp</dimen>
- <dimen name="drawer_icon_size">24dp</dimen>
- <dimen name="normal_icon_size">24dp</dimen>
- <dimen name="drawer_icon_margin">24dp</dimen>
- <dimen name="drawer_width">300dp</dimen>
- <dimen name="drawer_item_top_bottom_margin">4dp</dimen>
- <dimen name="drawer_spacer_height">32dp</dimen>
<dimen name="battery_height">14.5dp</dimen>
<dimen name="battery_width">9.5dp</dimen>
diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml
index 961d0e5..f77d466 100644
--- a/packages/SettingsLib/res/values/strings.xml
+++ b/packages/SettingsLib/res/values/strings.xml
@@ -537,6 +537,11 @@
<string name="wait_for_debugger_summary">Debugged application waits for debugger to
attach before executing</string>
+ <!-- UI debug setting: title for Telephonymonitor switch [CHAR LIMIT=50] -->
+ <string name="telephony_monitor_switch">Telephony Monitor</string>
+ <!-- UI debug setting: summary for switch of Telephonymonitor [CHAR LIMIT=500] -->
+ <string name="telephony_monitor_switch_summary">TelephonyMonitor will collect logs when it detects a problem with telephony/modem functionality and prompt notification to user to file a bug</string>
+
<!-- Preference category for input debugging development settings. [CHAR LIMIT=25] -->
<string name="debug_input_category">Input</string>
diff --git a/packages/SettingsLib/src/com/android/settingslib/RestrictedLockUtils.java b/packages/SettingsLib/src/com/android/settingslib/RestrictedLockUtils.java
index 99d7f1e..49fc2ea 100644
--- a/packages/SettingsLib/src/com/android/settingslib/RestrictedLockUtils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/RestrictedLockUtils.java
@@ -16,6 +16,11 @@
package com.android.settingslib;
+import static android.app.admin.DevicePolicyManager.KEYGUARD_DISABLE_FEATURES_NONE;
+import static android.app.admin.DevicePolicyManager.PROFILE_KEYGUARD_FEATURES_AFFECT_OWNER;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.annotation.UserIdInt;
import android.app.AppGlobals;
import android.app.admin.DevicePolicyManager;
@@ -29,6 +34,7 @@
import android.os.UserHandle;
import android.os.UserManager;
import android.provider.Settings;
+import android.support.annotation.VisibleForTesting;
import android.text.Spanned;
import android.text.SpannableStringBuilder;
import android.text.style.ForegroundColorSpan;
@@ -108,47 +114,68 @@
}
/**
- * Checks if keyguard features are disabled by policy.
+ * Checks whether keyguard features are disabled by policy.
*
- * @param keyguardFeatures Could be any of keyguard features that can be
+ * @param context {@link Context} for the calling user.
+ *
+ * @param keyguardFeatures Any one of keyguard features that can be
* disabled by {@link android.app.admin.DevicePolicyManager#setKeyguardDisabledFeatures}.
+ *
+ * @param userId User to check enforced admin status for.
+ *
* @return EnforcedAdmin Object containing the enforced admin component and admin user details,
* or {@code null} If the notification features are not disabled. If the restriction is set by
* multiple admins, then the admin component will be set to {@code null} and userId to
* {@link UserHandle#USER_NULL}.
*/
public static EnforcedAdmin checkIfKeyguardFeaturesDisabled(Context context,
- int keyguardFeatures, int userId) {
- final LockSettingCheck check =
- (DevicePolicyManager dpm, ComponentName admin, @UserIdInt int checkUser) ->
- (dpm.getKeyguardDisabledFeatures(admin, checkUser) & keyguardFeatures) != 0;
+ int keyguardFeatures, final @UserIdInt int userId) {
+ final LockSettingCheck check = (dpm, admin, checkUser) -> {
+ int effectiveFeatures = dpm.getKeyguardDisabledFeatures(admin, checkUser);
+ if (checkUser != userId) {
+ effectiveFeatures &= PROFILE_KEYGUARD_FEATURES_AFFECT_OWNER;
+ }
+ return (effectiveFeatures & keyguardFeatures) != KEYGUARD_DISABLE_FEATURES_NONE;
+ };
+ if (UserManager.get(context).getUserInfo(userId).isManagedProfile()) {
+ DevicePolicyManager dpm =
+ (DevicePolicyManager) context.getSystemService(Context.DEVICE_POLICY_SERVICE);
+ return findEnforcedAdmin(dpm.getActiveAdminsAsUser(userId), dpm, userId, check);
+ }
+ return checkForLockSetting(context, userId, check);
+ }
- final DevicePolicyManager dpm = (DevicePolicyManager) context.getSystemService(
- Context.DEVICE_POLICY_SERVICE);
- if (dpm == null) {
+ /**
+ * Filter a set of device admins based on a predicate {@code check}. This is equivalent to
+ * {@code admins.stream().filter(check).map(x → new EnforcedAdmin(admin, userId)} except it's
+ * returning a zero/one/many-type thing.
+ *
+ * @param admins set of candidate device admins identified by {@link ComponentName}.
+ * @param userId user to create the resultant {@link EnforcedAdmin} as.
+ * @param check filter predicate.
+ *
+ * @return {@code null} if none of the {@param admins} match.
+ * An {@link EnforcedAdmin} if exactly one of the admins matches.
+ * Otherwise, {@link EnforcedAdmin#MULTIPLE_ENFORCED_ADMIN} for multiple matches.
+ */
+ @Nullable
+ private static EnforcedAdmin findEnforcedAdmin(@Nullable List<ComponentName> admins,
+ @NonNull DevicePolicyManager dpm, @UserIdInt int userId,
+ @NonNull LockSettingCheck check) {
+ if (admins == null) {
return null;
}
-
- final UserManager um = (UserManager) context.getSystemService(Context.USER_SERVICE);
- if (um.getUserInfo(userId).isManagedProfile()) {
- final List<ComponentName> admins = dpm.getActiveAdminsAsUser(userId);
- if (admins == null) {
- return null;
- }
- EnforcedAdmin enforcedAdmin = null;
- for (ComponentName admin : admins) {
- if (check.isEnforcing(dpm, admin, userId)) {
- if (enforcedAdmin == null) {
- enforcedAdmin = new EnforcedAdmin(admin, userId);
- } else {
- return EnforcedAdmin.MULTIPLE_ENFORCED_ADMIN;
- }
+ EnforcedAdmin enforcedAdmin = null;
+ for (ComponentName admin : admins) {
+ if (check.isEnforcing(dpm, admin, userId)) {
+ if (enforcedAdmin == null) {
+ enforcedAdmin = new EnforcedAdmin(admin, userId);
+ } else {
+ return EnforcedAdmin.MULTIPLE_ENFORCED_ADMIN;
}
}
- return enforcedAdmin;
- } else {
- return checkForLockSetting(context, userId, check);
}
+ return enforcedAdmin;
}
public static EnforcedAdmin checkIfUninstallBlocked(Context context,
@@ -361,7 +388,7 @@
}
LockPatternUtils lockPatternUtils = new LockPatternUtils(context);
- if (lockPatternUtils.isSeparateProfileChallengeEnabled(userId)) {
+ if (sProxy.isSeparateProfileChallengeEnabled(lockPatternUtils, userId)) {
// userId is managed profile and has a separate challenge, only consider
// the admins in that user.
final List<ComponentName> admins = dpm.getActiveAdminsAsUser(userId);
@@ -428,7 +455,7 @@
if (userInfo.isManagedProfile()) {
// If userInfo.id is a managed profile, we also need to look at
// the policies set on the parent.
- final DevicePolicyManager parentDpm = dpm.getParentProfileInstance(userInfo);
+ DevicePolicyManager parentDpm = sProxy.getParentProfileInstance(dpm, userInfo);
if (parentDpm.getMaximumTimeToLock(admin, userInfo.id) > 0) {
if (enforcedAdmin == null) {
enforcedAdmin = new EnforcedAdmin(admin, userInfo.id);
@@ -448,8 +475,9 @@
/**
* Checks whether any of the user's profiles enforce the lock setting. A managed profile is only
- * included if it does not have a separate challenege but the settings for it's parent (i.e. the
- * user being checked) are always included.
+ * included if it does not have a separate challenge.
+ *
+ * The user identified by {@param userId} is always included.
*/
private static EnforcedAdmin checkForLockSetting(
Context context, @UserIdInt int userId, LockSettingCheck check) {
@@ -468,7 +496,7 @@
continue;
}
final boolean isSeparateProfileChallengeEnabled =
- lockPatternUtils.isSeparateProfileChallengeEnabled(userInfo.id);
+ sProxy.isSeparateProfileChallengeEnabled(lockPatternUtils, userInfo.id);
for (ComponentName admin : admins) {
if (!isSeparateProfileChallengeEnabled) {
if (check.isEnforcing(dpm, admin, userInfo.id)) {
@@ -487,7 +515,7 @@
if (userInfo.isManagedProfile()) {
// If userInfo.id is a managed profile, we also need to look at
// the policies set on the parent.
- final DevicePolicyManager parentDpm = dpm.getParentProfileInstance(userInfo);
+ DevicePolicyManager parentDpm = sProxy.getParentProfileInstance(dpm, userInfo);
if (check.isEnforcing(parentDpm, admin, userInfo.id)) {
if (enforcedAdmin == null) {
enforcedAdmin = new EnforcedAdmin(admin, userInfo.id);
@@ -733,4 +761,23 @@
other.userId = userId;
}
}
+
+ /**
+ * Static {@link LockPatternUtils} and {@link DevicePolicyManager} wrapper for testing purposes.
+ * {@link LockPatternUtils} is an internal API not supported by robolectric.
+ * {@link DevicePolicyManager} has a {@code getProfileParent} not yet suppored by robolectric.
+ */
+ @VisibleForTesting
+ static Proxy sProxy = new Proxy();
+
+ @VisibleForTesting
+ static class Proxy {
+ public boolean isSeparateProfileChallengeEnabled(LockPatternUtils utils, int userHandle) {
+ return utils.isSeparateProfileChallengeEnabled(userHandle);
+ }
+
+ public DevicePolicyManager getParentProfileInstance(DevicePolicyManager dpm, UserInfo ui) {
+ return dpm.getParentProfileInstance(ui);
+ }
+ }
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/Utils.java b/packages/SettingsLib/src/com/android/settingslib/Utils.java
index 7a4514a..7e7b391 100644
--- a/packages/SettingsLib/src/com/android/settingslib/Utils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/Utils.java
@@ -184,10 +184,7 @@
@ColorInt
public static int getColorError(Context context) {
- TypedArray ta = context.obtainStyledAttributes(new int[]{android.R.attr.textColorError});
- @ColorInt int colorError = ta.getColor(0, 0);
- ta.recycle();
- return colorError;
+ return getColorAttr(context, android.R.attr.colorError);
}
@ColorInt
diff --git a/packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerActivity.java b/packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerActivity.java
index a8cab17..457ce76 100644
--- a/packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerActivity.java
+++ b/packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerActivity.java
@@ -5,7 +5,7 @@
* 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
+ * 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,
@@ -18,7 +18,6 @@
import android.annotation.LayoutRes;
import android.annotation.Nullable;
import android.app.Activity;
-import android.content.ActivityNotFoundException;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
@@ -29,20 +28,15 @@
import android.os.AsyncTask;
import android.os.Bundle;
import android.provider.Settings;
-import android.support.v4.widget.DrawerLayout;
import android.util.ArraySet;
import android.util.Log;
import android.util.Pair;
-import android.view.Gravity;
import android.view.LayoutInflater;
-import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.view.WindowManager.LayoutParams;
-import android.widget.AdapterView;
import android.widget.FrameLayout;
-import android.widget.ListView;
import android.widget.Toolbar;
import com.android.settingslib.R;
@@ -67,10 +61,7 @@
private final PackageReceiver mPackageReceiver = new PackageReceiver();
private final List<CategoryListener> mCategoryListeners = new ArrayList<>();
- private SettingsDrawerAdapter mDrawerAdapter;
private FrameLayout mContentHeaderContainer;
- private DrawerLayout mDrawerLayout;
- private boolean mShowingMenu;
// Remove below after new IA
@Deprecated
@@ -94,122 +85,50 @@
}
super.setContentView(R.layout.settings_with_drawer);
mContentHeaderContainer = (FrameLayout) findViewById(R.id.content_header_container);
- mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
- if (mDrawerLayout == null) {
- return;
- }
+
Toolbar toolbar = (Toolbar) findViewById(R.id.action_bar);
if (theme.getBoolean(android.R.styleable.Theme_windowNoTitle, false)) {
toolbar.setVisibility(View.GONE);
- mDrawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED);
- mDrawerLayout = null;
return;
}
- if (!isNavDrawerEnabled()) {
- setIsDrawerPresent(false);
- }
- if (!isDashboardFeatureEnabled()) {
- getDashboardCategories();
- }
setActionBar(toolbar);
- mDrawerAdapter = new SettingsDrawerAdapter(this);
- ListView listView = (ListView) findViewById(R.id.left_drawer);
- listView.setAdapter(mDrawerAdapter);
- listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
- public void onItemClick(android.widget.AdapterView<?> parent, View view, int position,
- long id) {
- onTileClicked(mDrawerAdapter.getTile(position));
- }
- });
- if (DEBUG_TIMING) Log.d(TAG, "onCreate took " + (System.currentTimeMillis() - startTime)
- + " ms");
- }
-
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
- if (mShowingMenu && mDrawerLayout != null && item.getItemId() == android.R.id.home
- && mDrawerAdapter.getCount() != 0) {
- openDrawer();
- return true;
+ if (DEBUG_TIMING) {
+ Log.d(TAG, "onCreate took " + (System.currentTimeMillis() - startTime)
+ + " ms");
}
- return super.onOptionsItemSelected(item);
}
@Override
public boolean onNavigateUp() {
- if (!isNavDrawerEnabled()) {
- finish();
- return true;
- }
- return super.onNavigateUp();
+ finish();
+ return true;
}
@Override
protected void onResume() {
super.onResume();
+ final IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_ADDED);
+ filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
+ filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
+ filter.addAction(Intent.ACTION_PACKAGE_REPLACED);
+ filter.addDataScheme("package");
+ registerReceiver(mPackageReceiver, filter);
- if (mDrawerLayout != null) {
- final IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_ADDED);
- filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
- filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
- filter.addAction(Intent.ACTION_PACKAGE_REPLACED);
- filter.addDataScheme("package");
- registerReceiver(mPackageReceiver, filter);
-
- if (isDashboardFeatureEnabled()) {
- new CategoriesUpdateTask().execute();
- } else {
- new CategoriesUpdater().execute();
- }
- }
+ new CategoriesUpdateTask().execute();
final Intent intent = getIntent();
- if (intent != null) {
- if (intent.hasExtra(EXTRA_SHOW_MENU)) {
- if (intent.getBooleanExtra(EXTRA_SHOW_MENU, false)) {
- // Intent explicitly set to show menu.
- showMenuIcon();
- }
- } else if (isNavDrawerEnabled() && isTopLevelTile(intent)) {
- showMenuIcon();
- }
+ if (intent != null && intent.getBooleanExtra(EXTRA_SHOW_MENU, false)) {
+ // Intent explicitly set to show menu.
+ showMenuIcon();
}
}
@Override
protected void onPause() {
- if (mDrawerLayout != null) {
- unregisterReceiver(mPackageReceiver);
- }
-
+ unregisterReceiver(mPackageReceiver);
super.onPause();
}
- private boolean isTopLevelTile(Intent intent) {
- final ComponentName componentName = intent.getComponent();
- if (componentName == null) {
- return false;
- }
- if (isDashboardFeatureEnabled()) {
- final DashboardCategory homepageCategories = CategoryManager.get(this)
- .getTilesByCategory(this, CategoryKey.CATEGORY_HOMEPAGE, getSettingPkg());
- return homepageCategories ==
- null ? false : homepageCategories.containsComponent(componentName);
- } else {
- // Look for a tile that has the same component as incoming intent
- final List<DashboardCategory> categories = getDashboardCategories();
- for (DashboardCategory category : categories) {
- if (category.containsComponent(componentName)) {
- return true;
- }
- }
- if (DEBUG) {
- Log.d(TAG, "Intent is not for top level settings " + intent);
- }
- return false;
- }
- }
-
/**
* Gets the name of the intent action of the default setting app. Used to launch setting app
* when Settings Home is clicked.
@@ -226,30 +145,6 @@
mCategoryListeners.remove(listener);
}
- public void setIsDrawerPresent(boolean isPresent) {
- if (isPresent) {
- mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
- updateDrawer();
- } else {
- if (mDrawerLayout != null) {
- mDrawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED);
- mDrawerLayout = null;
- }
- }
- }
-
- public void openDrawer() {
- if (mDrawerLayout != null) {
- mDrawerLayout.openDrawer(Gravity.START);
- }
- }
-
- public void closeDrawer() {
- if (mDrawerLayout != null) {
- mDrawerLayout.closeDrawers();
- }
- }
-
public void setContentHeaderView(View headerView) {
mContentHeaderContainer.removeAllViews();
if (headerView != null) {
@@ -276,31 +171,8 @@
((ViewGroup) findViewById(R.id.content_frame)).addView(view, params);
}
- public void updateDrawer() {
- if (mDrawerLayout == null) {
- return;
- }
- // TODO: Do this in the background with some loading.
- if (isDashboardFeatureEnabled()) {
- mDrawerAdapter.updateHomepageCategories(getSettingPkg());
- } else {
- mDrawerAdapter.updateCategories();
- }
- if (mDrawerAdapter.getCount() != 0) {
- mDrawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED);
- } else {
- mDrawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED);
- }
- }
-
public void showMenuIcon() {
getActionBar().setDisplayHomeAsUpEnabled(true);
- if (isNavDrawerEnabled()) {
- mShowingMenu = true;
- getActionBar().setHomeAsUpIndicator(R.drawable.ic_menu);
- getActionBar().setHomeActionContentDescription(
- R.string.content_description_menu_button);
- }
}
public List<DashboardCategory> getDashboardCategories() {
@@ -315,51 +187,12 @@
}
protected void onCategoriesChanged() {
- updateDrawer();
final int N = mCategoryListeners.size();
for (int i = 0; i < N; i++) {
mCategoryListeners.get(i).onCategoriesChanged();
}
}
- @Deprecated
- public boolean openTile(Tile tile) {
- closeDrawer();
- if (tile == null) {
- Intent intent = new Intent(getSettingAction()).addFlags(
- Intent.FLAG_ACTIVITY_CLEAR_TASK);
- startActivity(intent);
- return true;
- }
- try {
- ProfileSelectDialog.updateUserHandlesIfNeeded(this /* context */, tile);
- int numUserHandles = tile.userHandle.size();
- if (numUserHandles > 1) {
- ProfileSelectDialog.show(getFragmentManager(), tile);
- return false;
- } else if (numUserHandles == 1) {
- // Show menu on top level items.
- tile.intent.putExtra(EXTRA_SHOW_MENU, true);
- tile.intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
- startActivityAsUser(tile.intent, tile.userHandle.get(0));
- } else {
- // Show menu on top level items.
- tile.intent.putExtra(EXTRA_SHOW_MENU, true);
- tile.intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
- startActivity(tile.intent);
- }
- } catch (ActivityNotFoundException e) {
- Log.w(TAG, "Couldn't find tile " + tile.intent, e);
- }
- return true;
- }
-
- protected void onTileClicked(Tile tile) {
- if (openTile(tile)) {
- finish();
- }
- }
-
public void onProfileTileOpen() {
finish();
}
@@ -375,8 +208,8 @@
sTileBlacklist.add(component);
}
pm.setComponentEnabledSetting(component, enabled
- ? PackageManager.COMPONENT_ENABLED_STATE_ENABLED
- : PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
+ ? PackageManager.COMPONENT_ENABLED_STATE_ENABLED
+ : PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
PackageManager.DONT_KILL_APP);
}
}
@@ -385,11 +218,7 @@
* Updates dashboard categories. Only necessary to call this after setTileEnabled
*/
public void updateCategories() {
- if (isDashboardFeatureEnabled()) {
- new CategoriesUpdateTask().execute();
- } else {
- new CategoriesUpdater().execute();
- }
+ new CategoriesUpdateTask().execute();
}
public String getSettingPkg() {
@@ -400,42 +229,6 @@
void onCategoriesChanged();
}
- /**
- * @deprecated remove after new IA
- */
- @Deprecated
- private class CategoriesUpdater extends AsyncTask<Void, Void, List<DashboardCategory>> {
- @Override
- protected List<DashboardCategory> doInBackground(Void... params) {
- if (sConfigTracker.applyNewConfig(getResources())) {
- sTileCache.clear();
- }
- return TileUtils.getCategories(SettingsDrawerActivity.this, sTileCache);
- }
-
- @Override
- protected void onPreExecute() {
- if (sConfigTracker == null || sTileCache == null) {
- getDashboardCategories();
- }
- }
-
- @Override
- protected void onPostExecute(List<DashboardCategory> dashboardCategories) {
- for (int i = 0; i < dashboardCategories.size(); i++) {
- DashboardCategory category = dashboardCategories.get(i);
- for (int j = 0; j < category.tiles.size(); j++) {
- Tile tile = category.tiles.get(j);
- if (sTileBlacklist.contains(tile.intent.getComponent())) {
- category.tiles.remove(j--);
- }
- }
- }
- sDashboardCategories = dashboardCategories;
- onCategoriesChanged();
- }
- }
-
private class CategoriesUpdateTask extends AsyncTask<Void, Void, Void> {
private final CategoryManager mCategoryManager;
@@ -457,25 +250,10 @@
}
}
- /**
- * @return {@code true} if IA (Information Architecture) is enabled.
- */
- protected boolean isDashboardFeatureEnabled() {
- return false;
- }
-
- boolean isNavDrawerEnabled() {
- return getResources().getBoolean(R.bool.config_enable_nav_drawer);
- }
-
private class PackageReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
- if (isDashboardFeatureEnabled()) {
- new CategoriesUpdateTask().execute();
- } else {
- new CategoriesUpdater().execute();
- }
+ new CategoriesUpdateTask().execute();
}
}
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerAdapter.java b/packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerAdapter.java
deleted file mode 100644
index 75942f9..0000000
--- a/packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerAdapter.java
+++ /dev/null
@@ -1,147 +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.settingslib.drawer;
-
-import android.graphics.drawable.Icon;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.BaseAdapter;
-import android.widget.ImageView;
-import android.widget.TextView;
-
-import com.android.settingslib.R;
-
-import java.util.ArrayList;
-import java.util.List;
-
-public class SettingsDrawerAdapter extends BaseAdapter {
-
- private final ArrayList<Item> mItems = new ArrayList<>();
- private final SettingsDrawerActivity mActivity;
-
- public SettingsDrawerAdapter(SettingsDrawerActivity activity) {
- mActivity = activity;
- }
-
- /**
- * @deprecated Remove after new IA
- */
- @Deprecated
- void updateCategories() {
- List<DashboardCategory> categories = mActivity.getDashboardCategories();
- mItems.clear();
- // Spacer.
- mItems.add(null);
- Item tile = new Item();
- tile.label = mActivity.getString(R.string.home);
- tile.icon = Icon.createWithResource(mActivity, R.drawable.home);
- mItems.add(tile);
- for (int i = 0; i < categories.size(); i++) {
- Item category = new Item();
- category.icon = null;
- DashboardCategory dashboardCategory = categories.get(i);
- category.label = dashboardCategory.title;
- mItems.add(category);
- for (int j = 0; j < dashboardCategory.tiles.size(); j++) {
- tile = new Item();
- Tile dashboardTile = dashboardCategory.tiles.get(j);
- tile.label = dashboardTile.title;
- tile.icon = dashboardTile.icon;
- tile.tile = dashboardTile;
- mItems.add(tile);
- }
- }
- notifyDataSetChanged();
- }
-
- public void updateHomepageCategories(String settingPkg) {
- final DashboardCategory category = CategoryManager.get(mActivity)
- .getTilesByCategory(mActivity, CategoryKey.CATEGORY_HOMEPAGE, settingPkg);
- mItems.clear();
- // Spacer.
- mItems.add(null);
- Item tile = new Item();
- tile.label = mActivity.getString(R.string.home);
- tile.icon = Icon.createWithResource(mActivity, R.drawable.home);
- mItems.add(tile);
- for (int j = 0; j < category.tiles.size(); j++) {
- tile = new Item();
- Tile dashboardTile = category.tiles.get(j);
- tile.label = dashboardTile.title;
- tile.icon = dashboardTile.icon;
- tile.tile = dashboardTile;
- mItems.add(tile);
- }
- notifyDataSetChanged();
- }
-
- public Tile getTile(int position) {
- return mItems.get(position) != null ? mItems.get(position).tile : null;
- }
-
- @Override
- public int getCount() {
- return mItems.size();
- }
-
- @Override
- public Object getItem(int position) {
- return mItems.get(position);
- }
-
- @Override
- public long getItemId(int position) {
- return position;
- }
-
- @Override
- public boolean isEnabled(int position) {
- return mItems.get(position) != null && mItems.get(position).icon != null;
- }
-
- @Override
- public View getView(int position, View convertView, ViewGroup parent) {
- Item item = mItems.get(position);
- if (item == null) {
- if (convertView == null || convertView.getId() != R.id.spacer) {
- convertView = LayoutInflater.from(mActivity).inflate(R.layout.drawer_spacer,
- parent, false);
- }
- return convertView;
- }
- if (convertView != null && convertView.getId() == R.id.spacer) {
- convertView = null;
- }
- boolean isTile = item.icon != null;
- if (convertView == null || (isTile != (convertView.getId() == R.id.tile_item))) {
- convertView = LayoutInflater.from(mActivity).inflate(isTile ? R.layout.drawer_item
- : R.layout.drawer_category,
- parent, false);
- }
- if (isTile) {
- ((ImageView) convertView.findViewById(android.R.id.icon)).setImageIcon(item.icon);
- }
- ((TextView) convertView.findViewById(android.R.id.title)).setText(item.label);
- return convertView;
- }
-
- private static class Item {
- public Icon icon;
- public CharSequence label;
- public Tile tile;
- }
-}
diff --git a/packages/SettingsLib/src/com/android/settingslib/drawer/TileUtils.java b/packages/SettingsLib/src/com/android/settingslib/drawer/TileUtils.java
index 6e10aab..f31c09b 100644
--- a/packages/SettingsLib/src/com/android/settingslib/drawer/TileUtils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/drawer/TileUtils.java
@@ -33,7 +33,6 @@
import android.os.UserManager;
import android.provider.Settings.Global;
import android.text.TextUtils;
-import android.util.ArrayMap;
import android.util.Log;
import android.util.Pair;
@@ -353,10 +352,7 @@
CharSequence title = null;
String summary = null;
String keyHint = null;
- String uriString = null;
Uri uri = null;
- // Several resources can be using the same provider. Only acquire a single provider.
- Map<String, IContentProvider> providerMap = new ArrayMap<>();
// Get the activity's meta-data
try {
@@ -365,11 +361,7 @@
Bundle metaData = activityInfo.metaData;
if (res != null && metaData != null) {
- if (metaData.containsKey(META_DATA_PREFERENCE_ICON_URI)) {
- iconFromUri = getIconFromUri(context, activityInfo.packageName,
- metaData.getString(META_DATA_PREFERENCE_ICON_URI), providerMap);
- }
- if (iconFromUri == null && metaData.containsKey(META_DATA_PREFERENCE_ICON)) {
+ if (metaData.containsKey(META_DATA_PREFERENCE_ICON)) {
icon = metaData.getInt(META_DATA_PREFERENCE_ICON);
}
if (metaData.containsKey(META_DATA_PREFERENCE_TITLE)) {
@@ -379,13 +371,7 @@
title = metaData.getString(META_DATA_PREFERENCE_TITLE);
}
}
- if (metaData.containsKey(META_DATA_PREFERENCE_SUMMARY_URI)) {
- summary = getTextFromUri(context,
- metaData.getString(META_DATA_PREFERENCE_SUMMARY_URI), providerMap,
- META_DATA_PREFERENCE_SUMMARY);
- }
- if (TextUtils.isEmpty(summary)
- && metaData.containsKey(META_DATA_PREFERENCE_SUMMARY)) {
+ if (metaData.containsKey(META_DATA_PREFERENCE_SUMMARY)) {
if (metaData.get(META_DATA_PREFERENCE_SUMMARY) instanceof Integer) {
summary = res.getString(metaData.getInt(META_DATA_PREFERENCE_SUMMARY));
} else {
diff --git a/packages/SettingsLib/src/com/android/settingslib/graph/BatteryMeterDrawableBase.java b/packages/SettingsLib/src/com/android/settingslib/graph/BatteryMeterDrawableBase.java
index fd2e7ca..6764a6b 100755
--- a/packages/SettingsLib/src/com/android/settingslib/graph/BatteryMeterDrawableBase.java
+++ b/packages/SettingsLib/src/com/android/settingslib/graph/BatteryMeterDrawableBase.java
@@ -29,7 +29,8 @@
import android.graphics.RectF;
import android.graphics.Typeface;
import android.graphics.drawable.Drawable;
-import android.provider.Settings;
+import android.util.TypedValue;
+
import com.android.settingslib.R;
import com.android.settingslib.Utils;
@@ -97,9 +98,13 @@
final int N = levels.length();
mColors = new int[2 * N];
- for (int i = 0; i < N; i++) {
+ for (int i=0; i < N; i++) {
mColors[2 * i] = levels.getInt(i, 0);
- mColors[2 * i + 1] = colors.getColor(i, 0);
+ if (colors.getType(i) == TypedValue.TYPE_ATTRIBUTE) {
+ mColors[2 * i + 1] = Utils.getColorAttr(context, colors.getResourceId(i, 0));
+ } else {
+ mColors[2 * i + 1] = colors.getColor(i, 0);
+ }
}
levels.recycle();
colors.recycle();
diff --git a/packages/SettingsLib/src/com/android/settingslib/inputmethod/InputMethodAndSubtypeUtil.java b/packages/SettingsLib/src/com/android/settingslib/inputmethod/InputMethodAndSubtypeUtil.java
index 3f6f5b5..55be137 100644
--- a/packages/SettingsLib/src/com/android/settingslib/inputmethod/InputMethodAndSubtypeUtil.java
+++ b/packages/SettingsLib/src/com/android/settingslib/inputmethod/InputMethodAndSubtypeUtil.java
@@ -396,7 +396,7 @@
.applicationInfo);
}
return LocaleHelper.toSentenceCase(
- ListFormatter.getInstance(locale).format(subtypeNames), locale);
+ ListFormatter.getInstance(locale).format((Object[]) subtypeNames), locale);
}
@NonNull
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
index 2dcbf90..6fe581e 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
@@ -89,15 +89,15 @@
new ConcurrentHashMap<String, ScanResult>(32);
private static final long MAX_SCAN_RESULT_AGE_MS = 15000;
- private static final String KEY_NETWORKINFO = "key_networkinfo";
- private static final String KEY_WIFIINFO = "key_wifiinfo";
- private static final String KEY_SCANRESULT = "key_scanresult";
- private static final String KEY_SSID = "key_ssid";
- private static final String KEY_SECURITY = "key_security";
- private static final String KEY_PSKTYPE = "key_psktype";
- private static final String KEY_SCANRESULTCACHE = "key_scanresultcache";
- private static final String KEY_CONFIG = "key_config";
- private static final AtomicInteger sLastId = new AtomicInteger(0);
+ static final String KEY_NETWORKINFO = "key_networkinfo";
+ static final String KEY_WIFIINFO = "key_wifiinfo";
+ static final String KEY_SCANRESULT = "key_scanresult";
+ static final String KEY_SSID = "key_ssid";
+ static final String KEY_SECURITY = "key_security";
+ static final String KEY_PSKTYPE = "key_psktype";
+ static final String KEY_SCANRESULTCACHE = "key_scanresultcache";
+ static final String KEY_CONFIG = "key_config";
+ static final AtomicInteger sLastId = new AtomicInteger(0);
/**
* These values are matched in string arrays -- changes must be kept in sync
@@ -114,6 +114,8 @@
public static final int SIGNAL_LEVELS = 4;
+ static final int UNREACHABLE_RSSI = Integer.MAX_VALUE;
+
private final Context mContext;
private String ssid;
@@ -125,7 +127,7 @@
private WifiConfiguration mConfig;
- private int mRssi = Integer.MAX_VALUE;
+ private int mRssi = UNREACHABLE_RSSI;
private long mSeen = 0;
private WifiInfo mInfo;
@@ -214,6 +216,21 @@
this.mRankingScore = that.mRankingScore;
}
+ /**
+ * Returns a negative integer, zero, or a positive integer if this AccessPoint is less than,
+ * equal to, or greater than the other AccessPoint.
+ *
+ * Sort order rules for AccessPoints:
+ * 1. Active before inactive
+ * 2. Reachable before unreachable
+ * 3. Saved before unsaved
+ * 4. (Internal only) Network ranking score
+ * 5. Stronger signal before weaker signal
+ * 6. SSID alphabetically
+ *
+ * Note that AccessPoints with a signal are usually also Reachable,
+ * and will thus appear before unreachable saved AccessPoints.
+ */
@Override
public int compareTo(@NonNull AccessPoint other) {
// Active one goes first.
@@ -221,18 +238,16 @@
if (!isActive() && other.isActive()) return 1;
// Reachable one goes before unreachable one.
- if (mRssi != Integer.MAX_VALUE && other.mRssi == Integer.MAX_VALUE) return -1;
- if (mRssi == Integer.MAX_VALUE && other.mRssi != Integer.MAX_VALUE) return 1;
+ if (isReachable() && !other.isReachable()) return -1;
+ if (!isReachable() && other.isReachable()) return 1;
// Configured (saved) one goes before unconfigured one.
- if (networkId != WifiConfiguration.INVALID_NETWORK_ID
- && other.networkId == WifiConfiguration.INVALID_NETWORK_ID) return -1;
- if (networkId == WifiConfiguration.INVALID_NETWORK_ID
- && other.networkId != WifiConfiguration.INVALID_NETWORK_ID) return 1;
+ if (isSaved() && !other.isSaved()) return -1;
+ if (!isSaved() && other.isSaved()) return 1;
// Higher scores go before lower scores
- if (mRankingScore != other.mRankingScore) {
- return (mRankingScore > other.mRankingScore) ? -1 : 1;
+ if (getRankingScore() != other.getRankingScore()) {
+ return (getRankingScore() > other.getRankingScore()) ? -1 : 1;
}
// Sort by signal strength, bucketed by level
@@ -242,7 +257,7 @@
return difference;
}
// Sort by ssid.
- return ssid.compareToIgnoreCase(other.ssid);
+ return getSsidStr().compareToIgnoreCase(other.getSsidStr());
}
@Override
@@ -265,6 +280,9 @@
public String toString() {
StringBuilder builder = new StringBuilder().append("AccessPoint(")
.append(ssid);
+ if (bssid != null) {
+ builder.append(":").append(bssid);
+ }
if (isSaved()) {
builder.append(',').append("saved");
}
@@ -280,6 +298,7 @@
if (security != SECURITY_NONE) {
builder.append(',').append(securityToString(security, pskType));
}
+ builder.append(",level=").append(getLevel());
builder.append(",rankingScore=").append(mRankingScore);
builder.append(",badge=").append(mBadge);
@@ -351,7 +370,7 @@
}
public int getLevel() {
- if (mRssi == Integer.MAX_VALUE) {
+ if (!isReachable()) {
return -1;
}
return WifiManager.calculateSignalLevel(mRssi, SIGNAL_LEVELS);
@@ -527,7 +546,7 @@
}
} else if (config != null && config.getNetworkSelectionStatus().isNotRecommended()) {
summary.append(mContext.getString(R.string.wifi_disabled_by_recommendation_provider));
- } else if (mRssi == Integer.MAX_VALUE) { // Wifi out of range
+ } else if (!isReachable()) { // Wifi out of range
summary.append(mContext.getString(R.string.wifi_not_in_range));
} else { // In range, not disabled.
if (config != null) { // Is saved network
@@ -870,6 +889,11 @@
return mBadge;
}
+ /** Return true if the current RSSI is reachable, and false otherwise. */
+ boolean isReachable() {
+ return mRssi != UNREACHABLE_RSSI;
+ }
+
public static String getSummary(Context context, String ssid, DetailedState state,
boolean isEphemeral, String passpointProvider) {
if (state == DetailedState.CONNECTED && ssid == null) {
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
index 11bcdca..8421c2c 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
@@ -271,7 +271,6 @@
if (mWifiManager.isWifiEnabled()) {
mScanner.resume();
}
- mWorkHandler.sendEmptyMessage(WorkHandler.MSG_UPDATE_ACCESS_POINTS);
}
/**
@@ -715,9 +714,9 @@
mMainHandler.sendEmptyMessage(MainHandler.MSG_CONNECTED_CHANGED);
- mWorkHandler.sendEmptyMessage(WorkHandler.MSG_UPDATE_ACCESS_POINTS);
mWorkHandler.obtainMessage(WorkHandler.MSG_UPDATE_NETWORK_INFO, info)
.sendToTarget();
+ mWorkHandler.sendEmptyMessage(WorkHandler.MSG_UPDATE_ACCESS_POINTS);
}
}
};
diff --git a/packages/SettingsLib/tests/integ/src/com/android/settingslib/drawer/SettingsDrawerActivityTest.java b/packages/SettingsLib/tests/integ/src/com/android/settingslib/drawer/SettingsDrawerActivityTest.java
index c3f2f73..752b5b0 100644
--- a/packages/SettingsLib/tests/integ/src/com/android/settingslib/drawer/SettingsDrawerActivityTest.java
+++ b/packages/SettingsLib/tests/integ/src/com/android/settingslib/drawer/SettingsDrawerActivityTest.java
@@ -86,16 +86,6 @@
.check(matches(isDisplayed()));
}
- @Test
- public void startActivity_shouldNotHaveNavDrawer() {
- Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
- Activity activity = instrumentation.startActivitySync(
- new Intent(instrumentation.getTargetContext(), TestActivity.class));
-
- assertThat(((SettingsDrawerActivity) activity).isNavDrawerEnabled())
- .isFalse();
- }
-
/**
* Test Activity in this test.
*
diff --git a/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/AccessPointTest.java b/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/AccessPointTest.java
index 6481f4d..ec0190c 100644
--- a/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/AccessPointTest.java
+++ b/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/AccessPointTest.java
@@ -15,9 +15,8 @@
*/
package com.android.settingslib.wifi;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertSame;
-import static org.junit.Assert.assertTrue;
+import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth.assertWithMessage;
import android.content.Context;
import android.net.ConnectivityManager;
@@ -39,6 +38,7 @@
import org.junit.runner.RunWith;
import java.util.ArrayList;
+import java.util.Collections;
@SmallTest
@RunWith(AndroidJUnit4.class)
@@ -59,12 +59,12 @@
final AccessPoint ap = new AccessPoint(InstrumentationRegistry.getTargetContext(), bundle);
final CharSequence ssid = ap.getSsid();
- assertTrue(ssid instanceof SpannableString);
+ assertThat(ssid instanceof SpannableString).isTrue();
TtsSpan[] spans = ((SpannableString) ssid).getSpans(0, TEST_SSID.length(), TtsSpan.class);
- assertEquals(1, spans.length);
- assertEquals(TtsSpan.TYPE_TELEPHONE, spans[0].getType());
+ assertThat(spans.length).isEqualTo(1);
+ assertThat(spans[0].getType()).isEqualTo(TtsSpan.TYPE_TELEPHONE);
}
@Test
@@ -80,11 +80,11 @@
originalAccessPoint.update(configuration, wifiInfo, networkInfo);
AccessPoint copy = new AccessPoint(mContext, originalAccessPoint);
- assertEquals(originalAccessPoint.getSsid().toString(), copy.getSsid().toString());
- assertEquals(originalAccessPoint.getBssid(), copy.getBssid());
- assertSame(originalAccessPoint.getConfig(), copy.getConfig());
- assertEquals(originalAccessPoint.getSecurity(), copy.getSecurity());
- assertTrue(originalAccessPoint.compareTo(copy) == 0);
+ assertThat(originalAccessPoint.getSsid().toString()).isEqualTo(copy.getSsid().toString());
+ assertThat(originalAccessPoint.getBssid()).isEqualTo(copy.getBssid());
+ assertThat(originalAccessPoint.getConfig()).isEqualTo(copy.getConfig());
+ assertThat(originalAccessPoint.getSecurity()).isEqualTo(copy.getSecurity());
+ assertThat(originalAccessPoint.compareTo(copy) == 0).isTrue();
}
@Test
@@ -101,11 +101,93 @@
bundle.putParcelableArrayList("key_scanresultcache", scanResults);
AccessPoint original = new AccessPoint(mContext, bundle);
- assertEquals(4, original.getRssi());
+ assertThat(original.getRssi()).isEqualTo(4);
AccessPoint copy = new AccessPoint(mContext, createWifiConfiguration());
- assertEquals(Integer.MIN_VALUE, copy.getRssi());
+ assertThat(copy.getRssi()).isEqualTo(Integer.MIN_VALUE);
copy.copyFrom(original);
- assertEquals(original.getRssi(), copy.getRssi());
+ assertThat(original.getRssi()).isEqualTo(copy.getRssi());
+ }
+
+ @Test
+ public void testCompareTo_GivesActiveBeforeInactive() {
+ AccessPoint activeAp = new TestAccessPointBuilder(mContext).setActive(true).build();
+ AccessPoint inactiveAp = new TestAccessPointBuilder(mContext).setActive(false).build();
+
+ assertSortingWorks(activeAp, inactiveAp);
+ }
+
+ @Test
+ public void testCompareTo_GivesReachableBeforeUnreachable() {
+ AccessPoint nearAp = new TestAccessPointBuilder(mContext).setReachable(true).build();
+ AccessPoint farAp = new TestAccessPointBuilder(mContext).setReachable(false).build();
+
+ assertSortingWorks(nearAp, farAp);
+ }
+
+ @Test
+ public void testCompareTo_GivesSavedBeforeUnsaved() {
+ AccessPoint savedAp = new TestAccessPointBuilder(mContext).setSaved(true).build();
+ AccessPoint notSavedAp = new TestAccessPointBuilder(mContext).setSaved(false).build();
+
+ assertSortingWorks(savedAp, notSavedAp);
+ }
+
+ //TODO: add tests for mRankingScore sort order if ranking is exposed
+
+ @Test
+ public void testCompareTo_GivesHighLevelBeforeLowLevel() {
+ final int highLevel = AccessPoint.SIGNAL_LEVELS - 1;
+ final int lowLevel = 1;
+ assertThat(highLevel).isGreaterThan(lowLevel);
+
+ AccessPoint strongAp = new TestAccessPointBuilder(mContext).setLevel(highLevel).build();
+ AccessPoint weakAp = new TestAccessPointBuilder(mContext).setLevel(lowLevel).build();
+
+ assertSortingWorks(strongAp, weakAp);
+ }
+
+ @Test
+ public void testCompareTo_GivesSsidAlphabetically() {
+
+ final String firstName = "AAAAAA";
+ final String secondName = "zzzzzz";
+
+ AccessPoint firstAp = new TestAccessPointBuilder(mContext).setSsid(firstName).build();
+ AccessPoint secondAp = new TestAccessPointBuilder(mContext).setSsid(secondName).build();
+
+ assertThat(firstAp.getSsidStr().compareToIgnoreCase(secondAp.getSsidStr()) < 0).isTrue();
+ assertSortingWorks(firstAp, secondAp);
+ }
+
+ @Test
+ public void testCompareTo_AllSortingRulesCombined() {
+
+ AccessPoint active = new TestAccessPointBuilder(mContext).setActive(true).build();
+ AccessPoint reachableAndMinLevel = new TestAccessPointBuilder(mContext)
+ .setReachable(true).build();
+ AccessPoint saved = new TestAccessPointBuilder(mContext).setSaved(true).build();
+ AccessPoint highLevelAndReachable = new TestAccessPointBuilder(mContext)
+ .setLevel(AccessPoint.SIGNAL_LEVELS - 1).build();
+ AccessPoint firstName = new TestAccessPointBuilder(mContext).setSsid("a").build();
+ AccessPoint lastname = new TestAccessPointBuilder(mContext).setSsid("z").build();
+
+ ArrayList<AccessPoint> points = new ArrayList<AccessPoint>();
+ points.add(lastname);
+ points.add(firstName);
+ points.add(highLevelAndReachable);
+ points.add(saved);
+ points.add(reachableAndMinLevel);
+ points.add(active);
+
+ Collections.sort(points);
+ assertThat(points.indexOf(active)).isLessThan(points.indexOf(reachableAndMinLevel));
+ assertThat(points.indexOf(reachableAndMinLevel)).isLessThan(points.indexOf(saved));
+ // note: the saved AP will not appear before highLevelAndReachable,
+ // because all APs with a signal level are reachable,
+ // and isReachable() takes higher sorting precedence than isSaved().
+ assertThat(points.indexOf(saved)).isLessThan(points.indexOf(firstName));
+ assertThat(points.indexOf(highLevelAndReachable)).isLessThan(points.indexOf(firstName));
+ assertThat(points.indexOf(firstName)).isLessThan(points.indexOf(lastname));
}
private WifiConfiguration createWifiConfiguration() {
@@ -115,4 +197,85 @@
configuration.networkId = 123;
return configuration;
}
+
+ /**
+ * Assert that the first AccessPoint appears after the second AccessPoint
+ * once sorting has been completed.
+ */
+ private void assertSortingWorks(AccessPoint first, AccessPoint second) {
+
+ ArrayList<AccessPoint> points = new ArrayList<AccessPoint>();
+
+ // add in reverse order so we can tell that sorting actually changed something
+ points.add(second);
+ points.add(first);
+ Collections.sort(points);
+ assertWithMessage(
+ String.format("After sorting: second AccessPoint should have higher array index "
+ + "than the first, but found indicies second '%s' and first '%s'.",
+ points.indexOf(second), points.indexOf(first)))
+ .that(points.indexOf(second)).isGreaterThan(points.indexOf(first));
+ }
+
+ @Test
+ public void testBuilder_setActive() {
+ AccessPoint activeAp = new TestAccessPointBuilder(mContext).setActive(true).build();
+ assertThat(activeAp.isActive()).isTrue();
+
+ AccessPoint inactiveAp = new TestAccessPointBuilder(mContext).setActive(false).build();
+ assertThat(inactiveAp.isActive()).isFalse();
+ }
+
+ @Test
+ public void testBuilder_setReachable() {
+ AccessPoint nearAp = new TestAccessPointBuilder(mContext).setReachable(true).build();
+ assertThat(nearAp.isReachable()).isTrue();
+
+ AccessPoint farAp = new TestAccessPointBuilder(mContext).setReachable(false).build();
+ assertThat(farAp.isReachable()).isFalse();
+ }
+
+ @Test
+ public void testBuilder_setSaved() {
+ AccessPoint savedAp = new TestAccessPointBuilder(mContext).setSaved(true).build();
+ assertThat(savedAp.isSaved()).isTrue();
+
+ AccessPoint newAp = new TestAccessPointBuilder(mContext).setSaved(false).build();
+ assertThat(newAp.isSaved()).isFalse();
+ }
+
+ @Test
+ public void testBuilder_setLevel() {
+ AccessPoint testAp;
+
+ for (int i = 0; i < AccessPoint.SIGNAL_LEVELS; i++) {
+ testAp = new TestAccessPointBuilder(mContext).setLevel(i).build();
+ assertThat(testAp.getLevel()).isEqualTo(i);
+ }
+
+ // numbers larger than the max level should be set to max
+ testAp = new TestAccessPointBuilder(mContext).setLevel(AccessPoint.SIGNAL_LEVELS).build();
+ assertThat(testAp.getLevel()).isEqualTo(AccessPoint.SIGNAL_LEVELS - 1);
+
+ // numbers less than 0 should give level 0
+ testAp = new TestAccessPointBuilder(mContext).setLevel(-100).build();
+ assertThat(testAp.getLevel()).isEqualTo(0);
+ }
+
+ @Test
+ public void testBuilder_settingReachableAfterLevelDoesNotAffectLevel() {
+ int level = 1;
+ assertThat(level).isLessThan(AccessPoint.SIGNAL_LEVELS - 1);
+
+ AccessPoint testAp =
+ new TestAccessPointBuilder(mContext).setLevel(level).setReachable(true).build();
+ assertThat(testAp.getLevel()).isEqualTo(level);
+ }
+
+ @Test
+ public void testBuilder_setSsid() {
+ String name = "AmazingSsid!";
+ AccessPoint namedAp = new TestAccessPointBuilder(mContext).setSsid(name).build();
+ assertThat(namedAp.getSsidStr()).isEqualTo(name);
+ }
}
diff --git a/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/TestAccessPointBuilder.java b/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/TestAccessPointBuilder.java
new file mode 100644
index 0000000..665c439
--- /dev/null
+++ b/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/TestAccessPointBuilder.java
@@ -0,0 +1,128 @@
+/*
+ * Copyright (C) 2017 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.settingslib.wifi;
+
+import android.content.Context;
+import android.net.ConnectivityManager;
+import android.net.NetworkInfo;
+import android.net.wifi.WifiConfiguration;
+import android.os.Bundle;
+
+/**
+* Build and return a valid AccessPoint.
+*
+* Only intended for testing the AccessPoint class;
+* AccessPoints were designed to only be populated
+* by the mechanisms of scan results and wifi configurations.
+*/
+public class TestAccessPointBuilder {
+ // match the private values in WifiManager
+ private static final int MIN_RSSI = -100;
+ private static final int MAX_RSSI = -55;
+
+ // set some sensible defaults
+ private int mRssi = AccessPoint.UNREACHABLE_RSSI;
+ private int networkId = WifiConfiguration.INVALID_NETWORK_ID;
+ private String ssid = "TestSsid";
+ private NetworkInfo mNetworkInfo = null;
+
+ Context mContext;
+
+ public TestAccessPointBuilder(Context context) {
+ mContext = context;
+ }
+
+ public AccessPoint build() {
+ Bundle bundle = new Bundle();
+
+ WifiConfiguration wifiConig = new WifiConfiguration();
+ wifiConig.networkId = networkId;
+
+ bundle.putString(AccessPoint.KEY_SSID, ssid);
+ bundle.putParcelable(AccessPoint.KEY_CONFIG, wifiConig);
+ bundle.putParcelable(AccessPoint.KEY_NETWORKINFO, mNetworkInfo);
+ AccessPoint ap = new AccessPoint(mContext, bundle);
+ ap.setRssi(mRssi);
+ return ap;
+ }
+
+ public TestAccessPointBuilder setActive(boolean active) {
+ if (active) {
+ mNetworkInfo = new NetworkInfo(
+ ConnectivityManager.TYPE_DUMMY,
+ ConnectivityManager.TYPE_DUMMY,
+ "TestNetwork",
+ "TestNetwork");
+ } else {
+ mNetworkInfo = null;
+ }
+ return this;
+ }
+
+ /**
+ * Set the signal level.
+ * Side effect: if this AccessPoint was previously unreachable,
+ * setting the level will also make it reachable.
+ */
+ public TestAccessPointBuilder setLevel(int level) {
+ int outputRange = AccessPoint.SIGNAL_LEVELS - 1;
+
+ if (level > outputRange) {
+ level = outputRange;
+ } else if (level < 0) {
+ level = 0;
+ }
+
+ int inputRange = MAX_RSSI - MIN_RSSI;
+
+ // calculate the rssi required to get the level we want.
+ // this is a rearrangement of the formula from WifiManager.calculateSignalLevel()
+ mRssi = (int)((float)(level * inputRange) / (float)outputRange) + MIN_RSSI;
+ return this;
+ }
+
+ /**
+ * Set whether the AccessPoint is reachable.
+ * Side effect: if the signal level was not previously set,
+ * making an AccessPoint reachable will set the signal to the minimum level.
+ */
+ public TestAccessPointBuilder setReachable(boolean reachable) {
+ if (reachable) {
+ // only override the mRssi if it hasn't been set yet
+ if (mRssi == AccessPoint.UNREACHABLE_RSSI) {
+ mRssi = MIN_RSSI;
+ }
+ } else {
+ mRssi = AccessPoint.UNREACHABLE_RSSI;
+ }
+ return this;
+ }
+
+ public TestAccessPointBuilder setSaved(boolean saved){
+ if (saved) {
+ networkId = 1;
+ } else {
+ networkId = WifiConfiguration.INVALID_NETWORK_ID;
+ }
+ return this;
+ }
+
+ public TestAccessPointBuilder setSsid(String newSsid) {
+ ssid = newSsid;
+ return this;
+ }
+}
diff --git a/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/WifiTrackerTest.java b/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/WifiTrackerTest.java
index 2018c13..e100884 100644
--- a/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/WifiTrackerTest.java
+++ b/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/WifiTrackerTest.java
@@ -15,6 +15,8 @@
*/
package com.android.settingslib.wifi;
+import static com.google.common.truth.Truth.assertThat;
+
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
@@ -28,6 +30,7 @@
import android.content.Intent;
import android.net.ConnectivityManager;
import android.net.NetworkBadging;
+import android.net.NetworkInfo;
import android.net.NetworkKey;
import android.net.NetworkScoreManager;
import android.net.ScoredNetwork;
@@ -35,6 +38,7 @@
import android.net.WifiKey;
import android.net.wifi.ScanResult;
import android.net.wifi.WifiConfiguration;
+import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
import android.net.wifi.WifiNetworkScoreCache;
import android.net.wifi.WifiSsid;
@@ -68,6 +72,8 @@
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
+// TODO(sghuman): Change these to robolectric tests b/35766684.
+
@SmallTest
@RunWith(AndroidJUnit4.class)
public class WifiTrackerTest {
@@ -115,9 +121,10 @@
@Before
public void setUp() {
- mContext = InstrumentationRegistry.getTargetContext();
MockitoAnnotations.initMocks(this);
+ mContext = InstrumentationRegistry.getTargetContext();
+
mWorkerThread = new HandlerThread("TestHandlerWorkerThread");
mWorkerThread.start();
mLooper = mWorkerThread.getLooper();
@@ -221,9 +228,15 @@
SystemClock.elapsedRealtime() * 1000 /* microsecond timestamp */);
}
- private WifiTracker createTrackerAndInjectInitialScanResults() throws InterruptedException {
+ private WifiTracker createTrackerWithImmediateBroadcastsAndInjectInitialScanResults(
+ Intent ... intents)
+ throws InterruptedException {
WifiTracker tracker = createMockedWifiTracker();
+
startTracking(tracker);
+ for (Intent intent : intents) {
+ tracker.mReceiver.onReceive(mContext, intent);
+ }
mAccessPointsChangedLatch = new CountDownLatch(1);
sendScanResultsAndProcess(tracker);
@@ -235,16 +248,16 @@
private WifiTracker createMockedWifiTracker() {
WifiTracker tracker =
new WifiTracker(
- mContext,
- mockWifiListener,
- mLooper,
- true,
- true,
- true,
- mockWifiManager,
- mockConnectivityManager,
- mockNetworkScoreManager,
- mMainLooper
+ mContext,
+ mockWifiListener,
+ mLooper,
+ true,
+ true,
+ true,
+ mockWifiManager,
+ mockConnectivityManager,
+ mockNetworkScoreManager,
+ mMainLooper
);
return tracker;
@@ -294,6 +307,31 @@
scoreCache.updateScores(Arrays.asList(sc1, sc2));
}
+ private WifiTracker createTrackerWithScanResultsAndAccessPoint1Connected()
+ throws InterruptedException {
+ int networkId = 123;
+
+ WifiInfo wifiInfo = new WifiInfo();
+ wifiInfo.setSSID(WifiSsid.createFromAsciiEncoded(SSID_1));
+ wifiInfo.setBSSID(BSSID_1);
+ wifiInfo.setNetworkId(networkId);
+ when(mockWifiManager.getConnectionInfo()).thenReturn(wifiInfo);
+
+ WifiConfiguration configuration = new WifiConfiguration();
+ configuration.SSID = SSID_1;
+ configuration.BSSID = BSSID_1;
+ configuration.networkId = networkId;
+ when(mockWifiManager.getConfiguredNetworks()).thenReturn(Arrays.asList(configuration));
+
+ NetworkInfo networkInfo = new NetworkInfo(
+ ConnectivityManager.TYPE_WIFI, 0, "Type Wifi", "subtype");
+ networkInfo.setDetailedState(NetworkInfo.DetailedState.CONNECTED, "connected", "test");
+
+ Intent intent = new Intent(WifiManager.NETWORK_STATE_CHANGED_ACTION);
+ intent.putExtra(WifiManager.EXTRA_NETWORK_INFO, networkInfo);
+ return createTrackerWithImmediateBroadcastsAndInjectInitialScanResults(intent);
+ }
+
@Test
public void testAccessPointListenerSetWhenLookingUpUsingScanResults() {
ScanResult scanResult = new ScanResult();
@@ -357,12 +395,21 @@
}
@Test
+ public void startTrackingShouldSetConnectedAccessPointAsActive() throws InterruptedException {
+ WifiTracker tracker = createTrackerWithScanResultsAndAccessPoint1Connected();
+
+ List<AccessPoint> aps = tracker.getAccessPoints();
+
+ assertThat(aps).hasSize(2);
+ assertThat(aps.get(0).isActive()).isTrue();
+ }
+
+ @Test
public void startTrackingShouldRequestScoresForCurrentAccessPoints() throws InterruptedException {
// Start the tracker and inject the initial scan results and then stop tracking
- WifiTracker tracker = createTrackerAndInjectInitialScanResults();
+ WifiTracker tracker = createTrackerWithImmediateBroadcastsAndInjectInitialScanResults();
tracker.stopTracking();
- android.util.Log.d("WifiTrackerTest", "Clearing previously captured requested keys");
mRequestedKeys.clear();
mRequestScoresLatch = new CountDownLatch(1);
@@ -370,7 +417,6 @@
assertTrue("Latch timed out",
mRequestScoresLatch.await(LATCH_TIMEOUT, TimeUnit.MILLISECONDS));
- android.util.Log.d("WifiTrackerTest", "requested keys: " + mRequestedKeys);
assertTrue(mRequestedKeys.contains(NETWORK_KEY_1));
assertTrue(mRequestedKeys.contains(NETWORK_KEY_2));
}
@@ -394,7 +440,7 @@
@Test
public void scoreCacheUpdateScoresShouldChangeSortOrder() throws InterruptedException {
- WifiTracker tracker = createTrackerAndInjectInitialScanResults();
+ WifiTracker tracker = createTrackerWithImmediateBroadcastsAndInjectInitialScanResults();
List<AccessPoint> aps = tracker.getAccessPoints();
assertTrue(aps.size() == 2);
assertEquals(aps.get(0).getSsidStr(), SSID_1);
@@ -416,7 +462,7 @@
Settings.Global.NETWORK_SCORING_UI_ENABLED,
0 /* disabled */);
- WifiTracker tracker = createTrackerAndInjectInitialScanResults();
+ WifiTracker tracker = createTrackerWithImmediateBroadcastsAndInjectInitialScanResults();
List<AccessPoint> aps = tracker.getAccessPoints();
assertTrue(aps.size() == 2);
assertEquals(aps.get(0).getSsidStr(), SSID_1);
@@ -432,7 +478,7 @@
@Test
public void scoreCacheUpdateScoresShouldInsertBadgeIntoAccessPoint() throws InterruptedException {
- WifiTracker tracker = createTrackerAndInjectInitialScanResults();
+ WifiTracker tracker = createTrackerWithImmediateBroadcastsAndInjectInitialScanResults();
updateScoresAndWaitForAccessPointsChangedCallback();
List<AccessPoint> aps = tracker.getAccessPoints();
@@ -454,7 +500,7 @@
Settings.Global.NETWORK_SCORING_UI_ENABLED,
0 /* disabled */);
- WifiTracker tracker = createTrackerAndInjectInitialScanResults();
+ WifiTracker tracker = createTrackerWithImmediateBroadcastsAndInjectInitialScanResults();
updateScoresAndWaitForAccessPointsChangedCallback();
List<AccessPoint> aps = tracker.getAccessPoints();
@@ -473,7 +519,7 @@
// Scores can be requested together or serially depending on how the scan results are
// processed.
mRequestScoresLatch = new CountDownLatch(2);
- WifiTracker tracker = createTrackerAndInjectInitialScanResults();
+ WifiTracker tracker = createTrackerWithImmediateBroadcastsAndInjectInitialScanResults();
mRequestScoresLatch.await(LATCH_TIMEOUT, TimeUnit.MILLISECONDS);
mRequestedKeys.clear();
@@ -503,7 +549,7 @@
@Test
public void scoreCacheAndListenerShouldBeUnregisteredWhenStopTrackingIsCalled() throws Exception
{
- WifiTracker tracker = createTrackerAndInjectInitialScanResults();
+ WifiTracker tracker = createTrackerWithImmediateBroadcastsAndInjectInitialScanResults();
WifiNetworkScoreCache cache = mScoreCacheCaptor.getValue();
tracker.stopTracking();
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/RestrictedLockUtilsTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/RestrictedLockUtilsTest.java
index 2958740..c506358 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/RestrictedLockUtilsTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/RestrictedLockUtilsTest.java
@@ -16,6 +16,17 @@
package com.android.settingslib;
+import static android.app.admin.DevicePolicyManager.KEYGUARD_DISABLE_FEATURES_NONE;
+import static android.app.admin.DevicePolicyManager.KEYGUARD_DISABLE_FINGERPRINT;
+import static android.app.admin.DevicePolicyManager.KEYGUARD_DISABLE_REMOTE_INPUT;
+import static android.app.admin.DevicePolicyManager.KEYGUARD_DISABLE_UNREDACTED_NOTIFICATIONS;
+import static com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
+import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.when;
+
import android.app.admin.DevicePolicyManager;
import android.content.ComponentName;
import android.content.Context;
@@ -25,18 +36,13 @@
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.Answers;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.annotation.Config;
import java.util.Arrays;
-import static android.app.admin.DevicePolicyManager.KEYGUARD_DISABLE_FINGERPRINT;
-import static android.app.admin.DevicePolicyManager.KEYGUARD_DISABLE_REMOTE_INPUT;
-import static com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
-import static com.google.common.truth.Truth.assertThat;
-import static org.mockito.Mockito.when;
-
@RunWith(SettingLibRobolectricTestRunner.class)
@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
public class RestrictedLockUtilsTest {
@@ -47,8 +53,11 @@
private DevicePolicyManager mDevicePolicyManager;
@Mock
private UserManager mUserManager;
+ @Mock(answer = Answers.RETURNS_DEEP_STUBS)
+ private RestrictedLockUtils.Proxy mProxy;
private static final int mUserId = 194;
+ private static final int mProfileId = 160;
private static final ComponentName mAdmin1 = new ComponentName("admin1", "admin1class");
private static final ComponentName mAdmin2 = new ComponentName("admin2", "admin2class");
@@ -60,12 +69,13 @@
.thenReturn(mDevicePolicyManager);
when(mContext.getSystemService(Context.USER_SERVICE))
.thenReturn(mUserManager);
+
+ RestrictedLockUtils.sProxy = mProxy;
}
@Test
public void checkIfKeyguardFeaturesDisabled_noEnforcedAdminForManagedProfile() {
- setUpManagedProfile(mUserId);
- setUpActiveAdmins(mUserId, new ComponentName[] {mAdmin1, mAdmin2});
+ setUpManagedProfile(mUserId, new ComponentName[] {mAdmin1, mAdmin2});
final EnforcedAdmin enforcedAdmin = RestrictedLockUtils.checkIfKeyguardFeaturesDisabled(
mContext, KEYGUARD_DISABLE_FINGERPRINT, mUserId);
@@ -75,8 +85,7 @@
@Test
public void checkIfKeyguardFeaturesDisabled_oneEnforcedAdminForManagedProfile() {
- setUpManagedProfile(mUserId);
- setUpActiveAdmins(mUserId, new ComponentName[] {mAdmin1, mAdmin2});
+ setUpManagedProfile(mUserId, new ComponentName[] {mAdmin1, mAdmin2});
when(mDevicePolicyManager.getKeyguardDisabledFeatures(mAdmin1, mUserId))
.thenReturn(KEYGUARD_DISABLE_FINGERPRINT);
@@ -89,8 +98,7 @@
@Test
public void checkIfKeyguardFeaturesDisabled_multipleEnforcedAdminForManagedProfile() {
- setUpManagedProfile(mUserId);
- setUpActiveAdmins(mUserId, new ComponentName[] {mAdmin1, mAdmin2});
+ setUpManagedProfile(mUserId, new ComponentName[] {mAdmin1, mAdmin2});
when(mDevicePolicyManager.getKeyguardDisabledFeatures(mAdmin1, mUserId))
.thenReturn(KEYGUARD_DISABLE_REMOTE_INPUT);
@@ -103,9 +111,129 @@
assertThat(enforcedAdmin).isEqualTo(EnforcedAdmin.MULTIPLE_ENFORCED_ADMIN);
}
- private UserInfo setUpManagedProfile(int userId) {
- final UserInfo userInfo = new UserInfo(userId, "myuser", UserInfo.FLAG_MANAGED_PROFILE);
+ @Test
+ public void checkIfKeyguardFeaturesAreDisabled_doesMatchAllowedFeature_unifiedManagedProfile() {
+ UserInfo userInfo = setUpUser(mUserId, new ComponentName[] {mAdmin1});
+ UserInfo profileInfo = setUpManagedProfile(mProfileId, new ComponentName[] {mAdmin2});
+ when(mUserManager.getProfiles(mUserId)).thenReturn(Arrays.asList(new UserInfo[] {
+ userInfo, profileInfo}));
+
+ when(mDevicePolicyManager.getKeyguardDisabledFeatures(mAdmin1, mUserId))
+ .thenReturn(KEYGUARD_DISABLE_FEATURES_NONE);
+ when(mDevicePolicyManager.getKeyguardDisabledFeatures(mAdmin2, mProfileId))
+ .thenReturn(KEYGUARD_DISABLE_FINGERPRINT);
+
+ // Querying the parent should return the policy, since it affects the parent.
+ EnforcedAdmin parent = RestrictedLockUtils.checkIfKeyguardFeaturesDisabled(
+ mContext, KEYGUARD_DISABLE_FINGERPRINT, mUserId);
+ assertThat(parent).isEqualTo(new EnforcedAdmin(mAdmin2, mProfileId));
+
+ // Querying the child should return that too.
+ EnforcedAdmin profile = RestrictedLockUtils.checkIfKeyguardFeaturesDisabled(
+ mContext, KEYGUARD_DISABLE_FINGERPRINT, mProfileId);
+ assertThat(profile).isEqualTo(new EnforcedAdmin(mAdmin2, mProfileId));
+
+ // Querying for some unrelated feature should return nothing. Nothing!
+ assertThat(RestrictedLockUtils.checkIfKeyguardFeaturesDisabled(
+ mContext, KEYGUARD_DISABLE_REMOTE_INPUT, mUserId)).isNull();
+ assertThat(RestrictedLockUtils.checkIfKeyguardFeaturesDisabled(
+ mContext, KEYGUARD_DISABLE_REMOTE_INPUT, mProfileId)).isNull();
+ }
+
+ @Test
+ public void checkIfKeyguardFeaturesAreDisabled_notMatchOtherFeatures_unifiedManagedProfile() {
+ UserInfo userInfo = setUpUser(mUserId, new ComponentName[] {mAdmin1});
+ UserInfo profileInfo = setUpManagedProfile(mProfileId, new ComponentName[] {mAdmin2});
+ when(mUserManager.getProfiles(mUserId)).thenReturn(Arrays.asList(new UserInfo[] {
+ userInfo, profileInfo}));
+
+ when(mDevicePolicyManager.getKeyguardDisabledFeatures(mAdmin1, mUserId))
+ .thenReturn(KEYGUARD_DISABLE_FEATURES_NONE);
+ when(mDevicePolicyManager.getKeyguardDisabledFeatures(mAdmin2, mProfileId))
+ .thenReturn(KEYGUARD_DISABLE_UNREDACTED_NOTIFICATIONS);
+
+ // Querying the parent should not return the policy, because it's not a policy that should
+ // affect parents even when the lock screen is unified.
+ EnforcedAdmin primary = RestrictedLockUtils.checkIfKeyguardFeaturesDisabled(
+ mContext, KEYGUARD_DISABLE_UNREDACTED_NOTIFICATIONS, mUserId);
+ assertThat(primary).isNull();
+
+ // Querying the child should still return the policy.
+ EnforcedAdmin profile = RestrictedLockUtils.checkIfKeyguardFeaturesDisabled(
+ mContext, KEYGUARD_DISABLE_UNREDACTED_NOTIFICATIONS, mProfileId);
+ assertThat(profile).isEqualTo(new EnforcedAdmin(mAdmin2, mProfileId));
+ }
+
+ @Test
+ public void checkIfKeyguardFeaturesAreDisabled_onlyMatchesProfile_separateManagedProfile() {
+ UserInfo userInfo = setUpUser(mUserId, new ComponentName[] {mAdmin1});
+ UserInfo profileInfo = setUpManagedProfile(mProfileId, new ComponentName[] {mAdmin2});
+ when(mUserManager.getProfiles(mUserId)).thenReturn(Arrays.asList(new UserInfo[] {
+ userInfo, profileInfo}));
+
+ when(mDevicePolicyManager.getKeyguardDisabledFeatures(mAdmin1, mUserId))
+ .thenReturn(KEYGUARD_DISABLE_FEATURES_NONE);
+ when(mDevicePolicyManager.getKeyguardDisabledFeatures(mAdmin2, mProfileId))
+ .thenReturn(KEYGUARD_DISABLE_FINGERPRINT);
+
+ // Crucially for this test, isSeparateWorkChallengeEnabled => true.
+ doReturn(true).when(mProxy).isSeparateProfileChallengeEnabled(any(), eq(mProfileId));
+
+ // Querying the parent should not return the policy, even though it's shared by default,
+ // because the parent doesn't share a lock screen with the profile any more.
+ EnforcedAdmin parent = RestrictedLockUtils.checkIfKeyguardFeaturesDisabled(
+ mContext, KEYGUARD_DISABLE_FINGERPRINT, mUserId);
+ assertThat(parent).isNull();
+
+ // Querying the child should still return the policy.
+ EnforcedAdmin profile = RestrictedLockUtils.checkIfKeyguardFeaturesDisabled(
+ mContext, KEYGUARD_DISABLE_FINGERPRINT, mProfileId);
+ assertThat(profile).isEqualTo(new EnforcedAdmin(mAdmin2, mProfileId));
+ }
+
+ /**
+ * This test works great. The real world implementation is sketchy though.
+ * <p>
+ * DevicePolicyManager.getParentProfileInstance(UserInfo) does not do what it looks like it does
+ * (which would be to get an instance for the parent of the user that's passed in to it.)
+ * <p>
+ * Instead it just always returns a parent instance for the current user.
+ * <p>
+ * Still, the test works.
+ */
+ @Test
+ public void checkIfKeyguardFeaturesAreDisabled_onlyMatchesParent_profileParentPolicy() {
+ UserInfo userInfo = setUpUser(mUserId, new ComponentName[] {mAdmin1});
+ UserInfo profileInfo = setUpManagedProfile(mProfileId, new ComponentName[] {mAdmin2});
+ when(mUserManager.getProfiles(mUserId)).thenReturn(Arrays.asList(new UserInfo[] {
+ userInfo, profileInfo}));
+
+ when(mProxy.getParentProfileInstance(any(DevicePolicyManager.class), any())
+ .getKeyguardDisabledFeatures(mAdmin2, mProfileId))
+ .thenReturn(KEYGUARD_DISABLE_FINGERPRINT);
+
+ // Parent should get the policy.
+ EnforcedAdmin parent = RestrictedLockUtils.checkIfKeyguardFeaturesDisabled(
+ mContext, KEYGUARD_DISABLE_FINGERPRINT, mUserId);
+ assertThat(parent).isEqualTo(new EnforcedAdmin(mAdmin2, mProfileId));
+
+ // Profile should not get the policy.
+ EnforcedAdmin profile = RestrictedLockUtils.checkIfKeyguardFeaturesDisabled(
+ mContext, KEYGUARD_DISABLE_FINGERPRINT, mProfileId);
+ assertThat(profile).isNull();
+ }
+
+ private UserInfo setUpUser(int userId, ComponentName[] admins) {
+ UserInfo userInfo = new UserInfo(userId, "primary", 0);
when(mUserManager.getUserInfo(userId)).thenReturn(userInfo);
+ setUpActiveAdmins(userId, admins);
+ return userInfo;
+ }
+
+ private UserInfo setUpManagedProfile(int userId, ComponentName[] admins) {
+ UserInfo userInfo = new UserInfo(userId, "profile", UserInfo.FLAG_MANAGED_PROFILE);
+ when(mUserManager.getUserInfo(userId)).thenReturn(userInfo);
+ setUpActiveAdmins(userId, admins);
return userInfo;
}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/TileUtilsTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/TileUtilsTest.java
index 1683901..2d3c4a7 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/TileUtilsTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/TileUtilsTest.java
@@ -282,26 +282,11 @@
when(mPackageManager.queryIntentActivitiesAsUser(eq(intent), anyInt(), anyInt()))
.thenReturn(info);
- Bundle bundle = new Bundle();
- bundle.putInt("com.android.settings.icon", 161803);
- bundle.putString("com.android.settings.icon_package", "abc");
- bundle.putString("com.android.settings.summary", "dynamic-summary");
- when(mIContentProvider.call(anyString(),
- eq(TileUtils.getMethodFromUri(Uri.parse(URI_GET_ICON))), eq(URI_GET_ICON), any()))
- .thenReturn(bundle);
- when(mIContentProvider.call(anyString(),
- eq(TileUtils.getMethodFromUri(Uri.parse(URI_GET_SUMMARY))), eq(URI_GET_SUMMARY),
- any())).thenReturn(bundle);
- when(mContentResolver.acquireProvider(anyString())).thenReturn(mIContentProvider);
- when(mContentResolver.acquireProvider(any(Uri.class))).thenReturn(mIContentProvider);
-
TileUtils.getTilesForIntent(mContext, UserHandle.CURRENT, intent, addedCache,
null /* defaultCategory */, outTiles, false /* usePriority */,
false /* checkCategory */);
assertThat(outTiles.size()).isEqualTo(1);
- assertThat(outTiles.get(0).icon.getResId()).isEqualTo(161803);
- assertThat(outTiles.get(0).summary).isEqualTo("dynamic-summary");
}
public static ResolveInfo newInfo(boolean systemApp, String category) {
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index 521b8d7..5b4d2fd 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -88,6 +88,7 @@
import java.security.SecureRandom;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
@@ -2617,6 +2618,8 @@
if (isSecureSettingsKey(key)) {
maybeNotifyProfiles(getTypeFromKey(key), userId, uri, name,
sSecureCloneToManagedSettings);
+ maybeNotifyProfiles(SETTINGS_TYPE_SYSTEM, userId, uri, name,
+ sSystemCloneFromParentOnDependency.values());
} else if (isSystemSettingsKey(key)) {
maybeNotifyProfiles(getTypeFromKey(key), userId, uri, name,
sSystemCloneToManagedSettings);
@@ -2626,7 +2629,7 @@
}
private void maybeNotifyProfiles(int type, int userId, Uri uri, String name,
- Set<String> keysCloned) {
+ Collection<String> keysCloned) {
if (keysCloned.contains(name)) {
for (int profileId : mUserManager.getProfileIdsWithDisabled(userId)) {
// the notification for userId has already been sent.
@@ -2737,7 +2740,7 @@
}
private final class UpgradeController {
- private static final int SETTINGS_VERSION = 141;
+ private static final int SETTINGS_VERSION = 142;
private final int mUserId;
@@ -3262,6 +3265,26 @@
currentVersion = 141;
}
+ if (currentVersion == 141) {
+ // Version 141: We added the notion of a default and whether the system set
+ // the setting. This is used for resetting the internal state and we need
+ // to make sure this value is updated for the existing settings, otherwise
+ // we would delete system set settings while they should stay unmodified.
+ SettingsState globalSettings = getGlobalSettingsLocked();
+ ensureLegacyDefaultValueAndSystemSetUpdatedLocked(globalSettings);
+ globalSettings.persistSyncLocked();
+
+ SettingsState secureSettings = getSecureSettingsLocked(mUserId);
+ ensureLegacyDefaultValueAndSystemSetUpdatedLocked(secureSettings);
+ secureSettings.persistSyncLocked();
+
+ SettingsState systemSettings = getSystemSettingsLocked(mUserId);
+ ensureLegacyDefaultValueAndSystemSetUpdatedLocked(systemSettings);
+ systemSettings.persistSyncLocked();
+
+ currentVersion = 142;
+ }
+
if (currentVersion != newVersion) {
Slog.wtf("SettingsProvider", "warning: upgrading settings database to version "
+ newVersion + " left it at "
@@ -3277,5 +3300,22 @@
return currentVersion;
}
}
+
+ private void ensureLegacyDefaultValueAndSystemSetUpdatedLocked(SettingsState settings) {
+ List<String> names = settings.getSettingNamesLocked();
+ final int nameCount = names.size();
+ for (int i = 0; i < nameCount; i++) {
+ String name = names.get(i);
+ Setting setting = settings.getSettingLocked(name);
+ if (setting.getDefaultValue() == null) {
+ boolean systemSet = SettingsState.isSystemPackage(getContext(),
+ setting.getPackageName());
+ if (systemSet) {
+ settings.insertSettingLocked(name, setting.getValue(),
+ setting.getTag(), true, setting.getPackageName());
+ }
+ }
+ }
+ }
}
}
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index 34164b16..5b4dd48 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -118,6 +118,8 @@
<uses-permission android:name="android.permission.SUBSTITUTE_NOTIFICATION_APP_NAME" />
<!-- Permission needed to hold a wakelock in dumpstate.cpp (drop_root_user()) -->
<uses-permission android:name="android.permission.WAKE_LOCK" />
+ <!-- Permission needed to enable/disable overlays -->
+ <uses-permission android:name="android.permission.CHANGE_OVERLAY_PACKAGES" />
<application android:label="@string/app_label"
android:defaultToDeviceProtectedStorage="true"
diff --git a/packages/Shell/src/com/android/shell/BugreportProgressService.java b/packages/Shell/src/com/android/shell/BugreportProgressService.java
index 12d0c03..1df626f 100644
--- a/packages/Shell/src/com/android/shell/BugreportProgressService.java
+++ b/packages/Shell/src/com/android/shell/BugreportProgressService.java
@@ -44,6 +44,7 @@
import libcore.io.Streams;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.app.ChooserActivity;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.internal.util.FastPrintWriter;
@@ -943,8 +944,13 @@
}
static void sendShareIntent(Context context, Intent intent) {
- context.startActivity(Intent.createChooser(intent,
- context.getResources().getText(R.string.bugreport_intent_chooser_title)));
+ final Intent chooserIntent = Intent.createChooser(intent,
+ context.getResources().getText(R.string.bugreport_intent_chooser_title));
+
+ // Since we may be launched behind lockscreen, make sure that ChooserActivity doesn't finish
+ // itself in onStop.
+ chooserIntent.putExtra(ChooserActivity.EXTRA_PRIVATE_RETAIN_IN_ON_STOP, true);
+ context.startActivity(chooserIntent);
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/ActivityStarter.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/ActivityStarter.java
similarity index 88%
rename from packages/SystemUI/src/com/android/systemui/ActivityStarter.java
rename to packages/SystemUI/plugin/src/com/android/systemui/plugins/ActivityStarter.java
index a4d8a10..b58ea00 100644
--- a/packages/SystemUI/src/com/android/systemui/ActivityStarter.java
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/ActivityStarter.java
@@ -12,17 +12,21 @@
* permissions and limitations under the License.
*/
-package com.android.systemui;
+package com.android.systemui.plugins;
import android.app.PendingIntent;
import android.content.Intent;
+import com.android.systemui.plugins.annotations.ProvidesInterface;
+
/**
* An interface to start activities. This is used as a callback from the views to
* {@link PhoneStatusBar} to allow custom handling for starting the activity, i.e. dismissing the
* Keyguard.
*/
+@ProvidesInterface(version = ActivityStarter.VERSION)
public interface ActivityStarter {
+ int VERSION = 1;
void startPendingIntentDismissingKeyguard(PendingIntent intent);
void startActivity(Intent intent, boolean dismissShade);
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/PluginDependency.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/PluginDependency.java
new file mode 100644
index 0000000..25ce3dd
--- /dev/null
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/PluginDependency.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the
+ * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+package com.android.systemui.plugins;
+
+import com.android.systemui.plugins.annotations.ProvidesInterface;
+
+@ProvidesInterface(version = PluginDependency.VERSION)
+public class PluginDependency {
+ public static final int VERSION = 1;
+ static DependencyProvider sProvider;
+
+ public static <T> T get(Plugin p, Class<T> cls) {
+ return sProvider.get(p, cls);
+ }
+
+ static abstract class DependencyProvider {
+ abstract <T> T get(Plugin p, Class<T> cls);
+ }
+}
diff --git a/packages/SystemUI/res/drawable/clipboard_empty.xml b/packages/SystemUI/res/drawable/clipboard_empty.xml
index 14a5ad2..33cd58c 100644
--- a/packages/SystemUI/res/drawable/clipboard_empty.xml
+++ b/packages/SystemUI/res/drawable/clipboard_empty.xml
@@ -1,25 +1,24 @@
<!--
- Copyright (C) 2016 The Android Open Source Project
+ Copyright (C) 2017 The Android Open Source Project
- Licensed under the Apache License, Version 2.0 (the License);
+ 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,
+ 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:width="24.0dp"
- android:height="24.0dp"
+ android:width="18.0dp"
+ android:height="18.0dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#FFFFFFFF"
- android:pathData="M19.0,2.0l-4.18,0.0C14.0,0.84 13.3,0.0 12.0,0.0c-1.3,0.0 -2.0,0.84 -2.82,2.0L5.0,2.0c-1.1,0.0 -2.0,0.9 -2.0,2.0l0.0,16.0c0.0,1.0 0.9,2.0 2.0,2.0l14.0,0.0c1.1,0.0 2.0,-0.9 2.0,-2.0L21.0,4.0c0.0,-1.1 -0.9,-2.0 -2.0,-2.0zm-7.0,0.0c0.55,0.0 1.0,0.45 1.0,1.0s-0.45,1.0 -1.0,1.0 -1.0,-0.45 -1.0,-1.0 0.45,-1.0 1.0,-1.0zm7.0,18.0L5.0,20.0L5.0,4.0l2.0,0.0l0.0,3.0l10.0,0.0L17.0,4.0l2.0,0.0l0.0,16.0z" />
+ android:pathData="M16.0,1.0L4.0,1.0c-1.1,0.0 -2.0,0.9 -2.0,2.0l0.0,14.0l2.0,0.0L4.0,3.0l12.0,0.0L16.0,1.0zm3.0,4.0L8.0,5.0c-1.1,0.0 -2.0,0.9 -2.0,2.0l0.0,14.0c0.0,1.0 0.9,2.0 2.0,2.0l11.0,0.0c1.1,0.0 2.0,-0.9 2.0,-2.0L21.0,7.0c0.0,-1.1 -0.9,-2.0 -2.0,-2.0zm0.0,16.0L8.0,21.0L8.0,7.0l11.0,0.0l0.0,14.0z"/>
</vector>
-
diff --git a/packages/SystemUI/res/drawable/clipboard_full.xml b/packages/SystemUI/res/drawable/clipboard_full.xml
index 2d46870..cb056da 100644
--- a/packages/SystemUI/res/drawable/clipboard_full.xml
+++ b/packages/SystemUI/res/drawable/clipboard_full.xml
@@ -1,25 +1,24 @@
<!--
- Copyright (C) 2016 The Android Open Source Project
+ Copyright (C) 2017 The Android Open Source Project
- Licensed under the Apache License, Version 2.0 (the License);
+ 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,
+ 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:width="24.0dp"
- android:height="24.0dp"
- android:viewportWidth="24.0"
- android:viewportHeight="24.0">
+ android:width="18.0dp"
+ android:height="18.0dp"
+ android:viewportWidth="18.0"
+ android:viewportHeight="18.0">
<path
- android:fillColor="#FFFFFFFF"
- android:pathData="M19.0,2.0l-4.18,0.0C14.0,0.84 13.3,0.0 12.0,0.0c-1.3,0.0 -2.0,0.84 -2.82,2.0L5.0,2.0c-1.1,0.0 -2.0,0.9 -2.0,2.0l0.0,16.0c0.0,1.0 0.9,2.0 2.0,2.0l14.0,0.0c1.1,0.0 2.0,-0.9 2.0,-2.0L21.0,4.0c0.0,-1.1 -0.9,-2.0 -2.0,-2.0zm-7.0,0.0c0.55,0.0 1.0,0.45 1.0,1.0s-0.45,1.0 -1.0,1.0 -1.0,-0.45 -1.0,-1.0 0.45,-1.0 1.0,-1.0zm7.0,18.0L5.0,20.0L5.0,4.0l2.0,0.0l0.0,3.0l10.0,0.0L17.0,4.0l2.0,0.0l0.0,16.0z M 6,8 l 12,0 l 0,11 l -12,0 l 0,-11z" />
+ android:pathData="M12.0,0.75L3.0,0.75c-0.82,0.0 -1.5,0.67 -1.5,1.5l0.0,10.5L3.0,12.75L3.0,2.25l9.0,0.0L12.0,0.75zM14.25,3.75L6.0,3.75c-0.83,0.0 -1.5,0.67 -1.5,1.5l0.0,10.5c0.0,0.83 0.67,1.5 1.5,1.5l8.25,0.0c0.83,0.0 1.5,-0.67 1.5,-1.5L15.75,5.25C15.75,4.42 15.08,3.75 14.25,3.75zM7.25,6.5l5.74,0.0l0.0,1.75L7.25,8.25L7.25,6.5zM11.76,14.5l-4.5,0.0l0.0,-1.75l4.5,0.0L11.76,14.5zM13.0,11.38L7.26,11.38L7.26,9.62L13.0,9.62L13.0,11.38z"
+ android:fillColor="#FFFFFF"/>
</vector>
-
diff --git a/packages/SystemUI/res/drawable/ic_fingerprint_error.xml b/packages/SystemUI/res/drawable/ic_fingerprint_error.xml
index 11e83a1..a7fb1a1 100644
--- a/packages/SystemUI/res/drawable/ic_fingerprint_error.xml
+++ b/packages/SystemUI/res/drawable/ic_fingerprint_error.xml
@@ -19,12 +19,12 @@
android:viewportWidth="32.0"
android:viewportHeight="32.0">
<path
- android:fillColor="@color/system_warning_color"
+ android:fillColor="?android:attr/colorError"
android:pathData="M15.99,2.5C8.53,2.5 2.5,8.54 2.5,16.0s6.03,13.5 13.49,13.5S29.5,23.46 29.5,16.0S23.45,2.5 15.99,2.5zM16.0,26.8c-5.97,0.0 -10.8,-4.83 -10.8,-10.8S10.03,5.2 16.0,5.2S26.8,10.03 26.8,16.0S21.97,26.8 16.0,26.8z"/>
<path
- android:fillColor="@color/system_warning_color"
+ android:fillColor="?android:attr/colorError"
android:pathData="M14.65,20.05l2.7,0.0l0.0,2.7l-2.7,0.0z"/>
<path
- android:fillColor="@color/system_warning_color"
+ android:fillColor="?android:attr/colorError"
android:pathData="M14.65,9.25l2.7,0.0l0.0,8.1l-2.7,0.0z"/>
</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_network_logging.xml b/packages/SystemUI/res/drawable/ic_qs_network_logging.xml
index 87b5a14..7bdf50c 100644
--- a/packages/SystemUI/res/drawable/ic_qs_network_logging.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_network_logging.xml
@@ -20,8 +20,7 @@
android:width="12.0dp"
android:height="12.0dp"
android:viewportWidth="24.0"
- android:viewportHeight="24.0"
- android:tint="#4DFFFFFF" >
+ android:viewportHeight="24.0">
<path
android:fillColor="#FFFFFFFF"
android:pathData="M2,24v-4h12v4H2z M2,16v-4h20v4H2z M5,7 12,0 19,7 14,7 14,15 10,15 10,7z"/>
diff --git a/packages/SystemUI/res/drawable/ic_qs_signal_4g_plus.xml b/packages/SystemUI/res/drawable/ic_qs_signal_4g_plus.xml
index 54c52bf..782fbe4 100644
--- a/packages/SystemUI/res/drawable/ic_qs_signal_4g_plus.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_signal_4g_plus.xml
@@ -16,8 +16,8 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="32.0dp"
android:height="32.0dp"
- android:viewportWidth="24.0"
- android:viewportHeight="24.0">
+ android:viewportWidth="19.0"
+ android:viewportHeight="19.0">
<path
android:fillColor="#FFFFFFFF"
android:pathData="M4.6,7.8l0.7,0.0l0.0,1.3L4.6,9.1L4.6,11.0L3.0,11.0L3.0,9.2L0.1,9.2L0.0,8.2l3.0,-5.7l1.7,0.0L4.6,7.8L4.6,7.8zM1.7,7.8L3.0,7.8l0.0,-3.0L2.9,5.0L1.7,7.8z"/>
diff --git a/packages/SystemUI/res/drawable/ic_qs_signal_e.xml b/packages/SystemUI/res/drawable/ic_qs_signal_e.xml
index dd0f271..4232126 100644
--- a/packages/SystemUI/res/drawable/ic_qs_signal_e.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_signal_e.xml
@@ -16,9 +16,12 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="32dp"
android:height="32dp"
- android:viewportWidth="5.0"
- android:viewportHeight="5.0">
+ android:viewportWidth="13.0"
+ android:viewportHeight="13.0">
+ <group
+ android:translateX="3.5" >
<path
- android:fillColor="#FFFFFFFF"
- android:pathData="M4.400000,7.300000L1.700000,7.300000l0.000000,2.400000l3.300000,0.000000L5.000000,11.000000L0.000000,11.000000L0.000000,2.500000l4.900000,0.000000l0.000000,1.300000L1.700000,3.800000l0.000000,2.100000l2.800000,0.000000L4.500000,7.300000z"/>
+ android:fillColor="#FFFFFFFF"
+ android:pathData="M4.400000,7.300000L1.700000,7.300000l0.000000,2.400000l3.300000,0.000000L5.000000,11.000000L0.000000,11.000000L0.000000,2.500000l4.900000,0.000000l0.000000,1.300000L1.700000,3.800000l0.000000,2.100000l2.800000,0.000000L4.500000,7.300000z"/>
+ </group>
</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_signal_g.xml b/packages/SystemUI/res/drawable/ic_qs_signal_g.xml
index 3b47c0d..0c512d7 100644
--- a/packages/SystemUI/res/drawable/ic_qs_signal_g.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_signal_g.xml
@@ -16,9 +16,11 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="32dp"
android:height="32dp"
- android:viewportWidth="7.0"
- android:viewportHeight="7.0">
- <path
- android:fillColor="#FFFFFFFF"
- android:pathData="M6.500000,9.900000c-0.200000,0.400000 -0.600000,0.700000 -1.000000,0.900000s-1.000000,0.400000 -1.800000,0.400000c-0.900000,0.000000 -1.700000,-0.300000 -2.200000,-0.800000S0.700000,9.000000 0.700000,7.900000L0.700000,5.600000c0.000000,-1.100000 0.300000,-1.900000 0.800000,-2.400000s1.200000,-0.800000 2.100000,-0.800000c1.000000,0.000000 1.700000,0.200000 2.100000,0.700000s0.700000,1.200000 0.700000,2.100000L4.700000,5.200000c0.000000,-0.500000 -0.100000,-0.900000 -0.200000,-1.100000S4.000000,3.700000 3.600000,3.700000c-0.400000,0.000000 -0.700000,0.200000 -0.900000,0.500000S2.300000,5.000000 2.300000,5.600000l0.000000,2.300000c0.000000,0.700000 0.100000,1.100000 0.300000,1.400000s0.600000,0.500000 1.000000,0.500000c0.300000,0.000000 0.600000,0.000000 0.700000,-0.100000s0.300000,-0.200000 0.400000,-0.300000L4.700000,7.800000L3.500000,7.800000L3.500000,6.600000l2.900000,0.000000L6.400000,9.900000z"/>
+ android:viewportWidth="13.0"
+ android:viewportHeight="13.0">
+ <group android:translateX="3.5" >
+ <path
+ android:fillColor="#FFFFFFFF"
+ android:pathData="M6.500000,9.900000c-0.200000,0.400000 -0.600000,0.700000 -1.000000,0.900000s-1.000000,0.400000 -1.800000,0.400000c-0.900000,0.000000 -1.700000,-0.300000 -2.200000,-0.800000S0.700000,9.000000 0.700000,7.900000L0.700000,5.600000c0.000000,-1.100000 0.300000,-1.900000 0.800000,-2.400000s1.200000,-0.800000 2.100000,-0.800000c1.000000,0.000000 1.700000,0.200000 2.100000,0.700000s0.700000,1.200000 0.700000,2.100000L4.700000,5.200000c0.000000,-0.500000 -0.100000,-0.900000 -0.200000,-1.100000S4.000000,3.700000 3.600000,3.700000c-0.400000,0.000000 -0.700000,0.200000 -0.900000,0.500000S2.300000,5.000000 2.300000,5.600000l0.000000,2.300000c0.000000,0.700000 0.100000,1.100000 0.300000,1.400000s0.600000,0.500000 1.000000,0.500000c0.300000,0.000000 0.600000,0.000000 0.700000,-0.100000s0.300000,-0.200000 0.400000,-0.300000L4.700000,7.800000L3.500000,7.800000L3.500000,6.600000l2.900000,0.000000L6.400000,9.900000z"/>
+ </group>
</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_signal_h.xml b/packages/SystemUI/res/drawable/ic_qs_signal_h.xml
index d694e61..b9572b2 100644
--- a/packages/SystemUI/res/drawable/ic_qs_signal_h.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_signal_h.xml
@@ -14,11 +14,14 @@
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="32.0dp"
+ android:width="32dp"
android:height="32dp"
- android:viewportWidth="6.0"
- android:viewportHeight="6.0">
- <path
- android:fillColor="#FFFFFFFF"
- android:pathData="M6.000000,11.000000L4.400000,11.000000L4.400000,7.500000L1.700000,7.500000L1.700000,11.000000L0.000000,11.000000L0.000000,2.500000l1.700000,0.000000l0.000000,3.700000l2.700000,0.000000L4.400000,2.500000L6.000000,2.500000L6.000000,11.000000z"/>
+ android:viewportWidth="13.0"
+ android:viewportHeight="13.0">
+ <group
+ android:translateX="3.5" >
+ <path
+ android:fillColor="#FFFFFFFF"
+ android:pathData="M6.000000,11.000000L4.400000,11.000000L4.400000,7.500000L1.700000,7.500000L1.700000,11.000000L0.000000,11.000000L0.000000,2.500000l1.700000,0.000000l0.000000,3.700000l2.700000,0.000000L4.400000,2.500000L6.000000,2.500000L6.000000,11.000000z"/>
+ </group>
</vector>
diff --git a/packages/SystemUI/res/drawable/lockscreen_fingerprint_error_state_to_fp.xml b/packages/SystemUI/res/drawable/lockscreen_fingerprint_error_state_to_fp.xml
index e207cb3..3af2f7f 100644
--- a/packages/SystemUI/res/drawable/lockscreen_fingerprint_error_state_to_fp.xml
+++ b/packages/SystemUI/res/drawable/lockscreen_fingerprint_error_state_to_fp.xml
@@ -98,11 +98,11 @@
<path
android:name="path_2"
android:pathData="M 1.35900878906,6.76104736328 c 0.0,0.0 -2.69998168945,0.0 -2.69998168945,0.0 c 0.0,0.0 0.0,-2.69995117188 0.0,-2.69995117188 c 0.0,0.0 2.69998168945,0.0 2.69998168945,0.0 c 0.0,0.0 0.0,2.69995117188 0.0,2.69995117188 Z"
- android:fillColor="@*android:color/system_error" />
+ android:fillColor="?android:attr/colorError" />
<path
android:name="path_1"
android:pathData="M 1.35363769531,1.36633300781 c 0.0,0.0 -2.69998168945,0.0 -2.69998168945,0.0 c 0.0,0.0 0.0,-8.09997558594 0.0,-8.09997558594 c 0.0,0.0 2.69998168945,0.0 2.69998168945,0.0 c 0.0,0.0 0.0,8.09997558594 0.0,8.09997558594 Z"
- android:fillColor="@*android:color/system_error" />
+ android:fillColor="?android:attr/colorError" />
</group>
</group>
<group
@@ -117,7 +117,7 @@
<path
android:name="path_3"
android:pathData="M 0.0101470947266,10.8087768555 c -5.96701049805,0.0 -10.8000183105,-4.8330078125 -10.8000183105,-10.8000488281 c 0.0,-5.96691894531 4.8330078125,-10.7999267578 10.8000183105,-10.7999267578 c 5.96697998047,0.0 10.799987793,4.8330078125 10.799987793,10.7999267578 c 0.0,5.96704101562 -4.8330078125,10.8000488281 -10.799987793,10.8000488281 Z"
- android:strokeColor="@*android:color/system_error"
+ android:strokeColor="?android:attr/colorError"
android:strokeWidth="2"
android:trimPathStart="0"
android:trimPathEnd="1" />
diff --git a/packages/SystemUI/res/drawable/lockscreen_fingerprint_fp_to_error_state.xml b/packages/SystemUI/res/drawable/lockscreen_fingerprint_fp_to_error_state.xml
index 2b4babc..a577afc 100644
--- a/packages/SystemUI/res/drawable/lockscreen_fingerprint_fp_to_error_state.xml
+++ b/packages/SystemUI/res/drawable/lockscreen_fingerprint_fp_to_error_state.xml
@@ -96,7 +96,7 @@
<path
android:name="ridge_5_path_0"
android:pathData="M -25.3591003418,-24.4138946533 c -0.569000244141,0.106399536133 -1.12660217285,0.140594482422 -1.45460510254,0.140594482422 c -1.29689025879,0.0 -2.53239440918,-0.343307495117 -3.62019348145,-1.12400817871 c -1.67700195312,-1.20349121094 -2.76950073242,-3.17008972168 -2.76950073242,-5.39189147949"
- android:strokeColor="@*android:color/system_error"
+ android:strokeColor="?android:attr/colorError"
android:strokeWidth="1.45"
android:strokeLineCap="round"
android:trimPathEnd="0" />
@@ -106,7 +106,7 @@
<path
android:name="ridge_7_path_0"
android:pathData="M -36.1409912109,-21.7843475342 c -1.00540161133,-1.19300842285 -1.57499694824,-1.9181060791 -2.36520385742,-3.50170898438 c -0.827560424805,-1.65869140625 -1.31352233887,-3.49159240723 -1.31352233887,-5.48489379883 c 0.0,-3.66279602051 2.96932983398,-6.63220214844 6.63221740723,-6.63220214844 c 3.6628112793,0.0 6.63220214844,2.96940612793 6.63220214844,6.63220214844"
- android:strokeColor="@*android:color/system_error"
+ android:strokeColor="?android:attr/colorError"
android:strokeWidth="1.45"
android:strokeLineCap="round"
android:trimPathEnd="0" />
@@ -116,7 +116,7 @@
<path
android:name="ridge_6_path_0"
android:pathData="M -42.1907958984,-25.6756896973 c -0.758117675781,-2.14370727539 -0.896545410156,-3.86891174316 -0.896545410156,-5.12921142578 c 0.0,-1.46069335938 0.249176025391,-2.84799194336 0.814682006836,-4.09748840332 c 1.56153869629,-3.45030212402 5.03434753418,-5.85076904297 9.0679473877,-5.85076904297 c 5.49430847168,0.0 9.94830322266,4.4539642334 9.94830322266,9.94825744629 c 0.0,1.83151245117 -1.48460388184,3.31610107422 -3.31610107422,3.31610107422 c -1.83149719238,0.0 -3.31610107422,-1.48469543457 -3.31610107422,-3.31610107422 c 0.0,-1.83139038086 -1.48458862305,-3.31610107422 -3.31610107422,-3.31610107422 c -1.83149719238,0.0 -3.31610107422,1.48471069336 -3.31610107422,3.31610107422 c 0.0,2.57020568848 0.989517211914,4.88710021973 2.60510253906,6.5865020752 c 1.22210693359,1.28550720215 2.43139648438,2.09950256348 4.47590637207,2.69030761719"
- android:strokeColor="@*android:color/system_error"
+ android:strokeColor="?android:attr/colorError"
android:strokeWidth="1.45"
android:strokeLineCap="round"
android:trimPathEnd="0" />
@@ -126,7 +126,7 @@
<path
android:name="ridge_2_path_0"
android:pathData="M -44.0646514893,-38.1672973633 c 1.19026184082,-1.77430725098 2.67503356934,-3.24531555176 4.55902099609,-4.27278137207 c 1.88395690918,-1.0274810791 4.04466247559,-1.61137390137 6.34175109863,-1.61137390137 c 2.28761291504,0.0 4.43991088867,0.579071044922 6.31831359863,1.59861755371 c 1.8784942627,1.01954650879 3.36059570312,2.4796295166 4.55279541016,4.24153137207"
- android:strokeColor="@*android:color/system_error"
+ android:strokeColor="?android:attr/colorError"
android:strokeWidth="1.45"
android:strokeLineCap="round"
android:trimPathStart="1" />
@@ -138,7 +138,7 @@
<path
android:name="ridge_1_path_0"
android:pathData="M 71.7812347412,97.0507202148 c -2.27149963379,-1.31344604492 -4.71360778809,-2.07006835938 -7.56221008301,-2.07006835938 c -2.84869384766,0.0 -5.23320007324,0.779556274414 -7.34411621094,2.07006835938"
- android:strokeColor="@*android:color/system_error"
+ android:strokeColor="?android:attr/colorError"
android:strokeWidth="1.45"
android:strokeLineCap="round"
android:trimPathEnd="0" />
@@ -157,11 +157,11 @@
<path
android:name="path_2"
android:pathData="M -1.3705291748,4.06730651855 c 0.0,0.0 0.036376953125,-0.0102386474609 0.036376953125,-0.0102386474609 c 0.0,0.0 -0.00682067871094,0.0040283203125 -0.00682067871093,0.0040283203125 c 0.0,0.0 -0.0161437988281,0.00479125976562 -0.0161437988281,0.00479125976563 c 0.0,0.0 -0.0134124755859,0.00141906738281 -0.0134124755859,0.00141906738281 Z"
- android:fillColor="@*android:color/system_error" />
+ android:fillColor="?android:attr/colorError" />
<path
android:name="path_1"
android:pathData="M -1.3737487793,-6.77532958984 c 0.0,0.0 0.00604248046875,0.0166625976562 0.00604248046876,0.0166625976562 c 0.0,0.0 0.0213623046875,0.0250244140625 0.0213623046875,0.0250244140625 c 0.0,0.0 -0.00604248046875,-0.0166625976562 -0.00604248046876,-0.0166625976562 c 0.0,0.0 -0.0213623046875,-0.0250244140625 -0.0213623046875,-0.0250244140625 Z"
- android:fillColor="@*android:color/system_error" />
+ android:fillColor="?android:attr/colorError" />
</group>
</group>
<group
@@ -176,7 +176,7 @@
<path
android:name="path_3"
android:pathData="M 0.0101470947266,10.8087768555 c -5.96701049805,0.0 -10.8000183105,-4.8330078125 -10.8000183105,-10.8000488281 c 0.0,-5.96691894531 4.8330078125,-10.7999267578 10.8000183105,-10.7999267578 c 5.96697998047,0.0 10.799987793,4.8330078125 10.799987793,10.7999267578 c 0.0,5.96704101562 -4.8330078125,10.8000488281 -10.799987793,10.8000488281 Z"
- android:strokeColor="@*android:color/system_error"
+ android:strokeColor="?android:attr/colorError"
android:strokeWidth="2"
android:trimPathStart="1" />
</group>
diff --git a/packages/SystemUI/res/drawable/qs_ic_wifi_lock.xml b/packages/SystemUI/res/drawable/qs_ic_wifi_lock.xml
index b7da30b..bf405fa 100644
--- a/packages/SystemUI/res/drawable/qs_ic_wifi_lock.xml
+++ b/packages/SystemUI/res/drawable/qs_ic_wifi_lock.xml
@@ -20,10 +20,10 @@
android:viewportHeight="72.0"
android:tint="?android:attr/textColorPrimary">
<group
- android:translateX="52.0"
- android:translateY="42.0" >
+ android:translateX="28.0"
+ android:translateY="10.5" >
<path
- android:fillColor="#FFFFFFFF"
- android:pathData="M18.0,8.0l-1.0,0.0L17.0,6.0c0.0,-2.76 -2.24,-5.0 -5.0,-5.0S7.0,3.24 7.0,6.0l0.0,2.0L6.0,8.0c-1.1,0.0 -2.0,0.9 -2.0,2.0l0.0,10.0c0.0,1.0 0.9,2.0 2.0,2.0l12.0,0.0c1.1,0.0 2.0,-0.9 2.0,-2.0L20.0,10.0c0.0,-1.1 -0.9,-2.0 -2.0,-2.0zm-6.0,9.0c-1.1,0.0 -2.0,-0.9 -2.0,-2.0s0.9,-2.0 2.0,-2.0 2.0,0.9 2.0,2.0 -0.9,2.0 -2.0,2.0zm3.1,-9.0L8.9,8.0L8.9,6.0c0.0,-1.71 1.39,-3.1 3.1,-3.1 1.71,0.0 3.1,1.39 3.1,3.1l0.0,2.0z"/>
+ android:pathData="M36 16l-2 0 0 -4C34 6.48 29.52 2 24 2 18.48 2 14 6.48 14 12l0 4 -2 0c-2.21 0 -4 1.79 -4 4l0 20c0 2.21 1.79 4 4 4l24 0c2.21 0 4 -1.79 4 -4l0 -20c0 -2.21 -1.79 -4 -4 -4zM24 34c-2.21 0 -4 -1.79 -4 -4 0 -2.21 1.79 -4 4 -4 2.21 0 4 1.79 4 4 0 2.21 -1.79 4 -4 4zm6.2 -18l-12.4 0 0 -4c0 -3.42 2.78 -6.2 6.2 -6.2 3.42 0 6.2 2.78 6.2 6.2l0 4z"
+ android:fillColor="#FFFFFF" />
</group>
</vector>
diff --git a/packages/SystemUI/res/drawable/stat_sys_signal_in.xml b/packages/SystemUI/res/drawable/stat_sys_signal_in.xml
new file mode 100644
index 0000000..7e6e09b
--- /dev/null
+++ b/packages/SystemUI/res/drawable/stat_sys_signal_in.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2016 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:autoMirrored="true"
+ android:width="17dp"
+ android:height="17dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ <path
+ android:name="in"
+ android:fillColor="#FFFFFFFF"
+ android:pathData="M8.7,12.2l-2.0,3.5l-2.0,-3.5z" />
+</vector>
diff --git a/packages/SystemUI/res/drawable/stat_sys_signal_inout.xml b/packages/SystemUI/res/drawable/stat_sys_signal_inout.xml
new file mode 100644
index 0000000..b7b6f0f
--- /dev/null
+++ b/packages/SystemUI/res/drawable/stat_sys_signal_inout.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2016 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:autoMirrored="true"
+ android:width="17dp"
+ android:height="17dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ <path
+ android:name="in"
+ android:fillColor="#FFFFFFFF"
+ android:pathData="M8.7,12.2l-2.0,3.5l-2.0,-3.5z" />
+ <path
+ android:name="out"
+ android:fillColor="#FFFFFFFF"
+ android:pathData="M0.5,15.7l2.0,-3.5l2.0,3.5z" />
+</vector>
diff --git a/packages/SystemUI/res/drawable/stat_sys_signal_out.xml b/packages/SystemUI/res/drawable/stat_sys_signal_out.xml
new file mode 100644
index 0000000..910c035
--- /dev/null
+++ b/packages/SystemUI/res/drawable/stat_sys_signal_out.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2016 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:autoMirrored="true"
+ android:width="17dp"
+ android:height="17dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ <path
+ android:name="out"
+ android:fillColor="#FFFFFFFF"
+ android:pathData="M0.5,15.7l2.0,-3.5l2.0,3.5z" />
+</vector>
diff --git a/packages/SystemUI/res/drawable/stat_sys_wifi_in.xml b/packages/SystemUI/res/drawable/stat_sys_wifi_in.xml
new file mode 100644
index 0000000..666127b
--- /dev/null
+++ b/packages/SystemUI/res/drawable/stat_sys_wifi_in.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2016 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:autoMirrored="true"
+ android:width="18.41dp"
+ android:height="17dp"
+ android:viewportWidth="26.0"
+ android:viewportHeight="24.0">
+ <path
+ android:name="in"
+ android:fillColor="#FFFFFFFF"
+ android:pathData="M8.7,18.3l-2.0,3.5l-2.0,-3.5z" />
+</vector>
diff --git a/packages/SystemUI/res/drawable/stat_sys_wifi_inout.xml b/packages/SystemUI/res/drawable/stat_sys_wifi_inout.xml
new file mode 100644
index 0000000..eeba030
--- /dev/null
+++ b/packages/SystemUI/res/drawable/stat_sys_wifi_inout.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2016 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:autoMirrored="true"
+ android:width="18.41dp"
+ android:height="17dp"
+ android:viewportWidth="26.0"
+ android:viewportHeight="24.0">
+ <path
+ android:name="in"
+ android:fillColor="#FFFFFFFF"
+ android:pathData="M8.7,18.3l-2.0,3.5l-2.0,-3.5z" />
+ <path
+ android:name="out"
+ android:fillColor="#FFFFFFFF"
+ android:pathData="M0.5,21.8l2.0,-3.5l2.0,3.5z" />
+</vector>
diff --git a/packages/SystemUI/res/drawable/stat_sys_wifi_out.xml b/packages/SystemUI/res/drawable/stat_sys_wifi_out.xml
new file mode 100644
index 0000000..d577d1a
--- /dev/null
+++ b/packages/SystemUI/res/drawable/stat_sys_wifi_out.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2016 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:autoMirrored="true"
+ android:width="18.41dp"
+ android:height="17dp"
+ android:viewportWidth="26.0"
+ android:viewportHeight="24.0">
+ <path
+ android:name="out"
+ android:fillColor="#FFFFFFFF"
+ android:pathData="M0.5,21.8l2.0,-3.5l2.0,3.5z" />
+</vector>
diff --git a/packages/SystemUI/res/layout/mobile_signal_group.xml b/packages/SystemUI/res/layout/mobile_signal_group.xml
index 8b10074..d988acc 100644
--- a/packages/SystemUI/res/layout/mobile_signal_group.xml
+++ b/packages/SystemUI/res/layout/mobile_signal_group.xml
@@ -54,4 +54,10 @@
android:src="@drawable/stat_sys_roaming"
android:contentDescription="@string/accessibility_data_connection_roaming"
android:visibility="gone" />
+ <ImageView
+ android:id="@+id/mobile_inout"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:visibility="gone"
+ />
</FrameLayout>
diff --git a/packages/SystemUI/res/layout/qs_detail_item.xml b/packages/SystemUI/res/layout/qs_detail_item.xml
index 6edf135..6544f0d 100644
--- a/packages/SystemUI/res/layout/qs_detail_item.xml
+++ b/packages/SystemUI/res/layout/qs_detail_item.xml
@@ -63,7 +63,6 @@
android:focusable="true"
android:scaleType="center"
android:contentDescription="@*android:string/media_route_controller_disconnect"
- android:tint="?android:attr/textColorPrimary"
- android:src="@drawable/ic_qs_cancel" />
+ android:tint="?android:attr/textColorPrimary" />
</LinearLayout>
diff --git a/packages/SystemUI/res/layout/signal_cluster_view.xml b/packages/SystemUI/res/layout/signal_cluster_view.xml
index 222a31d..4d03f0f 100644
--- a/packages/SystemUI/res/layout/signal_cluster_view.xml
+++ b/packages/SystemUI/res/layout/signal_cluster_view.xml
@@ -70,6 +70,11 @@
android:layout_width="wrap_content"
android:alpha="0.0"
/>
+ <ImageView
+ android:id="@+id/wifi_inout"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ />
</FrameLayout>
<View
android:id="@+id/wifi_signal_spacer"
diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml
index 073a6dc..d63fc0e 100644
--- a/packages/SystemUI/res/values-af/strings.xml
+++ b/packages/SystemUI/res/values-af/strings.xml
@@ -692,9 +692,7 @@
<string name="notification_channel_screenshot" msgid="6314080179230000938">"Skermkiekies"</string>
<string name="notification_channel_general" msgid="4525309436693914482">"Algemene boodskappe"</string>
<string name="notification_channel_storage" msgid="3077205683020695313">"Berging"</string>
- <!-- no translation found for instant_apps (6647570248119804907) -->
- <skip />
- <!-- no translation found for instant_apps_message (8116608994995104836) -->
- <skip />
+ <string name="instant_apps" msgid="6647570248119804907">"Kitsprogramme"</string>
+ <string name="instant_apps_message" msgid="8116608994995104836">"Kitsprogramme hoef nie geïnstalleer te word nie."</string>
<string name="app_info" msgid="6856026610594615344">"Programinligting"</string>
</resources>
diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml
index f33b663..4bfebd2 100644
--- a/packages/SystemUI/res/values-am/strings.xml
+++ b/packages/SystemUI/res/values-am/strings.xml
@@ -692,9 +692,7 @@
<string name="notification_channel_screenshot" msgid="6314080179230000938">"ቅጽበታዊ ገጽ እይታዎች"</string>
<string name="notification_channel_general" msgid="4525309436693914482">"አጠቃላይ መልዕክቶች"</string>
<string name="notification_channel_storage" msgid="3077205683020695313">"ማከማቻ"</string>
- <!-- no translation found for instant_apps (6647570248119804907) -->
- <skip />
- <!-- no translation found for instant_apps_message (8116608994995104836) -->
- <skip />
+ <string name="instant_apps" msgid="6647570248119804907">"የቅጽበት መተግበሪያዎች"</string>
+ <string name="instant_apps_message" msgid="8116608994995104836">"ቅጽበታዊ መተግበሪያዎች መጫን አያስፈልጋቸውም።"</string>
<string name="app_info" msgid="6856026610594615344">"የመተግበሪያ መረጃ"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml
index 94810bd..1381cb3 100644
--- a/packages/SystemUI/res/values-ar/strings.xml
+++ b/packages/SystemUI/res/values-ar/strings.xml
@@ -704,9 +704,7 @@
<string name="notification_channel_screenshot" msgid="6314080179230000938">"لقطات الشاشة"</string>
<string name="notification_channel_general" msgid="4525309436693914482">"رسائل عامة"</string>
<string name="notification_channel_storage" msgid="3077205683020695313">"سعة التخزين"</string>
- <!-- no translation found for instant_apps (6647570248119804907) -->
- <skip />
- <!-- no translation found for instant_apps_message (8116608994995104836) -->
- <skip />
+ <string name="instant_apps" msgid="6647570248119804907">"التطبيقات الفورية"</string>
+ <string name="instant_apps_message" msgid="8116608994995104836">"لا تتطلب التطبيقات الفورية إجراء التثبيت."</string>
<string name="app_info" msgid="6856026610594615344">"معلومات عن التطبيق"</string>
</resources>
diff --git a/packages/SystemUI/res/values-az/strings.xml b/packages/SystemUI/res/values-az/strings.xml
index dea9a57..c90e442 100644
--- a/packages/SystemUI/res/values-az/strings.xml
+++ b/packages/SystemUI/res/values-az/strings.xml
@@ -692,9 +692,7 @@
<string name="notification_channel_screenshot" msgid="6314080179230000938">"Skrinşotlar"</string>
<string name="notification_channel_general" msgid="4525309436693914482">"Ümumi Mesajlar"</string>
<string name="notification_channel_storage" msgid="3077205683020695313">"Yaddaş"</string>
- <!-- no translation found for instant_apps (6647570248119804907) -->
- <skip />
- <!-- no translation found for instant_apps_message (8116608994995104836) -->
- <skip />
+ <string name="instant_apps" msgid="6647570248119804907">"Ani Tətbiqlər"</string>
+ <string name="instant_apps_message" msgid="8116608994995104836">"Ani tətbiqlər quraşdırma tələb etmir."</string>
<string name="app_info" msgid="6856026610594615344">"Tətbiq məlumatı"</string>
</resources>
diff --git a/packages/SystemUI/res/values-b+sr+Latn/strings.xml b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
index eaeabc9..59a925e 100644
--- a/packages/SystemUI/res/values-b+sr+Latn/strings.xml
+++ b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
@@ -695,9 +695,7 @@
<string name="notification_channel_screenshot" msgid="6314080179230000938">"Snimci ekrana"</string>
<string name="notification_channel_general" msgid="4525309436693914482">"Opšte poruke"</string>
<string name="notification_channel_storage" msgid="3077205683020695313">"Memorijski prostor"</string>
- <!-- no translation found for instant_apps (6647570248119804907) -->
- <skip />
- <!-- no translation found for instant_apps_message (8116608994995104836) -->
- <skip />
+ <string name="instant_apps" msgid="6647570248119804907">"Instant aplikacije"</string>
+ <string name="instant_apps_message" msgid="8116608994995104836">"Instant aplikacije ne zahtevaju instalaciju."</string>
<string name="app_info" msgid="6856026610594615344">"Informacije o aplikaciji"</string>
</resources>
diff --git a/packages/SystemUI/res/values-be/strings.xml b/packages/SystemUI/res/values-be/strings.xml
index 89191fa..efbf39e 100644
--- a/packages/SystemUI/res/values-be/strings.xml
+++ b/packages/SystemUI/res/values-be/strings.xml
@@ -700,9 +700,7 @@
<string name="notification_channel_screenshot" msgid="6314080179230000938">"Здымкі экрана"</string>
<string name="notification_channel_general" msgid="4525309436693914482">"Агульныя паведамленні"</string>
<string name="notification_channel_storage" msgid="3077205683020695313">"Захоўванне"</string>
- <!-- no translation found for instant_apps (6647570248119804907) -->
- <skip />
- <!-- no translation found for instant_apps_message (8116608994995104836) -->
- <skip />
+ <string name="instant_apps" msgid="6647570248119804907">"Імгненныя праграмы"</string>
+ <string name="instant_apps_message" msgid="8116608994995104836">"Імгненныя праграмы не патрабуюць усталёўкі."</string>
<string name="app_info" msgid="6856026610594615344">"Інфармацыя пра праграму"</string>
</resources>
diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml
index 3816775..3ebfcc8 100644
--- a/packages/SystemUI/res/values-bg/strings.xml
+++ b/packages/SystemUI/res/values-bg/strings.xml
@@ -692,9 +692,7 @@
<string name="notification_channel_screenshot" msgid="6314080179230000938">"Екранни снимки"</string>
<string name="notification_channel_general" msgid="4525309436693914482">"Общи съобщения"</string>
<string name="notification_channel_storage" msgid="3077205683020695313">"Хранилище"</string>
- <!-- no translation found for instant_apps (6647570248119804907) -->
- <skip />
- <!-- no translation found for instant_apps_message (8116608994995104836) -->
- <skip />
+ <string name="instant_apps" msgid="6647570248119804907">"Мигновени приложения"</string>
+ <string name="instant_apps_message" msgid="8116608994995104836">"За мигновените приложения не се изисква инсталиране."</string>
<string name="app_info" msgid="6856026610594615344">"Информация за приложението"</string>
</resources>
diff --git a/packages/SystemUI/res/values-bn/strings.xml b/packages/SystemUI/res/values-bn/strings.xml
index 76a882f..476e27c 100644
--- a/packages/SystemUI/res/values-bn/strings.xml
+++ b/packages/SystemUI/res/values-bn/strings.xml
@@ -692,9 +692,7 @@
<string name="notification_channel_screenshot" msgid="6314080179230000938">"স্ক্রীনশটস"</string>
<string name="notification_channel_general" msgid="4525309436693914482">"সাধারণ বার্তাগুলি"</string>
<string name="notification_channel_storage" msgid="3077205683020695313">"সঞ্চয়স্থান"</string>
- <!-- no translation found for instant_apps (6647570248119804907) -->
- <skip />
- <!-- no translation found for instant_apps_message (8116608994995104836) -->
- <skip />
+ <string name="instant_apps" msgid="6647570248119804907">"ঝটপট অ্যাপ"</string>
+ <string name="instant_apps_message" msgid="8116608994995104836">"ঝটপট অ্যাপ ইনস্টল করার প্রয়োজন হয় না।"</string>
<string name="app_info" msgid="6856026610594615344">"অ্যাপ্লিকেশানের তথ্য"</string>
</resources>
diff --git a/packages/SystemUI/res/values-bs/strings.xml b/packages/SystemUI/res/values-bs/strings.xml
index 208befe..c318501 100644
--- a/packages/SystemUI/res/values-bs/strings.xml
+++ b/packages/SystemUI/res/values-bs/strings.xml
@@ -697,9 +697,7 @@
<string name="notification_channel_screenshot" msgid="6314080179230000938">"Snimci ekrana"</string>
<string name="notification_channel_general" msgid="4525309436693914482">"Općenite poruke"</string>
<string name="notification_channel_storage" msgid="3077205683020695313">"Pohrana"</string>
- <!-- no translation found for instant_apps (6647570248119804907) -->
- <skip />
- <!-- no translation found for instant_apps_message (8116608994995104836) -->
- <skip />
+ <string name="instant_apps" msgid="6647570248119804907">"Instant-aplikacije"</string>
+ <string name="instant_apps_message" msgid="8116608994995104836">"Za instant aplikacije nije potrebna instalacija"</string>
<string name="app_info" msgid="6856026610594615344">"Informacije o aplikaciji"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml
index ccb3114..14455b3 100644
--- a/packages/SystemUI/res/values-ca/strings.xml
+++ b/packages/SystemUI/res/values-ca/strings.xml
@@ -692,9 +692,7 @@
<string name="notification_channel_screenshot" msgid="6314080179230000938">"Captures de pantalla"</string>
<string name="notification_channel_general" msgid="4525309436693914482">"Missatges generals"</string>
<string name="notification_channel_storage" msgid="3077205683020695313">"Emmagatzematge"</string>
- <!-- no translation found for instant_apps (6647570248119804907) -->
- <skip />
- <!-- no translation found for instant_apps_message (8116608994995104836) -->
- <skip />
+ <string name="instant_apps" msgid="6647570248119804907">"Aplicacions instantànies"</string>
+ <string name="instant_apps_message" msgid="8116608994995104836">"No cal instal·lar les aplicacions instantànies."</string>
<string name="app_info" msgid="6856026610594615344">"Informació de l\'aplicació"</string>
</resources>
diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml
index 534e7bf..2cb79c9 100644
--- a/packages/SystemUI/res/values-cs/strings.xml
+++ b/packages/SystemUI/res/values-cs/strings.xml
@@ -700,9 +700,7 @@
<string name="notification_channel_screenshot" msgid="6314080179230000938">"Snímky obrazovek"</string>
<string name="notification_channel_general" msgid="4525309436693914482">"Všeobecné zprávy"</string>
<string name="notification_channel_storage" msgid="3077205683020695313">"Úložiště"</string>
- <!-- no translation found for instant_apps (6647570248119804907) -->
- <skip />
- <!-- no translation found for instant_apps_message (8116608994995104836) -->
- <skip />
+ <string name="instant_apps" msgid="6647570248119804907">"Okamžité aplikace"</string>
+ <string name="instant_apps_message" msgid="8116608994995104836">"Okamžité aplikace není třeba instalovat."</string>
<string name="app_info" msgid="6856026610594615344">"Informace o aplikaci"</string>
</resources>
diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml
index f694924..681f747 100644
--- a/packages/SystemUI/res/values-da/strings.xml
+++ b/packages/SystemUI/res/values-da/strings.xml
@@ -692,9 +692,7 @@
<string name="notification_channel_screenshot" msgid="6314080179230000938">"Screenshots"</string>
<string name="notification_channel_general" msgid="4525309436693914482">"Generelle meddelelser"</string>
<string name="notification_channel_storage" msgid="3077205683020695313">"Lagerplads"</string>
- <!-- no translation found for instant_apps (6647570248119804907) -->
- <skip />
- <!-- no translation found for instant_apps_message (8116608994995104836) -->
- <skip />
+ <string name="instant_apps" msgid="6647570248119804907">"Instant Apps"</string>
+ <string name="instant_apps_message" msgid="8116608994995104836">"Instant apps kræver ingen installation."</string>
<string name="app_info" msgid="6856026610594615344">"Oplysninger om appen"</string>
</resources>
diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml
index dbbb4f9..cb6c4b3 100644
--- a/packages/SystemUI/res/values-de/strings.xml
+++ b/packages/SystemUI/res/values-de/strings.xml
@@ -694,9 +694,7 @@
<string name="notification_channel_screenshot" msgid="6314080179230000938">"Screenshots"</string>
<string name="notification_channel_general" msgid="4525309436693914482">"Nachrichten"</string>
<string name="notification_channel_storage" msgid="3077205683020695313">"Speicher"</string>
- <!-- no translation found for instant_apps (6647570248119804907) -->
- <skip />
- <!-- no translation found for instant_apps_message (8116608994995104836) -->
- <skip />
+ <string name="instant_apps" msgid="6647570248119804907">"Instant-Apps"</string>
+ <string name="instant_apps_message" msgid="8116608994995104836">"Bei Instant-Apps ist keine vorherige Installation erforderlich."</string>
<string name="app_info" msgid="6856026610594615344">"App-Informationen"</string>
</resources>
diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml
index 688084b..0998797 100644
--- a/packages/SystemUI/res/values-el/strings.xml
+++ b/packages/SystemUI/res/values-el/strings.xml
@@ -692,9 +692,7 @@
<string name="notification_channel_screenshot" msgid="6314080179230000938">"Στιγμιότυπα οθόνης"</string>
<string name="notification_channel_general" msgid="4525309436693914482">"Γενικά μηνύματα"</string>
<string name="notification_channel_storage" msgid="3077205683020695313">"Αποθηκευτικός χώρος"</string>
- <!-- no translation found for instant_apps (6647570248119804907) -->
- <skip />
- <!-- no translation found for instant_apps_message (8116608994995104836) -->
- <skip />
+ <string name="instant_apps" msgid="6647570248119804907">"Instant Εφαρμογές"</string>
+ <string name="instant_apps_message" msgid="8116608994995104836">"Οι Instant Εφαρμογές δεν απαιτούν εγκατάσταση."</string>
<string name="app_info" msgid="6856026610594615344">"Πληροφορίες εφαρμογής"</string>
</resources>
diff --git a/packages/SystemUI/res/values-en-rAU/strings.xml b/packages/SystemUI/res/values-en-rAU/strings.xml
index bcac06f..eba837a 100644
--- a/packages/SystemUI/res/values-en-rAU/strings.xml
+++ b/packages/SystemUI/res/values-en-rAU/strings.xml
@@ -692,9 +692,7 @@
<string name="notification_channel_screenshot" msgid="6314080179230000938">"Screenshots"</string>
<string name="notification_channel_general" msgid="4525309436693914482">"General Messages"</string>
<string name="notification_channel_storage" msgid="3077205683020695313">"Storage"</string>
- <!-- no translation found for instant_apps (6647570248119804907) -->
- <skip />
- <!-- no translation found for instant_apps_message (8116608994995104836) -->
- <skip />
+ <string name="instant_apps" msgid="6647570248119804907">"Instant Apps"</string>
+ <string name="instant_apps_message" msgid="8116608994995104836">"Instant apps don\'t require installation."</string>
<string name="app_info" msgid="6856026610594615344">"App info"</string>
</resources>
diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml
index bcac06f..eba837a 100644
--- a/packages/SystemUI/res/values-en-rGB/strings.xml
+++ b/packages/SystemUI/res/values-en-rGB/strings.xml
@@ -692,9 +692,7 @@
<string name="notification_channel_screenshot" msgid="6314080179230000938">"Screenshots"</string>
<string name="notification_channel_general" msgid="4525309436693914482">"General Messages"</string>
<string name="notification_channel_storage" msgid="3077205683020695313">"Storage"</string>
- <!-- no translation found for instant_apps (6647570248119804907) -->
- <skip />
- <!-- no translation found for instant_apps_message (8116608994995104836) -->
- <skip />
+ <string name="instant_apps" msgid="6647570248119804907">"Instant Apps"</string>
+ <string name="instant_apps_message" msgid="8116608994995104836">"Instant apps don\'t require installation."</string>
<string name="app_info" msgid="6856026610594615344">"App info"</string>
</resources>
diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml
index bcac06f..eba837a 100644
--- a/packages/SystemUI/res/values-en-rIN/strings.xml
+++ b/packages/SystemUI/res/values-en-rIN/strings.xml
@@ -692,9 +692,7 @@
<string name="notification_channel_screenshot" msgid="6314080179230000938">"Screenshots"</string>
<string name="notification_channel_general" msgid="4525309436693914482">"General Messages"</string>
<string name="notification_channel_storage" msgid="3077205683020695313">"Storage"</string>
- <!-- no translation found for instant_apps (6647570248119804907) -->
- <skip />
- <!-- no translation found for instant_apps_message (8116608994995104836) -->
- <skip />
+ <string name="instant_apps" msgid="6647570248119804907">"Instant Apps"</string>
+ <string name="instant_apps_message" msgid="8116608994995104836">"Instant apps don\'t require installation."</string>
<string name="app_info" msgid="6856026610594615344">"App info"</string>
</resources>
diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml
index b0ccb27..c2a41f1 100644
--- a/packages/SystemUI/res/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings.xml
@@ -694,9 +694,7 @@
<string name="notification_channel_screenshot" msgid="6314080179230000938">"Capturas de pantalla"</string>
<string name="notification_channel_general" msgid="4525309436693914482">"Mensajes generales"</string>
<string name="notification_channel_storage" msgid="3077205683020695313">"Almacenamiento"</string>
- <!-- no translation found for instant_apps (6647570248119804907) -->
- <skip />
- <!-- no translation found for instant_apps_message (8116608994995104836) -->
- <skip />
+ <string name="instant_apps" msgid="6647570248119804907">"Apps instantáneas"</string>
+ <string name="instant_apps_message" msgid="8116608994995104836">"Las Apps instantáneas no requieren instalación."</string>
<string name="app_info" msgid="6856026610594615344">"Información de la app"</string>
</resources>
diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml
index 59fe471..503eb64 100644
--- a/packages/SystemUI/res/values-es/strings.xml
+++ b/packages/SystemUI/res/values-es/strings.xml
@@ -694,9 +694,7 @@
<string name="notification_channel_screenshot" msgid="6314080179230000938">"Capturas de pantalla"</string>
<string name="notification_channel_general" msgid="4525309436693914482">"Mensajes generales"</string>
<string name="notification_channel_storage" msgid="3077205683020695313">"Almacenamiento"</string>
- <!-- no translation found for instant_apps (6647570248119804907) -->
- <skip />
- <!-- no translation found for instant_apps_message (8116608994995104836) -->
- <skip />
+ <string name="instant_apps" msgid="6647570248119804907">"Aplicaciones Instantáneas"</string>
+ <string name="instant_apps_message" msgid="8116608994995104836">"No es necesario instalar las Aplicaciones Instantáneas."</string>
<string name="app_info" msgid="6856026610594615344">"Información de la aplicación"</string>
</resources>
diff --git a/packages/SystemUI/res/values-et/strings.xml b/packages/SystemUI/res/values-et/strings.xml
index 3afebd7..94577f5 100644
--- a/packages/SystemUI/res/values-et/strings.xml
+++ b/packages/SystemUI/res/values-et/strings.xml
@@ -694,9 +694,7 @@
<string name="notification_channel_screenshot" msgid="6314080179230000938">"Ekraanipildid"</string>
<string name="notification_channel_general" msgid="4525309436693914482">"Üldised sõnumid"</string>
<string name="notification_channel_storage" msgid="3077205683020695313">"Salvestusruum"</string>
- <!-- no translation found for instant_apps (6647570248119804907) -->
- <skip />
- <!-- no translation found for instant_apps_message (8116608994995104836) -->
- <skip />
+ <string name="instant_apps" msgid="6647570248119804907">"Installimata avatavad rakendused"</string>
+ <string name="instant_apps_message" msgid="8116608994995104836">"Installimata avatavaid rakendusi pole vaja installida."</string>
<string name="app_info" msgid="6856026610594615344">"Rakenduse teave"</string>
</resources>
diff --git a/packages/SystemUI/res/values-eu/strings.xml b/packages/SystemUI/res/values-eu/strings.xml
index 399d9ec..72d8ecb 100644
--- a/packages/SystemUI/res/values-eu/strings.xml
+++ b/packages/SystemUI/res/values-eu/strings.xml
@@ -694,9 +694,7 @@
<string name="notification_channel_screenshot" msgid="6314080179230000938">"Pantaila-argazkiak"</string>
<string name="notification_channel_general" msgid="4525309436693914482">"Mezu orokorrak"</string>
<string name="notification_channel_storage" msgid="3077205683020695313">"Memoria"</string>
- <!-- no translation found for instant_apps (6647570248119804907) -->
- <skip />
- <!-- no translation found for instant_apps_message (8116608994995104836) -->
- <skip />
+ <string name="instant_apps" msgid="6647570248119804907">"Zuzeneko aplikazioak"</string>
+ <string name="instant_apps_message" msgid="8116608994995104836">"Zuzeneko aplikazioak ez dira instalatu behar."</string>
<string name="app_info" msgid="6856026610594615344">"Aplikazioari buruzko informazioa"</string>
</resources>
diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml
index f38bd46..b8e8ed1 100644
--- a/packages/SystemUI/res/values-fa/strings.xml
+++ b/packages/SystemUI/res/values-fa/strings.xml
@@ -692,9 +692,7 @@
<string name="notification_channel_screenshot" msgid="6314080179230000938">"عکسهای صفحهنمایش"</string>
<string name="notification_channel_general" msgid="4525309436693914482">"پیامهای عمومی"</string>
<string name="notification_channel_storage" msgid="3077205683020695313">"فضای ذخیرهسازی"</string>
- <!-- no translation found for instant_apps (6647570248119804907) -->
- <skip />
- <!-- no translation found for instant_apps_message (8116608994995104836) -->
- <skip />
+ <string name="instant_apps" msgid="6647570248119804907">"برنامههای فوری"</string>
+ <string name="instant_apps_message" msgid="8116608994995104836">"برنامههای فوری نیاز به نصب ندارند."</string>
<string name="app_info" msgid="6856026610594615344">"اطلاعات برنامه"</string>
</resources>
diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml
index b29a0f5..2480ac8 100644
--- a/packages/SystemUI/res/values-fi/strings.xml
+++ b/packages/SystemUI/res/values-fi/strings.xml
@@ -692,9 +692,7 @@
<string name="notification_channel_screenshot" msgid="6314080179230000938">"Kuvakaappaukset"</string>
<string name="notification_channel_general" msgid="4525309436693914482">"Yleiset viestit"</string>
<string name="notification_channel_storage" msgid="3077205683020695313">"Tallennustila"</string>
- <!-- no translation found for instant_apps (6647570248119804907) -->
- <skip />
- <!-- no translation found for instant_apps_message (8116608994995104836) -->
- <skip />
+ <string name="instant_apps" msgid="6647570248119804907">"Instant Apps"</string>
+ <string name="instant_apps_message" msgid="8116608994995104836">"Pikasovelluksia ei tarvitse asentaa."</string>
<string name="app_info" msgid="6856026610594615344">"Sovelluksen tiedot"</string>
</resources>
diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml
index 21f7498..121b137 100644
--- a/packages/SystemUI/res/values-fr-rCA/strings.xml
+++ b/packages/SystemUI/res/values-fr-rCA/strings.xml
@@ -694,9 +694,7 @@
<string name="notification_channel_screenshot" msgid="6314080179230000938">"Saisies d\'écran"</string>
<string name="notification_channel_general" msgid="4525309436693914482">"Messages généraux"</string>
<string name="notification_channel_storage" msgid="3077205683020695313">"Stockage"</string>
- <!-- no translation found for instant_apps (6647570248119804907) -->
- <skip />
- <!-- no translation found for instant_apps_message (8116608994995104836) -->
- <skip />
+ <string name="instant_apps" msgid="6647570248119804907">"Applications instantanées"</string>
+ <string name="instant_apps_message" msgid="8116608994995104836">"Les applications instantanées ne nécessitent pas d\'installation."</string>
<string name="app_info" msgid="6856026610594615344">"Détails de l\'application"</string>
</resources>
diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml
index c65e0ea..6d677ae 100644
--- a/packages/SystemUI/res/values-fr/strings.xml
+++ b/packages/SystemUI/res/values-fr/strings.xml
@@ -694,9 +694,7 @@
<string name="notification_channel_screenshot" msgid="6314080179230000938">"Captures d\'écran"</string>
<string name="notification_channel_general" msgid="4525309436693914482">"Nouveaux messages"</string>
<string name="notification_channel_storage" msgid="3077205683020695313">"Espace de stockage"</string>
- <!-- no translation found for instant_apps (6647570248119804907) -->
- <skip />
- <!-- no translation found for instant_apps_message (8116608994995104836) -->
- <skip />
+ <string name="instant_apps" msgid="6647570248119804907">"Applis instantanées"</string>
+ <string name="instant_apps_message" msgid="8116608994995104836">"Les applis instantanées ne nécessitent pas d\'installation."</string>
<string name="app_info" msgid="6856026610594615344">"Infos sur l\'appli"</string>
</resources>
diff --git a/packages/SystemUI/res/values-gl/strings.xml b/packages/SystemUI/res/values-gl/strings.xml
index 3579ebe..e5df1d3 100644
--- a/packages/SystemUI/res/values-gl/strings.xml
+++ b/packages/SystemUI/res/values-gl/strings.xml
@@ -694,9 +694,7 @@
<string name="notification_channel_screenshot" msgid="6314080179230000938">"Capturas de pantalla"</string>
<string name="notification_channel_general" msgid="4525309436693914482">"Mensaxes xerais"</string>
<string name="notification_channel_storage" msgid="3077205683020695313">"Almacenamento"</string>
- <!-- no translation found for instant_apps (6647570248119804907) -->
- <skip />
- <!-- no translation found for instant_apps_message (8116608994995104836) -->
- <skip />
+ <string name="instant_apps" msgid="6647570248119804907">"Aplicacións instantáneas"</string>
+ <string name="instant_apps_message" msgid="8116608994995104836">"As aplicacións instantáneas non precisan instalación."</string>
<string name="app_info" msgid="6856026610594615344">"Información da aplicación"</string>
</resources>
diff --git a/packages/SystemUI/res/values-gu/strings.xml b/packages/SystemUI/res/values-gu/strings.xml
index acc3890..381476f 100644
--- a/packages/SystemUI/res/values-gu/strings.xml
+++ b/packages/SystemUI/res/values-gu/strings.xml
@@ -692,9 +692,7 @@
<string name="notification_channel_screenshot" msgid="6314080179230000938">"સ્ક્રીનશૉટ"</string>
<string name="notification_channel_general" msgid="4525309436693914482">"સામાન્ય સંદેશા"</string>
<string name="notification_channel_storage" msgid="3077205683020695313">"સ્ટોરેજ"</string>
- <!-- no translation found for instant_apps (6647570248119804907) -->
- <skip />
- <!-- no translation found for instant_apps_message (8116608994995104836) -->
- <skip />
+ <string name="instant_apps" msgid="6647570248119804907">"ઝટપટ ઍપ્લિકેશનો"</string>
+ <string name="instant_apps_message" msgid="8116608994995104836">"ઝટપટ ઍપ્લિકેશનો માટે ઇન્સ્ટૉલેશનની જરૂર નથી."</string>
<string name="app_info" msgid="6856026610594615344">"ઍપ્લિકેશન માહિતી"</string>
</resources>
diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml
index a318ea3..27a5918 100644
--- a/packages/SystemUI/res/values-hi/strings.xml
+++ b/packages/SystemUI/res/values-hi/strings.xml
@@ -692,9 +692,7 @@
<string name="notification_channel_screenshot" msgid="6314080179230000938">"स्क्रीनशॉट"</string>
<string name="notification_channel_general" msgid="4525309436693914482">"सामान्य संदेश"</string>
<string name="notification_channel_storage" msgid="3077205683020695313">"जगह"</string>
- <!-- no translation found for instant_apps (6647570248119804907) -->
- <skip />
- <!-- no translation found for instant_apps_message (8116608994995104836) -->
- <skip />
+ <string name="instant_apps" msgid="6647570248119804907">"झटपट ऐप्स"</string>
+ <string name="instant_apps_message" msgid="8116608994995104836">"झटपट ऐप्स के लिए इंस्टॉलेशन ज़रूरी नहीं है."</string>
<string name="app_info" msgid="6856026610594615344">"ऐप की जानकारी"</string>
</resources>
diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml
index 2ce11af..7957f2c 100644
--- a/packages/SystemUI/res/values-hr/strings.xml
+++ b/packages/SystemUI/res/values-hr/strings.xml
@@ -695,9 +695,7 @@
<string name="notification_channel_screenshot" msgid="6314080179230000938">"Snimke zaslona"</string>
<string name="notification_channel_general" msgid="4525309436693914482">"Općenite poruke"</string>
<string name="notification_channel_storage" msgid="3077205683020695313">"Pohrana"</string>
- <!-- no translation found for instant_apps (6647570248119804907) -->
- <skip />
- <!-- no translation found for instant_apps_message (8116608994995104836) -->
- <skip />
+ <string name="instant_apps" msgid="6647570248119804907">"Instant aplikacije"</string>
+ <string name="instant_apps_message" msgid="8116608994995104836">"Instant aplikacije nije potrebno instalirati."</string>
<string name="app_info" msgid="6856026610594615344">"Informacije o aplikaciji"</string>
</resources>
diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml
index 288b25f..629867b 100644
--- a/packages/SystemUI/res/values-hu/strings.xml
+++ b/packages/SystemUI/res/values-hu/strings.xml
@@ -692,9 +692,7 @@
<string name="notification_channel_screenshot" msgid="6314080179230000938">"Képernyőképek"</string>
<string name="notification_channel_general" msgid="4525309436693914482">"Általános üzenetek"</string>
<string name="notification_channel_storage" msgid="3077205683020695313">"Tárhely"</string>
- <!-- no translation found for instant_apps (6647570248119804907) -->
- <skip />
- <!-- no translation found for instant_apps_message (8116608994995104836) -->
- <skip />
+ <string name="instant_apps" msgid="6647570248119804907">"Azonnali alkalmazások"</string>
+ <string name="instant_apps_message" msgid="8116608994995104836">"Az azonnali alkalmazásokat nem kell telepíteni."</string>
<string name="app_info" msgid="6856026610594615344">"Alkalmazásinformáció"</string>
</resources>
diff --git a/packages/SystemUI/res/values-hy/strings.xml b/packages/SystemUI/res/values-hy/strings.xml
index 3b8dac7..f090714 100644
--- a/packages/SystemUI/res/values-hy/strings.xml
+++ b/packages/SystemUI/res/values-hy/strings.xml
@@ -692,9 +692,7 @@
<string name="notification_channel_screenshot" msgid="6314080179230000938">"Էկրանի պատկերներ"</string>
<string name="notification_channel_general" msgid="4525309436693914482">"Ընդհանուր հաղորդագրություններ"</string>
<string name="notification_channel_storage" msgid="3077205683020695313">"Հիշողություն"</string>
- <!-- no translation found for instant_apps (6647570248119804907) -->
- <skip />
- <!-- no translation found for instant_apps_message (8116608994995104836) -->
- <skip />
+ <string name="instant_apps" msgid="6647570248119804907">"Ակնթարթորեն գործարկվող հավելվածներ"</string>
+ <string name="instant_apps_message" msgid="8116608994995104836">"Ակնթարթորեն գործարկվող հավելվածները տեղադրում չեն պահանջում։"</string>
<string name="app_info" msgid="6856026610594615344">"Հավելվածի տվյալներ"</string>
</resources>
diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml
index 8efc3a9..12acc55 100644
--- a/packages/SystemUI/res/values-in/strings.xml
+++ b/packages/SystemUI/res/values-in/strings.xml
@@ -692,9 +692,7 @@
<string name="notification_channel_screenshot" msgid="6314080179230000938">"Screenshot"</string>
<string name="notification_channel_general" msgid="4525309436693914482">"Pesan Umum"</string>
<string name="notification_channel_storage" msgid="3077205683020695313">"Penyimpanan"</string>
- <!-- no translation found for instant_apps (6647570248119804907) -->
- <skip />
- <!-- no translation found for instant_apps_message (8116608994995104836) -->
- <skip />
+ <string name="instant_apps" msgid="6647570248119804907">"Aplikasi Instan"</string>
+ <string name="instant_apps_message" msgid="8116608994995104836">"Aplikasi instan tidak perlu diinstal."</string>
<string name="app_info" msgid="6856026610594615344">"Info aplikasi"</string>
</resources>
diff --git a/packages/SystemUI/res/values-is/strings.xml b/packages/SystemUI/res/values-is/strings.xml
index c1fa058..a355771 100644
--- a/packages/SystemUI/res/values-is/strings.xml
+++ b/packages/SystemUI/res/values-is/strings.xml
@@ -692,9 +692,7 @@
<string name="notification_channel_screenshot" msgid="6314080179230000938">"Skjámyndir"</string>
<string name="notification_channel_general" msgid="4525309436693914482">"Almenn skilaboð"</string>
<string name="notification_channel_storage" msgid="3077205683020695313">"Geymslurými"</string>
- <!-- no translation found for instant_apps (6647570248119804907) -->
- <skip />
- <!-- no translation found for instant_apps_message (8116608994995104836) -->
- <skip />
+ <string name="instant_apps" msgid="6647570248119804907">"Skyndiforrit"</string>
+ <string name="instant_apps_message" msgid="8116608994995104836">"Skyndiforrit þurfa ekki uppsetningu."</string>
<string name="app_info" msgid="6856026610594615344">"Forritsupplýsingar"</string>
</resources>
diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml
index 481d80c..be648e7 100644
--- a/packages/SystemUI/res/values-it/strings.xml
+++ b/packages/SystemUI/res/values-it/strings.xml
@@ -694,9 +694,7 @@
<string name="notification_channel_screenshot" msgid="6314080179230000938">"Screenshot"</string>
<string name="notification_channel_general" msgid="4525309436693914482">"Messaggi generali"</string>
<string name="notification_channel_storage" msgid="3077205683020695313">"Spazio di archiviazione"</string>
- <!-- no translation found for instant_apps (6647570248119804907) -->
- <skip />
- <!-- no translation found for instant_apps_message (8116608994995104836) -->
- <skip />
+ <string name="instant_apps" msgid="6647570248119804907">"App istantanee"</string>
+ <string name="instant_apps_message" msgid="8116608994995104836">"Le app istantanee non richiedono l\'installazione."</string>
<string name="app_info" msgid="6856026610594615344">"Informazioni app"</string>
</resources>
diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml
index f22dec5..d20d590 100644
--- a/packages/SystemUI/res/values-iw/strings.xml
+++ b/packages/SystemUI/res/values-iw/strings.xml
@@ -698,9 +698,7 @@
<string name="notification_channel_screenshot" msgid="6314080179230000938">"צילומי מסך"</string>
<string name="notification_channel_general" msgid="4525309436693914482">"הודעות כלליות"</string>
<string name="notification_channel_storage" msgid="3077205683020695313">"אחסון"</string>
- <!-- no translation found for instant_apps (6647570248119804907) -->
- <skip />
- <!-- no translation found for instant_apps_message (8116608994995104836) -->
- <skip />
+ <string name="instant_apps" msgid="6647570248119804907">"אפליקציות אינסטנט"</string>
+ <string name="instant_apps_message" msgid="8116608994995104836">"אפליקציות אינסטנט לא דורשות התקנה."</string>
<string name="app_info" msgid="6856026610594615344">"פרטי אפליקציה"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml
index d4c381e..00405ac 100644
--- a/packages/SystemUI/res/values-ja/strings.xml
+++ b/packages/SystemUI/res/values-ja/strings.xml
@@ -694,9 +694,7 @@
<string name="notification_channel_screenshot" msgid="6314080179230000938">"スクリーンショット"</string>
<string name="notification_channel_general" msgid="4525309436693914482">"一般メッセージ"</string>
<string name="notification_channel_storage" msgid="3077205683020695313">"ストレージ"</string>
- <!-- no translation found for instant_apps (6647570248119804907) -->
- <skip />
- <!-- no translation found for instant_apps_message (8116608994995104836) -->
- <skip />
+ <string name="instant_apps" msgid="6647570248119804907">"Instant Apps"</string>
+ <string name="instant_apps_message" msgid="8116608994995104836">"Instant Apps はインストールせずに利用できます。"</string>
<string name="app_info" msgid="6856026610594615344">"アプリ情報"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ka/strings.xml b/packages/SystemUI/res/values-ka/strings.xml
index 674f308..b5bc2408 100644
--- a/packages/SystemUI/res/values-ka/strings.xml
+++ b/packages/SystemUI/res/values-ka/strings.xml
@@ -692,9 +692,7 @@
<string name="notification_channel_screenshot" msgid="6314080179230000938">"ეკრანის ანაბეჭდები"</string>
<string name="notification_channel_general" msgid="4525309436693914482">"ზოგადი შეტყობინებები"</string>
<string name="notification_channel_storage" msgid="3077205683020695313">"მეხსიერება"</string>
- <!-- no translation found for instant_apps (6647570248119804907) -->
- <skip />
- <!-- no translation found for instant_apps_message (8116608994995104836) -->
- <skip />
+ <string name="instant_apps" msgid="6647570248119804907">"მყისიერი აპები"</string>
+ <string name="instant_apps_message" msgid="8116608994995104836">"მყისიერი აპები ინსტალაციას არ საჭიროებს."</string>
<string name="app_info" msgid="6856026610594615344">"აპის შესახებ"</string>
</resources>
diff --git a/packages/SystemUI/res/values-kk/strings.xml b/packages/SystemUI/res/values-kk/strings.xml
index dba10da..3e5fe2d 100644
--- a/packages/SystemUI/res/values-kk/strings.xml
+++ b/packages/SystemUI/res/values-kk/strings.xml
@@ -692,9 +692,7 @@
<string name="notification_channel_screenshot" msgid="6314080179230000938">"Скриншоттар"</string>
<string name="notification_channel_general" msgid="4525309436693914482">"Жалпы хабарлар"</string>
<string name="notification_channel_storage" msgid="3077205683020695313">"Жад"</string>
- <!-- no translation found for instant_apps (6647570248119804907) -->
- <skip />
- <!-- no translation found for instant_apps_message (8116608994995104836) -->
- <skip />
+ <string name="instant_apps" msgid="6647570248119804907">"Instant Apps"</string>
+ <string name="instant_apps_message" msgid="8116608994995104836">"Лездік қолданбаларды орнатудың қажеті жоқ."</string>
<string name="app_info" msgid="6856026610594615344">"Қолданба ақпараты"</string>
</resources>
diff --git a/packages/SystemUI/res/values-km/strings.xml b/packages/SystemUI/res/values-km/strings.xml
index f91c80a..4856e3c 100644
--- a/packages/SystemUI/res/values-km/strings.xml
+++ b/packages/SystemUI/res/values-km/strings.xml
@@ -692,9 +692,7 @@
<string name="notification_channel_screenshot" msgid="6314080179230000938">"រូបថតអេក្រង់"</string>
<string name="notification_channel_general" msgid="4525309436693914482">"សារទូទៅ"</string>
<string name="notification_channel_storage" msgid="3077205683020695313">"ទំហំផ្ទុក"</string>
- <!-- no translation found for instant_apps (6647570248119804907) -->
- <skip />
- <!-- no translation found for instant_apps_message (8116608994995104836) -->
- <skip />
+ <string name="instant_apps" msgid="6647570248119804907">"កម្មវិធីប្រើភ្លាមៗ"</string>
+ <string name="instant_apps_message" msgid="8116608994995104836">"កម្មវិធីប្រើភ្លាមៗមិនតម្រូវឲ្យមានការដំឡើងទេ។"</string>
<string name="app_info" msgid="6856026610594615344">"ព័ត៌មានកម្មវិធី"</string>
</resources>
diff --git a/packages/SystemUI/res/values-kn/strings.xml b/packages/SystemUI/res/values-kn/strings.xml
index b94c0bf..65b89b8 100644
--- a/packages/SystemUI/res/values-kn/strings.xml
+++ b/packages/SystemUI/res/values-kn/strings.xml
@@ -692,9 +692,7 @@
<string name="notification_channel_screenshot" msgid="6314080179230000938">"ಸ್ಕ್ರೀನ್ಶಾಟ್ಗಳು"</string>
<string name="notification_channel_general" msgid="4525309436693914482">"ಸಾಮಾನ್ಯ ಸಂದೇಶಗಳು"</string>
<string name="notification_channel_storage" msgid="3077205683020695313">"ಸಂಗ್ರಹಣೆ"</string>
- <!-- no translation found for instant_apps (6647570248119804907) -->
- <skip />
- <!-- no translation found for instant_apps_message (8116608994995104836) -->
- <skip />
+ <string name="instant_apps" msgid="6647570248119804907">"ತತ್ಕ್ಷಣ ಆಪ್ಗಳು"</string>
+ <string name="instant_apps_message" msgid="8116608994995104836">"ತತ್ಕ್ಷಣ ಆಪ್ಗಳಿಗೆ ಸ್ಥಾಪನೆಯ ಅಗತ್ಯವಿಲ್ಲ."</string>
<string name="app_info" msgid="6856026610594615344">"ಅಪ್ಲಿಕೇಶನ್ ಮಾಹಿತಿ"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml
index d46c0af..9c277b0 100644
--- a/packages/SystemUI/res/values-ko/strings.xml
+++ b/packages/SystemUI/res/values-ko/strings.xml
@@ -694,9 +694,7 @@
<string name="notification_channel_screenshot" msgid="6314080179230000938">"스크린샷"</string>
<string name="notification_channel_general" msgid="4525309436693914482">"일반 메시지"</string>
<string name="notification_channel_storage" msgid="3077205683020695313">"저장소"</string>
- <!-- no translation found for instant_apps (6647570248119804907) -->
- <skip />
- <!-- no translation found for instant_apps_message (8116608994995104836) -->
- <skip />
+ <string name="instant_apps" msgid="6647570248119804907">"빠른 실행 앱"</string>
+ <string name="instant_apps_message" msgid="8116608994995104836">"빠른 실행 앱은 설치가 필요하지 않습니다."</string>
<string name="app_info" msgid="6856026610594615344">"앱 정보"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ky/strings.xml b/packages/SystemUI/res/values-ky/strings.xml
index ec61db1..9080df8 100644
--- a/packages/SystemUI/res/values-ky/strings.xml
+++ b/packages/SystemUI/res/values-ky/strings.xml
@@ -692,9 +692,7 @@
<string name="notification_channel_screenshot" msgid="6314080179230000938">"Скриншоттор"</string>
<string name="notification_channel_general" msgid="4525309436693914482">"Жалпы билдирүүлөр"</string>
<string name="notification_channel_storage" msgid="3077205683020695313">"Сактагыч"</string>
- <!-- no translation found for instant_apps (6647570248119804907) -->
- <skip />
- <!-- no translation found for instant_apps_message (8116608994995104836) -->
- <skip />
+ <string name="instant_apps" msgid="6647570248119804907">"Ыкчам ачылуучу колдонмолор"</string>
+ <string name="instant_apps_message" msgid="8116608994995104836">"Ыкчам ачылуучу колдонмолорду орнотуу талап кылынбайт."</string>
<string name="app_info" msgid="6856026610594615344">"Колдонмо тууралуу"</string>
</resources>
diff --git a/packages/SystemUI/res/values-lo/strings.xml b/packages/SystemUI/res/values-lo/strings.xml
index 87f008b..3ccbe92 100644
--- a/packages/SystemUI/res/values-lo/strings.xml
+++ b/packages/SystemUI/res/values-lo/strings.xml
@@ -692,9 +692,7 @@
<string name="notification_channel_screenshot" msgid="6314080179230000938">"ຮູບຖ່າຍໜ້າຈໍ"</string>
<string name="notification_channel_general" msgid="4525309436693914482">"ຂໍ້ຄວາມທົ່ວໄປ"</string>
<string name="notification_channel_storage" msgid="3077205683020695313">"ບ່ອນເກັບຂໍ້ມູນ"</string>
- <!-- no translation found for instant_apps (6647570248119804907) -->
- <skip />
- <!-- no translation found for instant_apps_message (8116608994995104836) -->
- <skip />
+ <string name="instant_apps" msgid="6647570248119804907">"ອິນສະແຕນແອັບ"</string>
+ <string name="instant_apps_message" msgid="8116608994995104836">"ອິນສະແຕນແອັບບໍ່ຈຳເປັນຕ້ອງມີການຕິດຕັ້ງ."</string>
<string name="app_info" msgid="6856026610594615344">"ຂໍ້ມູນແອັບ"</string>
</resources>
diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml
index f2df152..fa4ab0d 100644
--- a/packages/SystemUI/res/values-lt/strings.xml
+++ b/packages/SystemUI/res/values-lt/strings.xml
@@ -698,9 +698,7 @@
<string name="notification_channel_screenshot" msgid="6314080179230000938">"Ekrano kopijos"</string>
<string name="notification_channel_general" msgid="4525309436693914482">"Bendrieji pranešimai"</string>
<string name="notification_channel_storage" msgid="3077205683020695313">"Saugykla"</string>
- <!-- no translation found for instant_apps (6647570248119804907) -->
- <skip />
- <!-- no translation found for instant_apps_message (8116608994995104836) -->
- <skip />
+ <string name="instant_apps" msgid="6647570248119804907">"Akimirksniu įkeliamos programėlės"</string>
+ <string name="instant_apps_message" msgid="8116608994995104836">"Akimirksniu įkeliamų programėlių nereikia įdiegti."</string>
<string name="app_info" msgid="6856026610594615344">"Programos informacija"</string>
</resources>
diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml
index e5970d4..cb7c413 100644
--- a/packages/SystemUI/res/values-lv/strings.xml
+++ b/packages/SystemUI/res/values-lv/strings.xml
@@ -695,9 +695,7 @@
<string name="notification_channel_screenshot" msgid="6314080179230000938">"Ekrānuzņēmumi"</string>
<string name="notification_channel_general" msgid="4525309436693914482">"Vispārīgi ziņojumi"</string>
<string name="notification_channel_storage" msgid="3077205683020695313">"Krātuve"</string>
- <!-- no translation found for instant_apps (6647570248119804907) -->
- <skip />
- <!-- no translation found for instant_apps_message (8116608994995104836) -->
- <skip />
+ <string name="instant_apps" msgid="6647570248119804907">"Tūlītējās lietotnes"</string>
+ <string name="instant_apps_message" msgid="8116608994995104836">"Tūlītējām lietotnēm nav nepieciešama instalēšana."</string>
<string name="app_info" msgid="6856026610594615344">"Lietotnes informācija"</string>
</resources>
diff --git a/packages/SystemUI/res/values-mk/strings.xml b/packages/SystemUI/res/values-mk/strings.xml
index dc5f44d..cdadb0a 100644
--- a/packages/SystemUI/res/values-mk/strings.xml
+++ b/packages/SystemUI/res/values-mk/strings.xml
@@ -692,9 +692,7 @@
<string name="notification_channel_screenshot" msgid="6314080179230000938">"Слики од екранот"</string>
<string name="notification_channel_general" msgid="4525309436693914482">"Општи пораки"</string>
<string name="notification_channel_storage" msgid="3077205683020695313">"Меморија"</string>
- <!-- no translation found for instant_apps (6647570248119804907) -->
- <skip />
- <!-- no translation found for instant_apps_message (8116608994995104836) -->
- <skip />
+ <string name="instant_apps" msgid="6647570248119804907">"Инстант апликации"</string>
+ <string name="instant_apps_message" msgid="8116608994995104836">"Инстант апликациите нема потреба да се инсталираат."</string>
<string name="app_info" msgid="6856026610594615344">"Информации за апликација"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ml/strings.xml b/packages/SystemUI/res/values-ml/strings.xml
index 4e3da1b..38769cf 100644
--- a/packages/SystemUI/res/values-ml/strings.xml
+++ b/packages/SystemUI/res/values-ml/strings.xml
@@ -692,9 +692,7 @@
<string name="notification_channel_screenshot" msgid="6314080179230000938">"സ്ക്രീൻഷോട്ടുകൾ"</string>
<string name="notification_channel_general" msgid="4525309436693914482">"പൊതുവായ സന്ദേശങ്ങൾ"</string>
<string name="notification_channel_storage" msgid="3077205683020695313">"സ്റ്റോറേജ്"</string>
- <!-- no translation found for instant_apps (6647570248119804907) -->
- <skip />
- <!-- no translation found for instant_apps_message (8116608994995104836) -->
- <skip />
+ <string name="instant_apps" msgid="6647570248119804907">"ഇൻസ്റ്റന്റ് ആപ്പ്"</string>
+ <string name="instant_apps_message" msgid="8116608994995104836">"ഇൻസ്റ്റന്റ് ആപ്പിന് ഇൻസ്റ്റലേഷൻ ആവശ്യമില്ല."</string>
<string name="app_info" msgid="6856026610594615344">"ആപ്പ് വിവരം"</string>
</resources>
diff --git a/packages/SystemUI/res/values-mn/strings.xml b/packages/SystemUI/res/values-mn/strings.xml
index 1ec28b2..206a9cc 100644
--- a/packages/SystemUI/res/values-mn/strings.xml
+++ b/packages/SystemUI/res/values-mn/strings.xml
@@ -692,9 +692,7 @@
<string name="notification_channel_screenshot" msgid="6314080179230000938">"Дэлгэцийн зураг дарах"</string>
<string name="notification_channel_general" msgid="4525309436693914482">"Энгийн зурвас"</string>
<string name="notification_channel_storage" msgid="3077205683020695313">"Хадгалах сан"</string>
- <!-- no translation found for instant_apps (6647570248119804907) -->
- <skip />
- <!-- no translation found for instant_apps_message (8116608994995104836) -->
- <skip />
+ <string name="instant_apps" msgid="6647570248119804907">"Шуурхай апп"</string>
+ <string name="instant_apps_message" msgid="8116608994995104836">"Шуурхай аппыг суулгах шаардлагагүй."</string>
<string name="app_info" msgid="6856026610594615344">"Апп-н мэдээлэл"</string>
</resources>
diff --git a/packages/SystemUI/res/values-mr/strings.xml b/packages/SystemUI/res/values-mr/strings.xml
index cce2635..266d0c9 100644
--- a/packages/SystemUI/res/values-mr/strings.xml
+++ b/packages/SystemUI/res/values-mr/strings.xml
@@ -692,9 +692,7 @@
<string name="notification_channel_screenshot" msgid="6314080179230000938">"स्क्रीनशॉट"</string>
<string name="notification_channel_general" msgid="4525309436693914482">"सर्वसाधारण संदेश"</string>
<string name="notification_channel_storage" msgid="3077205683020695313">"संचय"</string>
- <!-- no translation found for instant_apps (6647570248119804907) -->
- <skip />
- <!-- no translation found for instant_apps_message (8116608994995104836) -->
- <skip />
+ <string name="instant_apps" msgid="6647570248119804907">"इन्सटंट अॅप्स"</string>
+ <string name="instant_apps_message" msgid="8116608994995104836">"इन्सटंट अॅप्सना स्थापनेची आवश्यकता नसते."</string>
<string name="app_info" msgid="6856026610594615344">"अॅप माहिती"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ms/strings.xml b/packages/SystemUI/res/values-ms/strings.xml
index afc9541..441b4c1 100644
--- a/packages/SystemUI/res/values-ms/strings.xml
+++ b/packages/SystemUI/res/values-ms/strings.xml
@@ -692,9 +692,7 @@
<string name="notification_channel_screenshot" msgid="6314080179230000938">"Tangkapan skrin"</string>
<string name="notification_channel_general" msgid="4525309436693914482">"Mesej Am"</string>
<string name="notification_channel_storage" msgid="3077205683020695313">"Storan"</string>
- <!-- no translation found for instant_apps (6647570248119804907) -->
- <skip />
- <!-- no translation found for instant_apps_message (8116608994995104836) -->
- <skip />
+ <string name="instant_apps" msgid="6647570248119804907">"Apl Segera"</string>
+ <string name="instant_apps_message" msgid="8116608994995104836">"Apl segera tidak memerlukan pemasangan."</string>
<string name="app_info" msgid="6856026610594615344">"Maklumat apl"</string>
</resources>
diff --git a/packages/SystemUI/res/values-my/strings.xml b/packages/SystemUI/res/values-my/strings.xml
index 26cc72c..9b9359e 100644
--- a/packages/SystemUI/res/values-my/strings.xml
+++ b/packages/SystemUI/res/values-my/strings.xml
@@ -692,9 +692,7 @@
<string name="notification_channel_screenshot" msgid="6314080179230000938">"မျက်နှာပြင်ဓာတ်ပုံများ"</string>
<string name="notification_channel_general" msgid="4525309436693914482">"အထွေထွေ မက်ဆေ့ဂျ်များ"</string>
<string name="notification_channel_storage" msgid="3077205683020695313">"သိုလှောင်မှုများ"</string>
- <!-- no translation found for instant_apps (6647570248119804907) -->
- <skip />
- <!-- no translation found for instant_apps_message (8116608994995104836) -->
- <skip />
+ <string name="instant_apps" msgid="6647570248119804907">"Instant Apps"</string>
+ <string name="instant_apps_message" msgid="8116608994995104836">"ချက်ခြင်းသုံးအက်ပ်များကို ထည့်သွင်းစရာမလိုပါ။"</string>
<string name="app_info" msgid="6856026610594615344">"အက်ပ်အချက်အလက်"</string>
</resources>
diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml
index ccee80e..1744729 100644
--- a/packages/SystemUI/res/values-nb/strings.xml
+++ b/packages/SystemUI/res/values-nb/strings.xml
@@ -692,9 +692,7 @@
<string name="notification_channel_screenshot" msgid="6314080179230000938">"Skjermdumper"</string>
<string name="notification_channel_general" msgid="4525309436693914482">"Generelle meldinger"</string>
<string name="notification_channel_storage" msgid="3077205683020695313">"Lagring"</string>
- <!-- no translation found for instant_apps (6647570248119804907) -->
- <skip />
- <!-- no translation found for instant_apps_message (8116608994995104836) -->
- <skip />
+ <string name="instant_apps" msgid="6647570248119804907">"Instant Apps"</string>
+ <string name="instant_apps_message" msgid="8116608994995104836">"Du trenger ikke å installere instant-apper."</string>
<string name="app_info" msgid="6856026610594615344">"Info om appen"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ne/strings.xml b/packages/SystemUI/res/values-ne/strings.xml
index cc63dfb..a634b91 100644
--- a/packages/SystemUI/res/values-ne/strings.xml
+++ b/packages/SystemUI/res/values-ne/strings.xml
@@ -692,9 +692,7 @@
<string name="notification_channel_screenshot" msgid="6314080179230000938">"स्क्रिनशटहरू"</string>
<string name="notification_channel_general" msgid="4525309436693914482">"सामान्य सन्देशहरू"</string>
<string name="notification_channel_storage" msgid="3077205683020695313">"भण्डारण"</string>
- <!-- no translation found for instant_apps (6647570248119804907) -->
- <skip />
- <!-- no translation found for instant_apps_message (8116608994995104836) -->
- <skip />
+ <string name="instant_apps" msgid="6647570248119804907">"तात्कालिक अनुप्रयोगहरू"</string>
+ <string name="instant_apps_message" msgid="8116608994995104836">"तात्कालिक अनुप्रयोगहरूलाई स्थापना गर्नु पर्दैन|"</string>
<string name="app_info" msgid="6856026610594615344">"अनुप्रयोगका बारे जानकारी"</string>
</resources>
diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml
index 3fdf5a4..b5b741c 100644
--- a/packages/SystemUI/res/values-nl/strings.xml
+++ b/packages/SystemUI/res/values-nl/strings.xml
@@ -692,9 +692,7 @@
<string name="notification_channel_screenshot" msgid="6314080179230000938">"Screenshots"</string>
<string name="notification_channel_general" msgid="4525309436693914482">"Algemene berichten"</string>
<string name="notification_channel_storage" msgid="3077205683020695313">"Opslag"</string>
- <!-- no translation found for instant_apps (6647570248119804907) -->
- <skip />
- <!-- no translation found for instant_apps_message (8116608994995104836) -->
- <skip />
+ <string name="instant_apps" msgid="6647570248119804907">"Instant-apps"</string>
+ <string name="instant_apps_message" msgid="8116608994995104836">"Instant-apps hoeven niet te worden geïnstalleerd."</string>
<string name="app_info" msgid="6856026610594615344">"App-info"</string>
</resources>
diff --git a/packages/SystemUI/res/values-pa/strings.xml b/packages/SystemUI/res/values-pa/strings.xml
index bcdfb4c..abd0a70 100644
--- a/packages/SystemUI/res/values-pa/strings.xml
+++ b/packages/SystemUI/res/values-pa/strings.xml
@@ -692,9 +692,7 @@
<string name="notification_channel_screenshot" msgid="6314080179230000938">"ਸਕ੍ਰੀਨਸ਼ਾਟ"</string>
<string name="notification_channel_general" msgid="4525309436693914482">"ਆਮ ਸੁਨੇਹੇ"</string>
<string name="notification_channel_storage" msgid="3077205683020695313">"ਸਟੋਰੇਜ"</string>
- <!-- no translation found for instant_apps (6647570248119804907) -->
- <skip />
- <!-- no translation found for instant_apps_message (8116608994995104836) -->
- <skip />
+ <string name="instant_apps" msgid="6647570248119804907">"ਤਤਕਾਲ ਐਪਾਂ"</string>
+ <string name="instant_apps_message" msgid="8116608994995104836">"ਤਤਕਾਲ ਐਪਾਂ ਨੂੰ ਸਥਾਪਨਾ ਦੀ ਲੋੜ ਨਹੀਂ ਹੈ।"</string>
<string name="app_info" msgid="6856026610594615344">"ਐਪ ਜਾਣਕਾਰੀ"</string>
</resources>
diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml
index d2bf88e..09159ab 100644
--- a/packages/SystemUI/res/values-pl/strings.xml
+++ b/packages/SystemUI/res/values-pl/strings.xml
@@ -698,9 +698,7 @@
<string name="notification_channel_screenshot" msgid="6314080179230000938">"Zrzuty ekranu"</string>
<string name="notification_channel_general" msgid="4525309436693914482">"Wiadomości"</string>
<string name="notification_channel_storage" msgid="3077205683020695313">"Miejsce"</string>
- <!-- no translation found for instant_apps (6647570248119804907) -->
- <skip />
- <!-- no translation found for instant_apps_message (8116608994995104836) -->
- <skip />
+ <string name="instant_apps" msgid="6647570248119804907">"Aplikacje błyskawiczne"</string>
+ <string name="instant_apps_message" msgid="8116608994995104836">"Aplikacji błyskawicznych nie trzeba instalować."</string>
<string name="app_info" msgid="6856026610594615344">"O aplikacji"</string>
</resources>
diff --git a/packages/SystemUI/res/values-pt-rBR/strings.xml b/packages/SystemUI/res/values-pt-rBR/strings.xml
index 56ec9bc..19c3c28 100644
--- a/packages/SystemUI/res/values-pt-rBR/strings.xml
+++ b/packages/SystemUI/res/values-pt-rBR/strings.xml
@@ -694,9 +694,7 @@
<string name="notification_channel_screenshot" msgid="6314080179230000938">"Capturas de tela"</string>
<string name="notification_channel_general" msgid="4525309436693914482">"Mensagens gerais"</string>
<string name="notification_channel_storage" msgid="3077205683020695313">"Armazenamento"</string>
- <!-- no translation found for instant_apps (6647570248119804907) -->
- <skip />
- <!-- no translation found for instant_apps_message (8116608994995104836) -->
- <skip />
+ <string name="instant_apps" msgid="6647570248119804907">"Instant Apps"</string>
+ <string name="instant_apps_message" msgid="8116608994995104836">"Os Instant Apps não requerem instalação."</string>
<string name="app_info" msgid="6856026610594615344">"Informações do app"</string>
</resources>
diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml
index 4daf104..d221f3a 100644
--- a/packages/SystemUI/res/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res/values-pt-rPT/strings.xml
@@ -692,9 +692,7 @@
<string name="notification_channel_screenshot" msgid="6314080179230000938">"Capturas de ecrã"</string>
<string name="notification_channel_general" msgid="4525309436693914482">"Mensagens gerais"</string>
<string name="notification_channel_storage" msgid="3077205683020695313">"Armazenamento"</string>
- <!-- no translation found for instant_apps (6647570248119804907) -->
- <skip />
- <!-- no translation found for instant_apps_message (8116608994995104836) -->
- <skip />
+ <string name="instant_apps" msgid="6647570248119804907">"Aplicações instantâneas"</string>
+ <string name="instant_apps_message" msgid="8116608994995104836">"As Aplicações instantâneas não requerem instalação."</string>
<string name="app_info" msgid="6856026610594615344">"Informações da aplicação"</string>
</resources>
diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml
index 56ec9bc..19c3c28 100644
--- a/packages/SystemUI/res/values-pt/strings.xml
+++ b/packages/SystemUI/res/values-pt/strings.xml
@@ -694,9 +694,7 @@
<string name="notification_channel_screenshot" msgid="6314080179230000938">"Capturas de tela"</string>
<string name="notification_channel_general" msgid="4525309436693914482">"Mensagens gerais"</string>
<string name="notification_channel_storage" msgid="3077205683020695313">"Armazenamento"</string>
- <!-- no translation found for instant_apps (6647570248119804907) -->
- <skip />
- <!-- no translation found for instant_apps_message (8116608994995104836) -->
- <skip />
+ <string name="instant_apps" msgid="6647570248119804907">"Instant Apps"</string>
+ <string name="instant_apps_message" msgid="8116608994995104836">"Os Instant Apps não requerem instalação."</string>
<string name="app_info" msgid="6856026610594615344">"Informações do app"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml
index 2315e3b..2f32f6b 100644
--- a/packages/SystemUI/res/values-ro/strings.xml
+++ b/packages/SystemUI/res/values-ro/strings.xml
@@ -697,9 +697,7 @@
<string name="notification_channel_screenshot" msgid="6314080179230000938">"Capturi de ecran"</string>
<string name="notification_channel_general" msgid="4525309436693914482">"Mesaje generale"</string>
<string name="notification_channel_storage" msgid="3077205683020695313">"Stocare"</string>
- <!-- no translation found for instant_apps (6647570248119804907) -->
- <skip />
- <!-- no translation found for instant_apps_message (8116608994995104836) -->
- <skip />
+ <string name="instant_apps" msgid="6647570248119804907">"Aplicații instantanee"</string>
+ <string name="instant_apps_message" msgid="8116608994995104836">"Aplicațiile instantanee nu necesită instalare."</string>
<string name="app_info" msgid="6856026610594615344">"Informații despre aplicație"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml
index ab26879..744e322 100644
--- a/packages/SystemUI/res/values-ru/strings.xml
+++ b/packages/SystemUI/res/values-ru/strings.xml
@@ -700,9 +700,7 @@
<string name="notification_channel_screenshot" msgid="6314080179230000938">"Скриншоты"</string>
<string name="notification_channel_general" msgid="4525309436693914482">"Сообщения"</string>
<string name="notification_channel_storage" msgid="3077205683020695313">"Хранилище"</string>
- <!-- no translation found for instant_apps (6647570248119804907) -->
- <skip />
- <!-- no translation found for instant_apps_message (8116608994995104836) -->
- <skip />
+ <string name="instant_apps" msgid="6647570248119804907">"Приложения с мгновенным запуском"</string>
+ <string name="instant_apps_message" msgid="8116608994995104836">"Приложения с мгновенным запуском не требуется устанавливать."</string>
<string name="app_info" msgid="6856026610594615344">"О приложении"</string>
</resources>
diff --git a/packages/SystemUI/res/values-si/strings.xml b/packages/SystemUI/res/values-si/strings.xml
index 5040eb7..1b60299 100644
--- a/packages/SystemUI/res/values-si/strings.xml
+++ b/packages/SystemUI/res/values-si/strings.xml
@@ -692,9 +692,7 @@
<string name="notification_channel_screenshot" msgid="6314080179230000938">"තිර රු"</string>
<string name="notification_channel_general" msgid="4525309436693914482">"පොදු පණිවිඩ"</string>
<string name="notification_channel_storage" msgid="3077205683020695313">"ගබඩාව"</string>
- <!-- no translation found for instant_apps (6647570248119804907) -->
- <skip />
- <!-- no translation found for instant_apps_message (8116608994995104836) -->
- <skip />
+ <string name="instant_apps" msgid="6647570248119804907">"ක්ෂණික යෙදුම්"</string>
+ <string name="instant_apps_message" msgid="8116608994995104836">"ක්ෂණික යෙදුම් ස්ථාපනය කිරීම අවශ්ය නොවේ."</string>
<string name="app_info" msgid="6856026610594615344">"යෙදුම් තොරතුරු"</string>
</resources>
diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml
index 5e163c2..4ff18ba 100644
--- a/packages/SystemUI/res/values-sk/strings.xml
+++ b/packages/SystemUI/res/values-sk/strings.xml
@@ -700,9 +700,7 @@
<string name="notification_channel_screenshot" msgid="6314080179230000938">"Snímky obrazovky"</string>
<string name="notification_channel_general" msgid="4525309436693914482">"Všeobecné správy"</string>
<string name="notification_channel_storage" msgid="3077205683020695313">"Úložisko"</string>
- <!-- no translation found for instant_apps (6647570248119804907) -->
- <skip />
- <!-- no translation found for instant_apps_message (8116608994995104836) -->
- <skip />
+ <string name="instant_apps" msgid="6647570248119804907">"Okamžité aplikácie"</string>
+ <string name="instant_apps_message" msgid="8116608994995104836">"Okamžité aplikácie nevyžadujú inštaláciu."</string>
<string name="app_info" msgid="6856026610594615344">"Info o aplikácii"</string>
</resources>
diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml
index ee33c0b..a689699 100644
--- a/packages/SystemUI/res/values-sl/strings.xml
+++ b/packages/SystemUI/res/values-sl/strings.xml
@@ -700,9 +700,7 @@
<string name="notification_channel_screenshot" msgid="6314080179230000938">"Posnetki zaslona"</string>
<string name="notification_channel_general" msgid="4525309436693914482">"Splošna sporočila"</string>
<string name="notification_channel_storage" msgid="3077205683020695313">"Shramba"</string>
- <!-- no translation found for instant_apps (6647570248119804907) -->
- <skip />
- <!-- no translation found for instant_apps_message (8116608994995104836) -->
- <skip />
+ <string name="instant_apps" msgid="6647570248119804907">"Aplikacije brez nameščanja"</string>
+ <string name="instant_apps_message" msgid="8116608994995104836">"Aplikacij brez nameščanja ni treba namestiti."</string>
<string name="app_info" msgid="6856026610594615344">"Podatki o aplikaciji"</string>
</resources>
diff --git a/packages/SystemUI/res/values-sq/strings.xml b/packages/SystemUI/res/values-sq/strings.xml
index aab5942..757714fa 100644
--- a/packages/SystemUI/res/values-sq/strings.xml
+++ b/packages/SystemUI/res/values-sq/strings.xml
@@ -692,9 +692,7 @@
<string name="notification_channel_screenshot" msgid="6314080179230000938">"Pamjet e ekranit"</string>
<string name="notification_channel_general" msgid="4525309436693914482">"Mesazhe të përgjithshme"</string>
<string name="notification_channel_storage" msgid="3077205683020695313">"Hapësira ruajtëse"</string>
- <!-- no translation found for instant_apps (6647570248119804907) -->
- <skip />
- <!-- no translation found for instant_apps_message (8116608994995104836) -->
- <skip />
+ <string name="instant_apps" msgid="6647570248119804907">"Aplikacionet e çastit"</string>
+ <string name="instant_apps_message" msgid="8116608994995104836">"Aplikacionet e çastit nuk kërkojnë instalim."</string>
<string name="app_info" msgid="6856026610594615344">"Informacioni mbi aplikacionin"</string>
</resources>
diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml
index 0d6aa7b..f02e935 100644
--- a/packages/SystemUI/res/values-sr/strings.xml
+++ b/packages/SystemUI/res/values-sr/strings.xml
@@ -695,9 +695,7 @@
<string name="notification_channel_screenshot" msgid="6314080179230000938">"Снимци екрана"</string>
<string name="notification_channel_general" msgid="4525309436693914482">"Опште поруке"</string>
<string name="notification_channel_storage" msgid="3077205683020695313">"Меморијски простор"</string>
- <!-- no translation found for instant_apps (6647570248119804907) -->
- <skip />
- <!-- no translation found for instant_apps_message (8116608994995104836) -->
- <skip />
+ <string name="instant_apps" msgid="6647570248119804907">"Инстант апликације"</string>
+ <string name="instant_apps_message" msgid="8116608994995104836">"Инстант апликације не захтевају инсталацију."</string>
<string name="app_info" msgid="6856026610594615344">"Информације о апликацији"</string>
</resources>
diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml
index fb8df95..6778c73 100644
--- a/packages/SystemUI/res/values-sv/strings.xml
+++ b/packages/SystemUI/res/values-sv/strings.xml
@@ -692,9 +692,7 @@
<string name="notification_channel_screenshot" msgid="6314080179230000938">"Skärmdumpar"</string>
<string name="notification_channel_general" msgid="4525309436693914482">"Allmänna meddelanden"</string>
<string name="notification_channel_storage" msgid="3077205683020695313">"Lagring"</string>
- <!-- no translation found for instant_apps (6647570248119804907) -->
- <skip />
- <!-- no translation found for instant_apps_message (8116608994995104836) -->
- <skip />
+ <string name="instant_apps" msgid="6647570248119804907">"Instant Apps"</string>
+ <string name="instant_apps_message" msgid="8116608994995104836">"Snabbappar behöver inte installeras."</string>
<string name="app_info" msgid="6856026610594615344">"Info om appen"</string>
</resources>
diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml
index 15cc6aa..f97a582 100644
--- a/packages/SystemUI/res/values-sw/strings.xml
+++ b/packages/SystemUI/res/values-sw/strings.xml
@@ -692,9 +692,7 @@
<string name="notification_channel_screenshot" msgid="6314080179230000938">"Picha za skrini"</string>
<string name="notification_channel_general" msgid="4525309436693914482">"Ujumbe wa Jumla"</string>
<string name="notification_channel_storage" msgid="3077205683020695313">"Hifadhi"</string>
- <!-- no translation found for instant_apps (6647570248119804907) -->
- <skip />
- <!-- no translation found for instant_apps_message (8116608994995104836) -->
- <skip />
+ <string name="instant_apps" msgid="6647570248119804907">"Programu Zinazofunguka Papo Hapo"</string>
+ <string name="instant_apps_message" msgid="8116608994995104836">"Huhitaji kusakinisha programu zinazofunguka papo hapo."</string>
<string name="app_info" msgid="6856026610594615344">"Maelezo ya programu"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ta/strings.xml b/packages/SystemUI/res/values-ta/strings.xml
index 20ba620..c7166bd 100644
--- a/packages/SystemUI/res/values-ta/strings.xml
+++ b/packages/SystemUI/res/values-ta/strings.xml
@@ -692,9 +692,7 @@
<string name="notification_channel_screenshot" msgid="6314080179230000938">"ஸ்கிரீன் ஷாட்டுகள்"</string>
<string name="notification_channel_general" msgid="4525309436693914482">"பொதுச் செய்திகள்"</string>
<string name="notification_channel_storage" msgid="3077205683020695313">"சேமிப்பிடம்"</string>
- <!-- no translation found for instant_apps (6647570248119804907) -->
- <skip />
- <!-- no translation found for instant_apps_message (8116608994995104836) -->
- <skip />
+ <string name="instant_apps" msgid="6647570248119804907">"இன்ஸ்டண்ட் பயன்பாடுகள்"</string>
+ <string name="instant_apps_message" msgid="8116608994995104836">"இன்ஸ்டண்ட் பயன்பாடுகளுக்கு நிறுவல் தேவையில்லை."</string>
<string name="app_info" msgid="6856026610594615344">"பயன்பாட்டுத் தகவல்"</string>
</resources>
diff --git a/packages/SystemUI/res/values-te/strings.xml b/packages/SystemUI/res/values-te/strings.xml
index e824a35..e55fa84 100644
--- a/packages/SystemUI/res/values-te/strings.xml
+++ b/packages/SystemUI/res/values-te/strings.xml
@@ -692,9 +692,7 @@
<string name="notification_channel_screenshot" msgid="6314080179230000938">"స్క్రీన్షాట్లు"</string>
<string name="notification_channel_general" msgid="4525309436693914482">"సాధారణ సందేశాలు"</string>
<string name="notification_channel_storage" msgid="3077205683020695313">"నిల్వ"</string>
- <!-- no translation found for instant_apps (6647570248119804907) -->
- <skip />
- <!-- no translation found for instant_apps_message (8116608994995104836) -->
- <skip />
+ <string name="instant_apps" msgid="6647570248119804907">"తక్షణ అనువర్తనాలు"</string>
+ <string name="instant_apps_message" msgid="8116608994995104836">"తక్షణ అనువర్తనాలకు ఇన్స్టాలేషన్ అవసరం లేదు."</string>
<string name="app_info" msgid="6856026610594615344">"అనువర్తన సమాచారం"</string>
</resources>
diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml
index 667b106..c501195 100644
--- a/packages/SystemUI/res/values-th/strings.xml
+++ b/packages/SystemUI/res/values-th/strings.xml
@@ -692,9 +692,7 @@
<string name="notification_channel_screenshot" msgid="6314080179230000938">"ภาพหน้าจอ"</string>
<string name="notification_channel_general" msgid="4525309436693914482">"ข้อความทั่วไป"</string>
<string name="notification_channel_storage" msgid="3077205683020695313">"พื้นที่เก็บข้อมูล"</string>
- <!-- no translation found for instant_apps (6647570248119804907) -->
- <skip />
- <!-- no translation found for instant_apps_message (8116608994995104836) -->
- <skip />
+ <string name="instant_apps" msgid="6647570248119804907">"Instant App"</string>
+ <string name="instant_apps_message" msgid="8116608994995104836">"Instant Apps ไม่ต้องใช้การติดตั้ง"</string>
<string name="app_info" msgid="6856026610594615344">"ข้อมูลแอป"</string>
</resources>
diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml
index 2f6fdb2..1789606 100644
--- a/packages/SystemUI/res/values-tl/strings.xml
+++ b/packages/SystemUI/res/values-tl/strings.xml
@@ -692,9 +692,7 @@
<string name="notification_channel_screenshot" msgid="6314080179230000938">"Mga Screenshot"</string>
<string name="notification_channel_general" msgid="4525309436693914482">"Mga Pangkalahatang Mensahe"</string>
<string name="notification_channel_storage" msgid="3077205683020695313">"Storage"</string>
- <!-- no translation found for instant_apps (6647570248119804907) -->
- <skip />
- <!-- no translation found for instant_apps_message (8116608994995104836) -->
- <skip />
+ <string name="instant_apps" msgid="6647570248119804907">"Instant Apps"</string>
+ <string name="instant_apps_message" msgid="8116608994995104836">"Hindi kailangang i-install ang mga instant na app."</string>
<string name="app_info" msgid="6856026610594615344">"Impormasyon ng app"</string>
</resources>
diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml
index b2e7365..7675450 100644
--- a/packages/SystemUI/res/values-tr/strings.xml
+++ b/packages/SystemUI/res/values-tr/strings.xml
@@ -692,9 +692,7 @@
<string name="notification_channel_screenshot" msgid="6314080179230000938">"Ekran görüntüleri"</string>
<string name="notification_channel_general" msgid="4525309436693914482">"Genel Mesajlar"</string>
<string name="notification_channel_storage" msgid="3077205683020695313">"Depolama alanı"</string>
- <!-- no translation found for instant_apps (6647570248119804907) -->
- <skip />
- <!-- no translation found for instant_apps_message (8116608994995104836) -->
- <skip />
+ <string name="instant_apps" msgid="6647570248119804907">"Hazır Uygulamalar"</string>
+ <string name="instant_apps_message" msgid="8116608994995104836">"Hazır uygulamaların yüklenmesi gerekmez."</string>
<string name="app_info" msgid="6856026610594615344">"Uygulama bilgileri"</string>
</resources>
diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml
index 7eb84e4..774a663 100644
--- a/packages/SystemUI/res/values-uk/strings.xml
+++ b/packages/SystemUI/res/values-uk/strings.xml
@@ -700,9 +700,7 @@
<string name="notification_channel_screenshot" msgid="6314080179230000938">"Знімки екрана"</string>
<string name="notification_channel_general" msgid="4525309436693914482">"Загальні повідомлення"</string>
<string name="notification_channel_storage" msgid="3077205683020695313">"Пам’ять"</string>
- <!-- no translation found for instant_apps (6647570248119804907) -->
- <skip />
- <!-- no translation found for instant_apps_message (8116608994995104836) -->
- <skip />
+ <string name="instant_apps" msgid="6647570248119804907">"Додатки з миттєвим запуском"</string>
+ <string name="instant_apps_message" msgid="8116608994995104836">"Додатки з миттєвим запуском не потрібно встановлювати."</string>
<string name="app_info" msgid="6856026610594615344">"Про додаток"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ur/strings.xml b/packages/SystemUI/res/values-ur/strings.xml
index 6a0b92b..ee42e12 100644
--- a/packages/SystemUI/res/values-ur/strings.xml
+++ b/packages/SystemUI/res/values-ur/strings.xml
@@ -692,9 +692,7 @@
<string name="notification_channel_screenshot" msgid="6314080179230000938">"اسکرین شاٹس"</string>
<string name="notification_channel_general" msgid="4525309436693914482">"عمومی پیغامات"</string>
<string name="notification_channel_storage" msgid="3077205683020695313">"اسٹوریج"</string>
- <!-- no translation found for instant_apps (6647570248119804907) -->
- <skip />
- <!-- no translation found for instant_apps_message (8116608994995104836) -->
- <skip />
+ <string name="instant_apps" msgid="6647570248119804907">"فوری ایپس"</string>
+ <string name="instant_apps_message" msgid="8116608994995104836">"فوری ایپس کو انسٹالیشن کی ضرورت نہیں ہے۔"</string>
<string name="app_info" msgid="6856026610594615344">"ایپ کی معلومات"</string>
</resources>
diff --git a/packages/SystemUI/res/values-uz/strings.xml b/packages/SystemUI/res/values-uz/strings.xml
index 810902d..28bb21a 100644
--- a/packages/SystemUI/res/values-uz/strings.xml
+++ b/packages/SystemUI/res/values-uz/strings.xml
@@ -694,9 +694,7 @@
<string name="notification_channel_screenshot" msgid="6314080179230000938">"Skrinshotlar"</string>
<string name="notification_channel_general" msgid="4525309436693914482">"Umumiy xabarlar"</string>
<string name="notification_channel_storage" msgid="3077205683020695313">"Xotira"</string>
- <!-- no translation found for instant_apps (6647570248119804907) -->
- <skip />
- <!-- no translation found for instant_apps_message (8116608994995104836) -->
- <skip />
+ <string name="instant_apps" msgid="6647570248119804907">"Darhol ochiladigan ilovalar"</string>
+ <string name="instant_apps_message" msgid="8116608994995104836">"Darhol ochiladigan ilovalarni o‘rnatish shart emas."</string>
<string name="app_info" msgid="6856026610594615344">"Ilova haqida"</string>
</resources>
diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml
index a3ac98e..82b614d 100644
--- a/packages/SystemUI/res/values-vi/strings.xml
+++ b/packages/SystemUI/res/values-vi/strings.xml
@@ -694,9 +694,7 @@
<string name="notification_channel_screenshot" msgid="6314080179230000938">"Ảnh chụp màn hình"</string>
<string name="notification_channel_general" msgid="4525309436693914482">"Thông báo chung"</string>
<string name="notification_channel_storage" msgid="3077205683020695313">"Bộ nhớ"</string>
- <!-- no translation found for instant_apps (6647570248119804907) -->
- <skip />
- <!-- no translation found for instant_apps_message (8116608994995104836) -->
- <skip />
+ <string name="instant_apps" msgid="6647570248119804907">"Ứng dụng tức thì"</string>
+ <string name="instant_apps_message" msgid="8116608994995104836">"Ứng dụng tức thì không yêu cầu cài đặt."</string>
<string name="app_info" msgid="6856026610594615344">"Thông tin ứng dụng"</string>
</resources>
diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml
index 30db51a..9c7435a 100644
--- a/packages/SystemUI/res/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res/values-zh-rCN/strings.xml
@@ -692,9 +692,7 @@
<string name="notification_channel_screenshot" msgid="6314080179230000938">"屏幕截图"</string>
<string name="notification_channel_general" msgid="4525309436693914482">"常规消息"</string>
<string name="notification_channel_storage" msgid="3077205683020695313">"存储空间"</string>
- <!-- no translation found for instant_apps (6647570248119804907) -->
- <skip />
- <!-- no translation found for instant_apps_message (8116608994995104836) -->
- <skip />
+ <string name="instant_apps" msgid="6647570248119804907">"免安装应用"</string>
+ <string name="instant_apps_message" msgid="8116608994995104836">"免安装应用无需安装就能使用。"</string>
<string name="app_info" msgid="6856026610594615344">"应用信息"</string>
</resources>
diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml
index ee1dbb7..26fc99b 100644
--- a/packages/SystemUI/res/values-zh-rHK/strings.xml
+++ b/packages/SystemUI/res/values-zh-rHK/strings.xml
@@ -694,9 +694,7 @@
<string name="notification_channel_screenshot" msgid="6314080179230000938">"螢幕擷取畫面"</string>
<string name="notification_channel_general" msgid="4525309436693914482">"一般訊息"</string>
<string name="notification_channel_storage" msgid="3077205683020695313">"儲存空間"</string>
- <!-- no translation found for instant_apps (6647570248119804907) -->
- <skip />
- <!-- no translation found for instant_apps_message (8116608994995104836) -->
- <skip />
+ <string name="instant_apps" msgid="6647570248119804907">"即時應用程式"</string>
+ <string name="instant_apps_message" msgid="8116608994995104836">"即時應用程式無需安裝即可使用。"</string>
<string name="app_info" msgid="6856026610594615344">"應用程式資料"</string>
</resources>
diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml
index 35468dd..fc756f4 100644
--- a/packages/SystemUI/res/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res/values-zh-rTW/strings.xml
@@ -692,9 +692,7 @@
<string name="notification_channel_screenshot" msgid="6314080179230000938">"螢幕擷取畫面"</string>
<string name="notification_channel_general" msgid="4525309436693914482">"一般訊息"</string>
<string name="notification_channel_storage" msgid="3077205683020695313">"儲存空間"</string>
- <!-- no translation found for instant_apps (6647570248119804907) -->
- <skip />
- <!-- no translation found for instant_apps_message (8116608994995104836) -->
- <skip />
+ <string name="instant_apps" msgid="6647570248119804907">"免安裝應用程式"</string>
+ <string name="instant_apps_message" msgid="8116608994995104836">"免安裝應用程式不必安裝就能使用。"</string>
<string name="app_info" msgid="6856026610594615344">"應用程式資訊"</string>
</resources>
diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml
index 6007ea2..38580ec 100644
--- a/packages/SystemUI/res/values-zu/strings.xml
+++ b/packages/SystemUI/res/values-zu/strings.xml
@@ -692,9 +692,7 @@
<string name="notification_channel_screenshot" msgid="6314080179230000938">"Izithombe-skrini"</string>
<string name="notification_channel_general" msgid="4525309436693914482">"Imilayezo ejwayelekile"</string>
<string name="notification_channel_storage" msgid="3077205683020695313">"Isitoreji"</string>
- <!-- no translation found for instant_apps (6647570248119804907) -->
- <skip />
- <!-- no translation found for instant_apps_message (8116608994995104836) -->
- <skip />
+ <string name="instant_apps" msgid="6647570248119804907">"Izinhlelo zokusebenza ezisheshayo"</string>
+ <string name="instant_apps_message" msgid="8116608994995104836">"Izinhlelo zokusebenza ezisheshayo azidingi ukufakwa."</string>
<string name="app_info" msgid="6856026610594615344">"Ulwazi lohlelo lokusebenza"</string>
</resources>
diff --git a/packages/SystemUI/res/values/arrays_tv.xml b/packages/SystemUI/res/values/arrays_tv.xml
new file mode 100644
index 0000000..e52c5db
--- /dev/null
+++ b/packages/SystemUI/res/values/arrays_tv.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * Copyright (c) 2017, 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>
+ <!-- List of package names or class names which are considered as Settings,
+ so PIP location should be adjusted to the left of the side panel.
+ If it should be applied for all activities in a package, add the package name.
+ If it should be applied for an activity in a package, add its class name with package name.
+ The class name must follow format 'package_name/.class_name' ('/.' in between).
+ This can be overriden in an overlay.
+ -->
+ <string-array name="tv_pip_settings_class_name" translatable="false">
+ <item>com.android.tv.settings</item>
+ <item>com.google.android.leanbacklauncher/.settings.HomeScreenSettingsActivity</item>
+ <item>com.google.android.apps.mediashell/.settings.CastSettingsActivity</item>
+ <item>com.google.android.katniss.setting/.SpeechSettingsActivity</item>
+ <item>com.google.android.katniss.setting/.SearchSettingsActivity</item>
+ <item>com.google.android.gsf.notouch/.UsageDiagnosticsSettingActivity</item>
+ </string-array>
+</resources>
diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml
index 407cddf..f461bb3 100644
--- a/packages/SystemUI/res/values/colors.xml
+++ b/packages/SystemUI/res/values/colors.xml
@@ -27,7 +27,6 @@
<color name="notification_list_shadow_top">#80000000</color>
<drawable name="heads_up_notification_bg_pressed">#ff33B5E5</drawable>
<color name="qs_batterymeter_frame_color">#FF404040</color>
- <color name="system_warning_color">@*android:color/system_error</color>
<color name="qs_tile_divider">#29ffffff</color><!-- 16% white -->
<color name="qs_subhead">#99FFFFFF</color><!-- 60% white -->
<color name="qs_detail_button">@*android:color/quaternary_device_default_settings</color>
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index 48b7664..9168256 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -30,7 +30,7 @@
<!-- Recents theme -->
<style name="RecentsTheme.Wallpaper">
- <item name="android:windowBackground">@color/transparent</item>
+ <item name="android:windowBackground">@*android:color/transparent</item>
<item name="android:colorBackgroundCacheHint">@null</item>
<item name="android:windowShowWallpaper">true</item>
<item name="android:windowDisablePreview">true</item>
@@ -52,7 +52,7 @@
<!-- Theme used for the activity that shows when the system forced an app to be resizable -->
<style name="ForcedResizableTheme" parent="@android:style/Theme.Translucent.NoTitleBar">
<item name="android:windowBackground">@drawable/forced_resizable_background</item>
- <item name="android:statusBarColor">@color/transparent</item>
+ <item name="android:statusBarColor">@*android:color/transparent</item>
<item name="android:windowAnimationStyle">@style/Animation.ForcedResizable</item>
</style>
@@ -70,7 +70,7 @@
<item name="android:windowContentOverlay">@null</item>
<item name="android:windowBackground">@null</item>
<item name="android:colorBackgroundCacheHint">@null</item>
- <item name="android:statusBarColor">@color/transparent</item>
+ <item name="android:statusBarColor">@*android:color/transparent</item>
<item name="android:windowAnimationStyle">@style/Animation.PipPhoneOverlayControl</item>
</style>
@@ -164,7 +164,7 @@
<style name="TextAppearance.QS.Warning">
<item name="android:textSize">14sp</item>
- <item name="android:textColor">@color/system_warning_color</item>
+ <item name="android:textColor">?android:attr/colorError</item>
</style>
<style name="TextAppearance.QS.DetailButton">
@@ -366,7 +366,7 @@
</style>
<style name="TextAppearance.NotificationGuts.SecondaryWarning">
- <item name="android:textColor">@color/system_warning_color</item>
+ <item name="android:textColor">?android:attr/colorError</item>
<item name="android:textSize">12sp</item>
</style>
diff --git a/packages/SystemUI/src/com/android/systemui/ActivityStarterDelegate.java b/packages/SystemUI/src/com/android/systemui/ActivityStarterDelegate.java
index 14c67fe..e58538d 100644
--- a/packages/SystemUI/src/com/android/systemui/ActivityStarterDelegate.java
+++ b/packages/SystemUI/src/com/android/systemui/ActivityStarterDelegate.java
@@ -17,6 +17,8 @@
import android.app.PendingIntent;
import android.content.Intent;
+import com.android.systemui.plugins.ActivityStarter;
+
/**
* Single common instance of ActivityStarter that can be gotten and referenced from anywhere, but
* delegates to an actual implementation such as StatusBar, assuming it exists.
diff --git a/packages/SystemUI/src/com/android/systemui/Dependency.java b/packages/SystemUI/src/com/android/systemui/Dependency.java
index f1e7d53..8f9358f 100644
--- a/packages/SystemUI/src/com/android/systemui/Dependency.java
+++ b/packages/SystemUI/src/com/android/systemui/Dependency.java
@@ -25,8 +25,9 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.Preconditions;
import com.android.systemui.assist.AssistManager;
-import com.android.systemui.fragments.FragmentHostManager;
import com.android.systemui.fragments.FragmentService;
+import com.android.systemui.plugins.ActivityStarter;
+import com.android.systemui.plugins.PluginDependencyProvider;
import com.android.systemui.plugins.PluginManager;
import com.android.systemui.statusbar.phone.ConfigurationControllerImpl;
import com.android.systemui.statusbar.phone.DarkIconDispatcherImpl;
@@ -47,6 +48,8 @@
import com.android.systemui.statusbar.policy.DataSaverController;
import com.android.systemui.statusbar.policy.DeviceProvisionedController;
import com.android.systemui.statusbar.policy.DeviceProvisionedControllerImpl;
+import com.android.systemui.statusbar.policy.ExtensionController;
+import com.android.systemui.statusbar.policy.ExtensionControllerImpl;
import com.android.systemui.statusbar.policy.FlashlightController;
import com.android.systemui.statusbar.policy.FlashlightControllerImpl;
import com.android.systemui.statusbar.policy.HotspotController;
@@ -233,6 +236,12 @@
mProviders.put(FragmentService.class, () ->
new FragmentService(mContext));
+ mProviders.put(ExtensionController.class, () ->
+ new ExtensionControllerImpl());
+
+ mProviders.put(PluginDependencyProvider.class, () ->
+ new PluginDependencyProvider(get(PluginManager.class)));
+
// Put all dependencies above here so the factory can override them if it wants.
SystemUIFactory.getInstance().injectDependencies(mProviders, mContext);
}
diff --git a/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java b/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java
index 376a0b6..8f7a81c 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java
@@ -68,34 +68,10 @@
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
private static final boolean DEBUG_FORCE_ONBOARDING =
SystemProperties.getBoolean("debug.tv.pip_force_onboarding", false);
+ private static final String SETTINGS_PACKAGE_AND_CLASS_DELIMITER = "/";
private static PipManager sPipManager;
-
- /**
- * List of package and class name which are considered as Settings,
- * so PIP location should be adjusted to the left of the side panel.
- */
- private static final List<Pair<String, String>> sSettingsPackageAndClassNamePairList;
- static {
- sSettingsPackageAndClassNamePairList = new ArrayList<>();
- sSettingsPackageAndClassNamePairList.add(new Pair<String, String>(
- "com.android.tv.settings", null));
- sSettingsPackageAndClassNamePairList.add(new Pair<String, String>(
- "com.google.android.leanbacklauncher",
- "com.google.android.leanbacklauncher.settings.HomeScreenSettingsActivity"));
- sSettingsPackageAndClassNamePairList.add(new Pair<String, String>(
- "com.google.android.apps.mediashell",
- "com.google.android.apps.mediashell.settings.CastSettingsActivity"));
- sSettingsPackageAndClassNamePairList.add(new Pair<String, String>(
- "com.google.android.katniss",
- "com.google.android.katniss.setting.SpeechSettingsActivity"));
- sSettingsPackageAndClassNamePairList.add(new Pair<String, String>(
- "com.google.android.katniss",
- "com.google.android.katniss.setting.SearchSettingsActivity"));
- sSettingsPackageAndClassNamePairList.add(new Pair<String, String>(
- "com.google.android.gsf.notouch",
- "com.google.android.gsf.notouch.UsageDiagnosticsSettingActivity"));
- }
+ private static List<Pair<String, String>> sSettingsPackageAndClassNamePairList;
/**
* State when there's no PIP.
@@ -252,6 +228,36 @@
mOnboardingShown = Prefs.getBoolean(
mContext, TV_PICTURE_IN_PICTURE_ONBOARDING_SHOWN, false);
+ if (sSettingsPackageAndClassNamePairList == null) {
+ String[] settings = mContext.getResources().getStringArray(
+ R.array.tv_pip_settings_class_name);
+ sSettingsPackageAndClassNamePairList = new ArrayList<>();
+ if (settings != null) {
+ for (int i = 0; i < settings.length; i++) {
+ Pair<String, String> entry = null;
+ String[] packageAndClassName =
+ settings[i].split(SETTINGS_PACKAGE_AND_CLASS_DELIMITER);
+ switch (packageAndClassName.length) {
+ case 1:
+ entry = Pair.<String, String>create(packageAndClassName[0], null);
+ break;
+ case 2:
+ if (packageAndClassName[1] != null
+ && packageAndClassName[1].startsWith(".")) {
+ entry = Pair.<String, String>create(
+ packageAndClassName[0],
+ packageAndClassName[0] + packageAndClassName[1]);
+ }
+ }
+ if (entry != null) {
+ sSettingsPackageAndClassNamePairList.add(entry);
+ } else {
+ Log.w(TAG, "Ignoring malformed settings name " + settings[i]);
+ }
+ }
+ }
+ }
+
loadConfigurationsAndApply();
mPipRecentsOverlayManager = new PipRecentsOverlayManager(context);
mMediaSessionManager =
@@ -331,12 +337,11 @@
* Moves the PIPed activity to the fullscreen and closes PIP system UI.
*/
void movePipToFullscreen() {
- mState = STATE_NO_PIP;
mPipTaskId = TASK_ID_NO_PIP;
for (int i = mListeners.size() - 1; i >= 0; --i) {
mListeners.get(i).onMoveToFullscreen();
}
- resizePinnedStack(mState);
+ resizePinnedStack(STATE_NO_PIP);
updatePipVisibility(false);
}
@@ -382,6 +387,7 @@
if (DEBUG) Log.d(TAG, "resizePinnedStack() state=" + state);
boolean wasRecentsShown =
(mState == STATE_PIP_RECENTS || mState == STATE_PIP_RECENTS_FOCUSED);
+ boolean wasStateNoPip = (mState == STATE_NO_PIP);
mState = state;
for (int i = mListeners.size() - 1; i >= 0; --i) {
mListeners.get(i).onPipResizeAboutToStart();
@@ -395,6 +401,11 @@
switch (mState) {
case STATE_NO_PIP:
mCurrentPipBounds = null;
+ // If the state was already STATE_NO_PIP, then do not resize the stack below as it
+ // will not exist
+ if (wasStateNoPip) {
+ return;
+ }
break;
case STATE_PIP_MENU:
mCurrentPipBounds = mMenuModePipBounds;
@@ -412,18 +423,16 @@
mCurrentPipBounds = mPipBounds;
break;
}
- if (mCurrentPipBounds != null) {
- try {
- int animationDurationMs = -1;
- if (wasRecentsShown
- && (mState == STATE_PIP_RECENTS || mState == STATE_PIP_RECENTS_FOCUSED)) {
- animationDurationMs = mRecentsFocusChangedAnimationDurationMs;
- }
- mActivityManager.resizeStack(PINNED_STACK_ID, mCurrentPipBounds,
- true, true, true, animationDurationMs);
- } catch (RemoteException e) {
- Log.e(TAG, "resizeStack failed", e);
+ try {
+ int animationDurationMs = -1;
+ if (wasRecentsShown
+ && (mState == STATE_PIP_RECENTS || mState == STATE_PIP_RECENTS_FOCUSED)) {
+ animationDurationMs = mRecentsFocusChangedAnimationDurationMs;
}
+ mActivityManager.resizeStack(PINNED_STACK_ID, mCurrentPipBounds,
+ true, true, true, animationDurationMs);
+ } catch (RemoteException e) {
+ Log.e(TAG, "resizeStack failed", e);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/plugins/PluginDependencyProvider.java b/packages/SystemUI/src/com/android/systemui/plugins/PluginDependencyProvider.java
new file mode 100644
index 0000000..59f6d56
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/plugins/PluginDependencyProvider.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the
+ * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+package com.android.systemui.plugins;
+
+import android.util.ArrayMap;
+
+import com.android.systemui.Dependency;
+import com.android.systemui.plugins.PluginDependency.DependencyProvider;
+
+public class PluginDependencyProvider extends DependencyProvider {
+
+ private final ArrayMap<Class<?>, Object> mDependencies = new ArrayMap<>();
+ private final PluginManager mManager;
+
+ public PluginDependencyProvider(PluginManager manager) {
+ mManager = manager;
+ PluginDependency.sProvider = this;
+ }
+
+ public <T> void allowPluginDependency(Class<T> cls) {
+ allowPluginDependency(cls, Dependency.get(cls));
+ }
+
+ public <T> void allowPluginDependency(Class<T> cls, T obj) {
+ mDependencies.put(cls, obj);
+ }
+
+ @Override
+ <T> T get(Plugin p, Class<T> cls) {
+ if (!mManager.dependsOn(p, cls)) {
+ throw new IllegalArgumentException(p.getClass() + " does not depend on " + cls);
+ }
+ if (!mDependencies.containsKey(cls)) {
+ throw new IllegalArgumentException("Unknown dependency " + cls);
+ }
+ return (T) mDependencies.get(cls);
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/plugins/PluginInstanceManager.java b/packages/SystemUI/src/com/android/systemui/plugins/PluginInstanceManager.java
index e895fa2..58670da 100644
--- a/packages/SystemUI/src/com/android/systemui/plugins/PluginInstanceManager.java
+++ b/packages/SystemUI/src/com/android/systemui/plugins/PluginInstanceManager.java
@@ -161,6 +161,16 @@
mContext.sendBroadcast(intent);
}
+ public <T> boolean dependsOn(Plugin p, Class<T> cls) {
+ ArrayList<PluginInfo> plugins = new ArrayList<>(mPluginHandler.mPlugins);
+ for (PluginInfo info : plugins) {
+ if (info.mPlugin.getClass().getName().equals(p.getClass().getName())) {
+ return info.mVersion != null && info.mVersion.hasClass(cls);
+ }
+ }
+ return false;
+ }
+
private class MainHandler extends Handler {
private static final int PLUGIN_CONNECTED = 1;
private static final int PLUGIN_DISCONNECTED = 2;
@@ -304,9 +314,9 @@
// legacy version check.
T plugin = (T) pluginClass.newInstance();
try {
- checkVersion(pluginClass, plugin, mVersion);
+ VersionInfo version = checkVersion(pluginClass, plugin, mVersion);
if (DEBUG) Log.d(TAG, "createPlugin");
- return new PluginInfo(pkg, cls, plugin, pluginContext);
+ return new PluginInfo(pkg, cls, plugin, pluginContext, version);
} catch (InvalidVersionException e) {
final int icon = mContext.getResources().getIdentifier("tuner", "drawable",
mContext.getPackageName());
@@ -354,7 +364,7 @@
}
}
- private void checkVersion(Class<?> pluginClass, T plugin, VersionInfo version)
+ private VersionInfo checkVersion(Class<?> pluginClass, T plugin, VersionInfo version)
throws InvalidVersionException {
VersionInfo pv = new VersionInfo().addClass(pluginClass);
if (pv.hasVersionInfo()) {
@@ -364,7 +374,9 @@
if (fallbackVersion != version.getDefaultVersion()) {
throw new InvalidVersionException("Invalid legacy version", false);
}
+ return null;
}
+ return pv;
}
}
@@ -396,15 +408,18 @@
static class PluginInfo<T> {
private final Context mPluginContext;
+ private final VersionInfo mVersion;
private String mClass;
T mPlugin;
String mPackage;
- public PluginInfo(String pkg, String cls, T plugin, Context pluginContext) {
+ public PluginInfo(String pkg, String cls, T plugin, Context pluginContext,
+ VersionInfo info) {
mPlugin = plugin;
mClass = cls;
mPackage = pkg;
mPluginContext = pluginContext;
+ mVersion = info;
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/plugins/PluginManager.java b/packages/SystemUI/src/com/android/systemui/plugins/PluginManager.java
index 8b4bd7b..9ad862d 100644
--- a/packages/SystemUI/src/com/android/systemui/plugins/PluginManager.java
+++ b/packages/SystemUI/src/com/android/systemui/plugins/PluginManager.java
@@ -29,6 +29,7 @@
import android.content.res.Resources;
import android.net.Uri;
import android.os.Build;
+import android.os.Handler;
import android.os.HandlerThread;
import android.os.Looper;
import android.os.SystemProperties;
@@ -39,6 +40,7 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
+import com.android.systemui.Dependency;
import com.android.systemui.plugins.PluginInstanceManager.PluginContextWrapper;
import com.android.systemui.plugins.PluginInstanceManager.PluginInfo;
import com.android.systemui.plugins.annotations.ProvidesInterface;
@@ -93,6 +95,14 @@
PluginExceptionHandler uncaughtExceptionHandler = new PluginExceptionHandler(
defaultHandler);
Thread.setDefaultUncaughtExceptionHandler(uncaughtExceptionHandler);
+ if (isDebuggable) {
+ new Handler(mBackgroundThread.getLooper()).post(() -> {
+ // Plugin dependencies that don't have another good home can go here, but
+ // dependencies that have better places to init can happen elsewhere.
+ Dependency.get(PluginDependencyProvider.class)
+ .allowPluginDependency(ActivityStarter.class);
+ });
+ }
}
public <T extends Plugin> T getOneShotPlugin(Class<T> cls) {
@@ -133,14 +143,7 @@
public <T extends Plugin> void addPluginListener(PluginListener<T> listener, Class<?> cls,
boolean allowMultiple) {
- ProvidesInterface info = cls.getDeclaredAnnotation(ProvidesInterface.class);
- if (info == null) {
- throw new RuntimeException(cls + " doesn't provide an interface");
- }
- if (TextUtils.isEmpty(info.action())) {
- throw new RuntimeException(cls + " doesn't provide an action");
- }
- addPluginListener(info.action(), listener, cls, allowMultiple);
+ addPluginListener(getAction(cls), listener, cls, allowMultiple);
}
public <T extends Plugin> void addPluginListener(String action, PluginListener<T> listener,
@@ -275,36 +278,29 @@
return mParentClassLoader;
}
- public Context getAllPluginContext(Context context) {
- return new PluginContextWrapper(context,
- new AllPluginClassLoader(context.getClassLoader()));
- }
-
public Context getContext(ApplicationInfo info, String pkg) throws NameNotFoundException {
ClassLoader classLoader = getClassLoader(info.sourceDir, pkg);
return new PluginContextWrapper(mContext.createApplicationContext(info, 0), classLoader);
}
- private class AllPluginClassLoader extends ClassLoader {
- public AllPluginClassLoader(ClassLoader classLoader) {
- super(classLoader);
+ public static <P> String getAction(Class<P> cls) {
+ ProvidesInterface info = cls.getDeclaredAnnotation(ProvidesInterface.class);
+ if (info == null) {
+ throw new RuntimeException(cls + " doesn't provide an interface");
}
+ if (TextUtils.isEmpty(info.action())) {
+ throw new RuntimeException(cls + " doesn't provide an action");
+ }
+ return info.action();
+ }
- @Override
- public Class<?> loadClass(String s) throws ClassNotFoundException {
- try {
- return super.loadClass(s);
- } catch (ClassNotFoundException e) {
- for (ClassLoader classLoader : mClassLoaders.values()) {
- try {
- return classLoader.loadClass(s);
- } catch (ClassNotFoundException e1) {
- // Will re-throw e if all fail.
- }
- }
- throw e;
+ public <T> boolean dependsOn(Plugin p, Class<T> cls) {
+ for (int i = 0; i < mPluginMap.size(); i++) {
+ if (mPluginMap.valueAt(i).dependsOn(p, cls)) {
+ return true;
}
}
+ return false;
}
@VisibleForTesting
diff --git a/packages/SystemUI/src/com/android/systemui/plugins/VersionInfo.java b/packages/SystemUI/src/com/android/systemui/plugins/VersionInfo.java
index 84f7761..b69a7b4 100644
--- a/packages/SystemUI/src/com/android/systemui/plugins/VersionInfo.java
+++ b/packages/SystemUI/src/com/android/systemui/plugins/VersionInfo.java
@@ -103,6 +103,10 @@
return null;
}
+ public <T> boolean hasClass(Class<T> cls) {
+ return mVersions.containsKey(cls);
+ }
+
public static class InvalidVersionException extends RuntimeException {
private final boolean mTooNew;
diff --git a/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java b/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java
index 09ce2ad..daf0622 100644
--- a/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java
+++ b/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java
@@ -39,6 +39,7 @@
import android.util.Slog;
import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
+import com.android.settingslib.Utils;
import com.android.systemui.R;
import com.android.systemui.SystemUI;
import com.android.systemui.statusbar.phone.StatusBar;
@@ -175,8 +176,7 @@
.setOnlyAlertOnce(true)
.setDeleteIntent(pendingBroadcast(ACTION_DISMISSED_WARNING))
.setVisibility(Notification.VISIBILITY_PUBLIC)
- .setColor(mContext.getColor(
- com.android.internal.R.color.battery_saver_mode_color));
+ .setColor(Utils.getColorAttr(mContext, android.R.attr.colorError));
if (hasBatterySettings()) {
nb.setContentIntent(pendingBroadcast(ACTION_SHOW_BATTERY_SETTINGS));
}
@@ -245,8 +245,7 @@
.setVisibility(Notification.VISIBILITY_PUBLIC)
.setContentIntent(pendingBroadcast(ACTION_CLICKED_TEMP_WARNING))
.setDeleteIntent(pendingBroadcast(ACTION_DISMISSED_TEMP_WARNING))
- .setColor(mContext.getColor(
- com.android.internal.R.color.battery_saver_mode_color));
+ .setColor(Utils.getColorAttr(mContext, android.R.attr.colorError));
SystemUI.overrideNotificationAppName(mContext, nb);
final Notification n = nb.build();
mNoMan.notifyAsUser(TAG_TEMPERATURE, SystemMessage.NOTE_HIGH_TEMP, n, UserHandle.ALL);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSDetail.java b/packages/SystemUI/src/com/android/systemui/qs/QSDetail.java
index a20b7ba..7df124a 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSDetail.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSDetail.java
@@ -37,7 +37,7 @@
import com.android.systemui.FontSizeUtils;
import com.android.systemui.R;
import com.android.systemui.SysUiServiceProvider;
-import com.android.systemui.ActivityStarter;
+import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.plugins.qs.QS.BaseStatusBarHeader;
import com.android.systemui.plugins.qs.QS.Callback;
import com.android.systemui.plugins.qs.QS.DetailAdapter;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSDetailItems.java b/packages/SystemUI/src/com/android/systemui/qs/QSDetailItems.java
index dad8bea..65238b1 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSDetailItems.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSDetailItems.java
@@ -203,16 +203,28 @@
}
}
});
- final ImageView disconnect = (ImageView) view.findViewById(android.R.id.icon2);
- disconnect.setVisibility(item.canDisconnect ? VISIBLE : GONE);
- disconnect.setOnClickListener(new OnClickListener() {
- @Override
- public void onClick(View v) {
- if (mCallback != null) {
- mCallback.onDetailItemDisconnect(item);
+
+ final ImageView icon2 = (ImageView) view.findViewById(android.R.id.icon2);
+ if (item.canDisconnect) {
+ icon2.setImageResource(R.drawable.ic_qs_cancel);
+ icon2.setVisibility(VISIBLE);
+ icon2.setClickable(true);
+ icon2.setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ if (mCallback != null) {
+ mCallback.onDetailItemDisconnect(item);
+ }
}
- }
- });
+ });
+ } else if (item.icon2 != -1) {
+ icon2.setVisibility(VISIBLE);
+ icon2.setImageResource(item.icon2);
+ icon2.setClickable(false);
+ } else {
+ icon2.setVisibility(GONE);
+ }
+
return view;
}
};
@@ -245,6 +257,7 @@
public CharSequence line2;
public Object tag;
public boolean canDisconnect;
+ public int icon2 = -1;
}
public interface Callback {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFooter.java b/packages/SystemUI/src/com/android/systemui/qs/QSFooter.java
index 1835afd..d6c2447 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFooter.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFooter.java
@@ -37,7 +37,7 @@
import com.android.systemui.Dependency;
import com.android.systemui.FontSizeUtils;
import com.android.systemui.R;
-import com.android.systemui.ActivityStarter;
+import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.statusbar.phone.QSTileHost;
import com.android.systemui.statusbar.phone.SystemUIDialog;
import com.android.systemui.statusbar.policy.SecurityController;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSTile.java b/packages/SystemUI/src/com/android/systemui/qs/QSTile.java
index 0829ae5..c02067e 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSTile.java
@@ -32,7 +32,7 @@
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.settingslib.RestrictedLockUtils;
import com.android.systemui.Dependency;
-import com.android.systemui.ActivityStarter;
+import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.plugins.qs.QS.DetailAdapter;
import com.android.systemui.qs.QSTile.State;
import com.android.systemui.qs.external.TileServices;
@@ -45,8 +45,6 @@
import static com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
-import com.android.systemui.R;
-
/**
* Base quick-settings tile, extend this to create a new tile.
*
diff --git a/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java b/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java
index dea56aa1..b28b0e7 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java
@@ -30,17 +30,13 @@
import android.service.quicksettings.IQSTileService;
import android.service.quicksettings.Tile;
import android.service.quicksettings.TileService;
-import android.text.SpannableStringBuilder;
-import android.text.style.ForegroundColorSpan;
import android.util.Log;
import android.view.IWindowManager;
-import android.view.WindowManager;
import android.view.WindowManagerGlobal;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
-import com.android.systemui.R;
import com.android.systemui.Dependency;
-import com.android.systemui.ActivityStarter;
+import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.qs.QSTile;
import com.android.systemui.qs.external.TileLifecycleManager.TileChangeListener;
import com.android.systemui.statusbar.phone.QSTileHost;
@@ -87,7 +83,7 @@
private void setTileIcon() {
try {
PackageManager pm = mContext.getPackageManager();
- int flags = PackageManager.MATCH_ENCRYPTION_AWARE_AND_UNAWARE;
+ int flags = PackageManager.MATCH_DIRECT_BOOT_UNAWARE | PackageManager.MATCH_DIRECT_BOOT_AWARE;
if (isSystemApp(pm)) {
flags |= PackageManager.MATCH_DISABLED_COMPONENTS;
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
index 4b56ecd..5d7508b 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
@@ -34,7 +34,7 @@
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
import com.android.systemui.Dependency;
import com.android.systemui.R;
-import com.android.systemui.ActivityStarter;
+import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.plugins.qs.QS.DetailAdapter;
import com.android.systemui.qs.QSDetailItems;
import com.android.systemui.qs.QSDetailItems.Item;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java
index 3c28f76..c501c91 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java
@@ -30,7 +30,7 @@
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.systemui.Dependency;
import com.android.systemui.R;
-import com.android.systemui.ActivityStarter;
+import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.plugins.qs.QS.DetailAdapter;
import com.android.systemui.qs.QSDetailItems;
import com.android.systemui.qs.QSDetailItems.Item;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java
index bae163f..1a04a51 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java
@@ -31,7 +31,7 @@
import com.android.settingslib.net.DataUsageController;
import com.android.systemui.Dependency;
import com.android.systemui.R;
-import com.android.systemui.ActivityStarter;
+import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.plugins.qs.QS.DetailAdapter;
import com.android.systemui.qs.QSIconView;
import com.android.systemui.qs.QSTile;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/DataUsageDetailView.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/DataUsageDetailView.java
index c7b6aea..9cd79f8 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/DataUsageDetailView.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/DataUsageDetailView.java
@@ -91,7 +91,7 @@
formatBytes(info.usageLevel));
bottom = res.getString(R.string.quick_settings_cellular_detail_data_limit,
formatBytes(info.limitLevel));
- usageColor = mContext.getColor(R.color.system_warning_color);
+ usageColor = Utils.getDefaultColor(mContext, android.R.attr.colorError);
}
if (usageColor == 0) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java
index 4072b44..d554a17 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java
@@ -39,7 +39,7 @@
import com.android.systemui.Prefs;
import com.android.systemui.R;
import com.android.systemui.SysUIToast;
-import com.android.systemui.ActivityStarter;
+import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.plugins.qs.QS.DetailAdapter;
import com.android.systemui.qs.QSTile;
import com.android.systemui.statusbar.policy.ZenModeController;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/IntentTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/IntentTile.java
index fcc9596..aeea75d 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/IntentTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/IntentTile.java
@@ -32,7 +32,7 @@
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.systemui.Dependency;
-import com.android.systemui.ActivityStarter;
+import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.qs.QSTile;
import java.util.Arrays;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java
index 423a1df..e61a953 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java
@@ -26,7 +26,7 @@
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.systemui.Dependency;
import com.android.systemui.R;
-import com.android.systemui.ActivityStarter;
+import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.qs.QSTile;
import com.android.systemui.statusbar.policy.KeyguardMonitor;
import com.android.systemui.statusbar.policy.LocationController;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java
index 90a9db6..83dc1c2 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java
@@ -33,7 +33,7 @@
import com.android.settingslib.wifi.AccessPoint;
import com.android.systemui.Dependency;
import com.android.systemui.R;
-import com.android.systemui.ActivityStarter;
+import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.plugins.qs.QS.DetailAdapter;
import com.android.systemui.qs.QSDetailItems;
import com.android.systemui.qs.QSDetailItems.Item;
@@ -372,9 +372,9 @@
item.icon = mWifiController.getIcon(ap);
item.line1 = ap.getSsid();
item.line2 = ap.isActive() ? ap.getSummary() : null;
- item.overlay = ap.getSecurity() != AccessPoint.SECURITY_NONE
- ? mContext.getDrawable(R.drawable.qs_ic_wifi_lock)
- : null;
+ item.icon2 = ap.getSecurity() != AccessPoint.SECURITY_NONE
+ ? R.drawable.qs_ic_wifi_lock
+ : -1;
items[i] = item;
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewThumbnail.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewThumbnail.java
index 02b0113..e0dac09 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewThumbnail.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewThumbnail.java
@@ -197,6 +197,7 @@
bm.getHeight() - thumbnailData.insets.top - thumbnailData.insets.bottom);
mThumbnailData = thumbnailData;
updateThumbnailMatrix();
+ updateThumbnailPaintFilter();
} else {
mBitmapShader = null;
mDrawPaint.setShader(null);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
index bc992d8..fb92a67 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
@@ -42,6 +42,7 @@
import com.android.internal.app.IBatteryStats;
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.keyguard.KeyguardUpdateMonitorCallback;
+import com.android.settingslib.Utils;
import com.android.systemui.Dependency;
import com.android.systemui.R;
import com.android.systemui.statusbar.phone.KeyguardIndicationTextView;
@@ -365,7 +366,7 @@
if (!updateMonitor.isUnlockingWithFingerprintAllowed()) {
return;
}
- int errorColor = mContext.getResources().getColor(R.color.system_warning_color, null);
+ int errorColor = Utils.getColorError(mContext);
if (mStatusBarKeyguardViewManager.isBouncerShowing()) {
mStatusBarKeyguardViewManager.showBouncerMessage(helpString, errorColor);
} else if (updateMonitor.isDeviceInteractive()
@@ -388,7 +389,7 @@
|| msgId == FingerprintManager.FINGERPRINT_ERROR_CANCELED) {
return;
}
- int errorColor = mContext.getResources().getColor(R.color.system_warning_color, null);
+ int errorColor = Utils.getColorError(mContext);
if (mStatusBarKeyguardViewManager.isBouncerShowing()) {
// When swiping up right after receiving a fingerprint error, the bouncer calls
// authenticate leading to the same message being shown again on the bouncer.
@@ -411,8 +412,7 @@
@Override
public void onScreenTurnedOn() {
if (mMessageToShowOnScreenOn != null) {
- int errorColor = mContext.getResources().getColor(R.color.system_warning_color,
- null);
+ int errorColor = Utils.getColorError(mContext);
showTransientIndication(mMessageToShowOnScreenOn, errorColor);
// We want to keep this message around in case the screen was off
mHandler.removeMessages(MSG_HIDE_TRANSIENT);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java b/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java
index 89041f9..67be99e5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java
@@ -83,6 +83,8 @@
private int mWifiStrengthId = 0;
private int mLastWifiBadgeId = -1;
private int mLastWifiStrengthId = -1;
+ private int mWifiActivityId = 0;
+ private int mLastWifiActivityId = -1;
private boolean mIsAirplaneMode = false;
private int mAirplaneIconId = 0;
private int mLastAirplaneIconId = -1;
@@ -97,6 +99,7 @@
ViewGroup mEthernetGroup, mWifiGroup;
View mNoSimsCombo;
ImageView mVpn, mEthernet, mWifi, mAirplane, mNoSims, mEthernetDark, mWifiDark, mNoSimsDark;
+ ImageView mWifiActivity;
View mWifiAirplaneSpacer;
View mWifiSignalSpacer;
LinearLayout mMobileSignalGroup;
@@ -177,6 +180,7 @@
mWifiGroup = (ViewGroup) findViewById(R.id.wifi_combo);
mWifi = (ImageView) findViewById(R.id.wifi_signal);
mWifiDark = (ImageView) findViewById(R.id.wifi_signal_dark);
+ mWifiActivity = (ImageView) findViewById(R.id.wifi_inout);
mAirplane = (ImageView) findViewById(R.id.airplane);
mNoSims = (ImageView) findViewById(R.id.no_sims);
mNoSimsDark = (ImageView) findViewById(R.id.no_sims_dark);
@@ -267,6 +271,10 @@
mWifiStrengthId = statusIcon.icon;
mWifiBadgeId = statusIcon.iconOverlay;
mWifiDescription = statusIcon.contentDescription;
+ mWifiActivityId = activityIn && activityOut ? R.drawable.stat_sys_wifi_inout
+ : activityIn ? R.drawable.stat_sys_wifi_in
+ : activityOut ? R.drawable.stat_sys_wifi_out
+ : 0;
apply();
}
@@ -286,6 +294,10 @@
state.mMobileTypeDescription = typeContentDescription;
state.mIsMobileTypeIconWide = statusType != 0 && isWide;
state.mRoaming = roaming;
+ state.mMobileActivityId = activityIn && activityOut ? R.drawable.stat_sys_signal_inout
+ : activityIn ? R.drawable.stat_sys_signal_in
+ : activityOut ? R.drawable.stat_sys_signal_out
+ : 0;
apply();
}
@@ -409,6 +421,10 @@
mLastWifiStrengthId = -1;
mLastWifiBadgeId = -1;
}
+ if (mWifiActivity != null) {
+ mWifiActivity.setImageDrawable(null);
+ mLastWifiActivityId = -1;
+ }
for (PhoneState state : mPhoneStates) {
if (state.mMobile != null) {
@@ -425,6 +441,10 @@
state.mMobileType.setImageDrawable(null);
state.mLastMobileTypeId = -1;
}
+ if (state.mMobileActivity != null) {
+ state.mMobileActivity.setImageDrawable(null);
+ state.mLastMobileActivityId = -1;
+ }
}
if (mAirplane != null) {
@@ -484,6 +504,12 @@
mLastWifiStrengthId = mWifiStrengthId;
mLastWifiBadgeId = mWifiBadgeId;
}
+ if (mWifiActivityId != mLastWifiActivityId) {
+ if (mWifiActivityId != 0) {
+ setIconForView(mWifiActivity, mWifiActivityId);
+ }
+ mLastWifiActivityId = mWifiActivityId;
+ }
mWifiGroup.setContentDescription(mWifiDescription);
mWifiGroup.setVisibility(View.VISIBLE);
} else {
@@ -495,6 +521,8 @@
(mWifiVisible ? "VISIBLE" : "GONE"),
mWifiStrengthId));
+ mWifiActivity.setVisibility(mWifiActivityId != 0 ? View.VISIBLE : View.GONE);
+
boolean anyMobileVisible = false;
int firstMobileTypeId = 0;
for (PhoneState state : mPhoneStates) {
@@ -603,6 +631,8 @@
applyDarkIntensity(
DarkIconDispatcher.getDarkIntensity(mTintArea, mWifi, mDarkIntensity),
mWifi, mWifiDark);
+ setTint(mWifiActivity,
+ DarkIconDispatcher.getTint(mTintArea, mWifiActivity, mIconTint));
applyDarkIntensity(
DarkIconDispatcher.getDarkIntensity(mTintArea, mEthernet, mDarkIntensity),
mEthernet, mEthernetDark);
@@ -627,15 +657,17 @@
private class PhoneState {
private final int mSubId;
private boolean mMobileVisible = false;
- private int mMobileStrengthId = 0, mMobileTypeId = 0;
+ private int mMobileStrengthId = 0, mMobileTypeId = 0, mMobileActivityId = 0;
private int mLastMobileStrengthId = -1;
private int mLastMobileTypeId = -1;
+ private int mLastMobileActivityId = -1;
private boolean mIsMobileTypeIconWide;
private String mMobileDescription, mMobileTypeDescription;
private ViewGroup mMobileGroup;
private ImageView mMobile, mMobileDark, mMobileType, mMobileRoaming;
public boolean mRoaming;
+ private ImageView mMobileActivity;
public PhoneState(int subId, Context context) {
ViewGroup root = (ViewGroup) LayoutInflater.from(context)
@@ -650,6 +682,7 @@
mMobileDark = (ImageView) root.findViewById(R.id.mobile_signal_dark);
mMobileType = (ImageView) root.findViewById(R.id.mobile_type);
mMobileRoaming = (ImageView) root.findViewById(R.id.mobile_roaming);
+ mMobileActivity = (ImageView) root.findViewById(R.id.mobile_inout);
}
public boolean apply(boolean isSecondaryIcon) {
@@ -664,6 +697,11 @@
mMobileType.setImageResource(mMobileTypeId);
mLastMobileTypeId = mMobileTypeId;
}
+
+ if (mLastMobileActivityId != mMobileActivityId) {
+ mMobileActivity.setImageResource(mMobileActivityId);
+ mLastMobileActivityId = mMobileActivityId;
+ }
mMobileGroup.setContentDescription(mMobileTypeDescription
+ " " + mMobileDescription);
mMobileGroup.setVisibility(View.VISIBLE);
@@ -686,6 +724,7 @@
mMobileType.setVisibility(mMobileTypeId != 0 ? View.VISIBLE : View.GONE);
mMobileRoaming.setVisibility(mRoaming ? View.VISIBLE : View.GONE);
+ mMobileActivity.setVisibility(mMobileActivityId != 0 ? View.VISIBLE : View.GONE);
return mMobileVisible;
}
@@ -747,6 +786,8 @@
setTint(mMobileType, DarkIconDispatcher.getTint(tintArea, mMobileType, tint));
setTint(mMobileRoaming, DarkIconDispatcher.getTint(tintArea, mMobileRoaming,
tint));
+ setTint(mMobileActivity,
+ DarkIconDispatcher.getTint(tintArea, mMobileActivity, tint));
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BarTransitions.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BarTransitions.java
index ed71e57..f3c2bc5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BarTransitions.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BarTransitions.java
@@ -33,6 +33,7 @@
import android.util.Log;
import android.view.View;
+import com.android.settingslib.Utils;
import com.android.systemui.Interpolators;
import com.android.systemui.R;
@@ -167,7 +168,7 @@
mSemiTransparent = context.getColor(
com.android.internal.R.color.system_bar_background_semi_transparent);
mTransparent = context.getColor(R.color.system_bar_background_transparent);
- mWarning = context.getColor(com.android.internal.R.color.battery_saver_mode_color);
+ mWarning = Utils.getColorAttr(context, android.R.attr.colorError);
}
mGradient = context.getDrawable(gradientResourceId);
}
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 8f63d45..9a49d67 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
@@ -19,9 +19,10 @@
import static android.view.accessibility.AccessibilityNodeInfo.ACTION_CLICK;
import static android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction;
+import static com.android.systemui.tuner.LockscreenFragment.LOCKSCREEN_LEFT_BUTTON;
import static com.android.systemui.tuner.LockscreenFragment.LOCKSCREEN_LEFT_UNLOCK;
+import static com.android.systemui.tuner.LockscreenFragment.LOCKSCREEN_RIGHT_BUTTON;
import static com.android.systemui.tuner.LockscreenFragment.LOCKSCREEN_RIGHT_UNLOCK;
-import static com.android.systemui.tuner.LockscreenFragment.getIntentButton;
import android.app.ActivityManager;
import android.app.ActivityOptions;
@@ -35,7 +36,6 @@
import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
-import android.content.res.AssetFileDescriptor.AutoCloseOutputStream;
import android.content.res.Configuration;
import android.graphics.drawable.Drawable;
import android.os.AsyncTask;
@@ -63,7 +63,6 @@
import com.android.internal.widget.LockPatternUtils;
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.keyguard.KeyguardUpdateMonitorCallback;
-import com.android.systemui.EventLogConstants;
import com.android.systemui.EventLogTags;
import com.android.systemui.Dependency;
import com.android.systemui.Interpolators;
@@ -74,14 +73,17 @@
import com.android.systemui.plugins.IntentButtonProvider.IntentButton.IconState;
import com.android.systemui.plugins.PluginListener;
import com.android.systemui.plugins.PluginManager;
-import com.android.systemui.ActivityStarter;
+import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.KeyguardAffordanceView;
import com.android.systemui.statusbar.KeyguardIndicationController;
import com.android.systemui.statusbar.policy.AccessibilityController;
+import com.android.systemui.statusbar.policy.ExtensionController;
+import com.android.systemui.statusbar.policy.ExtensionController.Extension;
import com.android.systemui.statusbar.policy.FlashlightController;
import com.android.systemui.statusbar.policy.PreviewInflater;
import com.android.systemui.tuner.LockscreenFragment;
+import com.android.systemui.tuner.LockscreenFragment.LockButtonFactory;
import com.android.systemui.tuner.TunerService;
import com.android.systemui.tuner.TunerService.Tunable;
@@ -91,8 +93,7 @@
*/
public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickListener,
UnlockMethodCache.OnUnlockMethodChangedListener,
- AccessibilityController.AccessibilityStateChangedCallback, View.OnLongClickListener,
- Tunable {
+ AccessibilityController.AccessibilityStateChangedCallback, View.OnLongClickListener {
final static String TAG = "StatusBar/KeyguardBottomAreaView";
@@ -159,12 +160,10 @@
private Drawable mLeftAssistIcon;
private IntentButton mRightButton = new DefaultRightButton();
- private IntentButton mRightDefault = mRightButton;
- private IntentButton mRightPlugin;
+ private Extension<IntentButton> mRightExtension;
private String mRightButtonStr;
private IntentButton mLeftButton = new DefaultLeftButton();
- private IntentButton mLeftDefault = mLeftButton;
- private IntentButton mLeftPlugin;
+ private Extension<IntentButton> mLeftExtension;
private String mLeftButtonStr;
private LockscreenGestureLogger mLockscreenGestureLogger = new LockscreenGestureLogger();
private boolean mDozing;
@@ -261,21 +260,28 @@
protected void onAttachedToWindow() {
super.onAttachedToWindow();
mAccessibilityController.addStateChangedCallback(this);
- Dependency.get(PluginManager.class).addPluginListener(RIGHT_BUTTON_PLUGIN,
- mRightListener, IntentButtonProvider.class, false /* Only allow one */);
- Dependency.get(PluginManager.class).addPluginListener(LEFT_BUTTON_PLUGIN,
- mLeftListener, IntentButtonProvider.class, false /* Only allow one */);
- Dependency.get(TunerService.class).addTunable(this, LockscreenFragment.LOCKSCREEN_LEFT_BUTTON,
- LockscreenFragment.LOCKSCREEN_RIGHT_BUTTON);
+ mRightExtension = Dependency.get(ExtensionController.class).newExtension(IntentButton.class)
+ .withPlugin(IntentButtonProvider.class, RIGHT_BUTTON_PLUGIN,
+ p -> p.getIntentButton())
+ .withTunerFactory(new LockButtonFactory(mContext, LOCKSCREEN_RIGHT_BUTTON))
+ .withDefault(() -> new DefaultRightButton())
+ .withCallback(button -> setRightButton(button))
+ .build();
+ mLeftExtension = Dependency.get(ExtensionController.class).newExtension(IntentButton.class)
+ .withPlugin(IntentButtonProvider.class, LEFT_BUTTON_PLUGIN,
+ p -> p.getIntentButton())
+ .withTunerFactory(new LockButtonFactory(mContext, LOCKSCREEN_LEFT_BUTTON))
+ .withDefault(() -> new DefaultLeftButton())
+ .withCallback(button -> setLeftButton(button))
+ .build();
}
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
mAccessibilityController.removeStateChangedCallback(this);
- Dependency.get(PluginManager.class).removePluginListener(mRightListener);
- Dependency.get(PluginManager.class).removePluginListener(mLeftListener);
- Dependency.get(TunerService.class).removeTunable(this);
+ mRightExtension.destroy();
+ mLeftExtension.destroy();
}
private void initAccessibility() {
@@ -790,63 +796,21 @@
inflateCameraPreview();
}
- @Override
- public void onTuningChanged(String key, String newValue) {
- if (LockscreenFragment.LOCKSCREEN_LEFT_BUTTON.equals(key)) {
- mLeftButtonStr = newValue;
- mLeftIsVoiceAssist = TextUtils.isEmpty(mLeftButtonStr) && mLeftPlugin == null;
- mLeftButton = getIntentButton(mContext, mLeftButtonStr, mLeftPlugin, mLeftDefault);
- updateLeftAffordance();
- } else {
- mRightButtonStr = newValue;
- mRightButton = getIntentButton(mContext, mRightButtonStr, mRightPlugin, mRightDefault);
- updateRightAffordanceIcon();
- updateCameraVisibility();
- inflateCameraPreview();
- }
- }
-
private void setRightButton(IntentButton button) {
- mRightPlugin = button;
- mRightButton = getIntentButton(mContext, mRightButtonStr, mRightPlugin, mRightDefault);
+ mRightButton = button;
updateRightAffordanceIcon();
updateCameraVisibility();
inflateCameraPreview();
}
private void setLeftButton(IntentButton button) {
- mLeftPlugin = button;
- mLeftButton = getIntentButton(mContext, mLeftButtonStr, mLeftPlugin, mLeftDefault);
- mLeftIsVoiceAssist = false;
+ mLeftButton = button;
+ if (!(mLeftButton instanceof DefaultLeftButton)) {
+ mLeftIsVoiceAssist = false;
+ }
updateLeftAffordance();
}
- private final PluginListener<IntentButtonProvider> mRightListener =
- new PluginListener<IntentButtonProvider>() {
- @Override
- public void onPluginConnected(IntentButtonProvider plugin, Context pluginContext) {
- setRightButton(plugin.getIntentButton());
- }
-
- @Override
- public void onPluginDisconnected(IntentButtonProvider plugin) {
- setRightButton(null);
- }
- };
-
- private final PluginListener<IntentButtonProvider> mLeftListener =
- new PluginListener<IntentButtonProvider>() {
- @Override
- public void onPluginConnected(IntentButtonProvider plugin, Context pluginContext) {
- setLeftButton(plugin.getIntentButton());
- }
-
- @Override
- public void onPluginDisconnected(IntentButtonProvider plugin) {
- setLeftButton(null);
- }
- };
-
public void setDozing(boolean dozing, boolean animate) {
mDozing = dozing;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitch.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitch.java
index 3cbac17..8cad85c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitch.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitch.java
@@ -31,7 +31,7 @@
import com.android.systemui.Dependency;
import com.android.systemui.R;
-import com.android.systemui.ActivityStarter;
+import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.plugins.qs.QS.DetailAdapter;
import com.android.systemui.qs.QSPanel;
import com.android.systemui.statusbar.policy.KeyguardUserSwitcher;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStatusBarHeader.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStatusBarHeader.java
index 0e7b2f3..a5590f2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStatusBarHeader.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStatusBarHeader.java
@@ -29,6 +29,7 @@
import android.os.UserManager;
import android.support.annotation.Nullable;
import android.support.annotation.VisibleForTesting;
+import android.telephony.SubscriptionInfo;
import android.util.AttributeSet;
import android.util.SparseBooleanArray;
import android.view.View;
@@ -42,7 +43,7 @@
import com.android.internal.logging.nano.MetricsProto;
import com.android.keyguard.KeyguardStatusView;
import com.android.settingslib.Utils;
-import com.android.systemui.ActivityStarter;
+import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.BatteryMeterView;
import com.android.systemui.Dependency;
import com.android.systemui.FontSizeUtils;
@@ -64,6 +65,8 @@
import com.android.systemui.statusbar.policy.UserInfoController.OnUserInfoChangedListener;
import com.android.systemui.tuner.TunerService;
+import java.util.List;
+
public class QuickStatusBarHeader extends BaseStatusBarHeader implements
NextAlarmChangeCallback, OnClickListener, OnUserInfoChangedListener, EmergencyListener,
SignalCallback {
@@ -440,10 +443,20 @@
}
}
+ @Override
+ public void setSubs(List<SubscriptionInfo> subs) {
+ mRoamingsBySubId.clear();
+ updateRoaming();
+ }
+
public void setMobileDataIndicators(IconState statusIcon, IconState qsIcon, int statusType,
int qsType, boolean activityIn, boolean activityOut, String typeContentDescription,
String description, boolean isWide, int subId, boolean roaming) {
mRoamingsBySubId.put(subId, roaming);
+ updateRoaming();
+ }
+
+ private void updateRoaming() {
boolean isRoaming = calculateRoaming();
if (mIsRoaming != isRoaming) {
mIsRoaming = isRoaming;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
index 213b0aa..648e00c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -124,7 +124,6 @@
import com.android.systemui.ActivityStarterDelegate;
import com.android.systemui.DemoMode;
import com.android.systemui.Dependency;
-import com.android.systemui.EventLogConstants;
import com.android.systemui.EventLogTags;
import com.android.systemui.Interpolators;
import com.android.systemui.Prefs;
@@ -139,7 +138,7 @@
import com.android.systemui.fragments.PluginFragmentListener;
import com.android.systemui.keyguard.KeyguardViewMediator;
import com.android.systemui.plugins.qs.QS;
-import com.android.systemui.ActivityStarter;
+import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.plugins.qs.QS.BaseStatusBarHeader;
import com.android.systemui.plugins.statusbar.NotificationMenuRowProvider.SnoozeListener;
import com.android.systemui.plugins.statusbar.NotificationMenuRowProvider.SnoozeOption;
@@ -5742,9 +5741,8 @@
if (snoozeOption.criterion != null) {
mNotificationListener.snoozeNotification(sbn.getKey(), snoozeOption.criterion.getId());
} else {
- GregorianCalendar snoozeUntil = new GregorianCalendar();
- snoozeUntil.add(Calendar.MINUTE, snoozeOption.snoozeForMinutes);
- mNotificationListener.snoozeNotification(sbn.getKey(), snoozeUntil.getTimeInMillis());
+ mNotificationListener.snoozeNotification(sbn.getKey(),
+ snoozeOption.snoozeForMinutes * 60 * 1000);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeviceProvisionedController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeviceProvisionedController.java
index aa4eaa7..21f9a79 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeviceProvisionedController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeviceProvisionedController.java
@@ -26,7 +26,9 @@
interface DeviceProvisionedListener {
default void onDeviceProvisionedChanged() { }
- default void onUserSwitched() { }
+ default void onUserSwitched() {
+ onUserSetupChanged();
+ }
default void onUserSetupChanged() { }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeviceProvisionedControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeviceProvisionedControllerImpl.java
index 528fefe..cfaca0d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeviceProvisionedControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeviceProvisionedControllerImpl.java
@@ -66,6 +66,8 @@
if (mListeners.size() == 1) {
startListening(getCurrentUser());
}
+ listener.onUserSetupChanged();
+ listener.onDeviceProvisionedChanged();
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ExtensionController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ExtensionController.java
new file mode 100644
index 0000000..eaf8925
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ExtensionController.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the
+ * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+package com.android.systemui.statusbar.policy;
+
+import com.android.systemui.Dependency;
+import com.android.systemui.plugins.Plugin;
+
+import java.util.Map;
+import java.util.function.Consumer;
+import java.util.function.Supplier;
+
+/**
+ * Utility class used to select between a plugin, tuner settings, and a default implementation
+ * of an interface.
+ */
+public interface ExtensionController {
+
+ <T> ExtensionBuilder<T> newExtension(Class<T> cls);
+
+ interface Extension<T> {
+ T get();
+ void destroy();
+ }
+
+ interface ExtensionBuilder<T> {
+ ExtensionBuilder<T> withTunerFactory(TunerFactory<T> factory);
+ <P extends T> ExtensionBuilder<T> withPlugin(Class<P> cls);
+ <P extends T> ExtensionBuilder<T> withPlugin(Class<P> cls, String action);
+ <P> ExtensionBuilder<T> withPlugin(Class<P> cls, String action,
+ PluginConverter<T, P> converter);
+ ExtensionBuilder<T> withDefault(Supplier<T> def);
+ ExtensionBuilder<T> withCallback(Consumer<T> callback);
+ Extension build();
+ }
+
+ public interface PluginConverter<T, P> {
+ T getInterfaceFromPlugin(P plugin);
+ }
+
+ public interface TunerFactory<T> {
+ String[] keys();
+ T create(Map<String, String> settings);
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ExtensionControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ExtensionControllerImpl.java
new file mode 100644
index 0000000..fefbaa3
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ExtensionControllerImpl.java
@@ -0,0 +1,236 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the
+ * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+package com.android.systemui.statusbar.policy;
+
+import com.android.systemui.Dependency;
+import com.android.systemui.plugins.Plugin;
+import com.android.systemui.plugins.PluginListener;
+import com.android.systemui.plugins.PluginManager;
+import com.android.systemui.tuner.TunerService;
+import com.android.systemui.tuner.TunerService.Tunable;
+
+import android.content.Context;
+import android.util.ArrayMap;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.function.Consumer;
+import java.util.function.Supplier;
+
+public class ExtensionControllerImpl implements ExtensionController {
+
+ @Override
+ public <T> ExtensionBuilder<T> newExtension(Class<T> cls) {
+ return new ExtensionBuilder<>();
+ }
+
+ private interface Producer<T> {
+ T get();
+ void destroy();
+ }
+
+ private class ExtensionBuilder<T> implements ExtensionController.ExtensionBuilder<T> {
+
+ private ExtensionImpl<T> mExtension = new ExtensionImpl<>();
+
+ @Override
+ public ExtensionController.ExtensionBuilder<T> withTunerFactory(TunerFactory<T> factory) {
+ mExtension.addTunerFactory(factory, factory.keys());
+ return this;
+ }
+
+ @Override
+ public <P extends T> ExtensionController.ExtensionBuilder<T> withPlugin(Class<P> cls) {
+ return withPlugin(cls, PluginManager.getAction(cls));
+ }
+
+ @Override
+ public <P extends T> ExtensionController.ExtensionBuilder<T> withPlugin(Class<P> cls,
+ String action) {
+ return withPlugin(cls, action, null);
+ }
+
+ @Override
+ public <P> ExtensionController.ExtensionBuilder<T> withPlugin(Class<P> cls,
+ String action, PluginConverter<T, P> converter) {
+ mExtension.addPlugin(action, cls, converter);
+ return this;
+ }
+
+ @Override
+ public ExtensionController.ExtensionBuilder<T> withDefault(Supplier<T> def) {
+ mExtension.addDefault(def);
+ return this;
+ }
+
+ @Override
+ public ExtensionController.ExtensionBuilder<T> withCallback(
+ Consumer<T> callback) {
+ mExtension.mCallbacks.add(callback);
+ return this;
+ }
+
+ @Override
+ public ExtensionController.Extension build() {
+ // Manually sort, plugins first, tuners second, defaults last.
+ Collections.sort(mExtension.mProducers, (o1, o2) -> {
+ if (o1 instanceof ExtensionImpl.PluginItem) {
+ if (o2 instanceof ExtensionImpl.PluginItem) {
+ return 0;
+ } else {
+ return -1;
+ }
+ }
+ if (o1 instanceof ExtensionImpl.TunerItem) {
+ if (o2 instanceof ExtensionImpl.PluginItem) {
+ return 1;
+ } else if (o2 instanceof ExtensionImpl.TunerItem) {
+ return 0;
+ } else {
+ return -1;
+ }
+ }
+ return 0;
+ });
+ mExtension.notifyChanged();
+ return mExtension;
+ }
+ }
+
+ private class ExtensionImpl<T> implements ExtensionController.Extension<T> {
+ private final ArrayList<Producer<T>> mProducers = new ArrayList<>();
+ private final ArrayList<Consumer<T>> mCallbacks = new ArrayList<>();
+ private T mItem;
+
+ @Override
+ public T get() {
+ return mItem;
+ }
+
+ @Override
+ public void destroy() {
+ for (int i = 0; i < mProducers.size(); i++) {
+ mProducers.get(i).destroy();
+ }
+ }
+
+ private void notifyChanged() {
+ for (int i = 0; i < mProducers.size(); i++) {
+ final T item = mProducers.get(i).get();
+ if (item != null) {
+ mItem = item;
+ break;
+ }
+ }
+ for (int i = 0; i < mCallbacks.size(); i++) {
+ mCallbacks.get(i).accept(mItem);
+ }
+ }
+
+ public void addDefault(Supplier<T> def) {
+ mProducers.add(new Default(def));
+ }
+
+ public <P> void addPlugin(String action, Class<P> cls, PluginConverter<T, P> converter) {
+ mProducers.add(new PluginItem(action, cls, converter));
+ }
+
+ public void addTunerFactory(TunerFactory<T> factory, String[] keys) {
+ mProducers.add(new TunerItem(factory, factory.keys()));
+ }
+
+ private class PluginItem<P extends Plugin> implements Producer<T>, PluginListener<P> {
+ private final PluginConverter<T, P> mConverter;
+ private T mItem;
+
+ public PluginItem(String action, Class<P> cls, PluginConverter<T, P> converter) {
+ mConverter = converter;
+ Dependency.get(PluginManager.class).addPluginListener(action, this, cls);
+ }
+
+ @Override
+ public void onPluginConnected(P plugin, Context pluginContext) {
+ if (mConverter != null) {
+ mItem = mConverter.getInterfaceFromPlugin(plugin);
+ } else {
+ mItem = (T) plugin;
+ }
+ notifyChanged();
+ }
+
+ @Override
+ public void onPluginDisconnected(P plugin) {
+ mItem = null;
+ notifyChanged();
+ }
+
+ @Override
+ public T get() {
+ return mItem;
+ }
+
+ @Override
+ public void destroy() {
+ Dependency.get(PluginManager.class).removePluginListener(this);
+ }
+ }
+
+ private class TunerItem<T> implements Producer<T>, Tunable {
+ private final TunerFactory<T> mFactory;
+ private final ArrayMap<String, String> mSettings = new ArrayMap<>();
+ private T mItem;
+
+ public TunerItem(TunerFactory<T> factory, String... setting) {
+ mFactory = factory;
+ Dependency.get(TunerService.class).addTunable(this, setting);
+ }
+
+ @Override
+ public T get() {
+ return mItem;
+ }
+
+ @Override
+ public void destroy() {
+ Dependency.get(TunerService.class).removeTunable(this);
+ }
+
+ @Override
+ public void onTuningChanged(String key, String newValue) {
+ mSettings.put(key, newValue);
+ mItem = mFactory.create(mSettings);
+ notifyChanged();
+ }
+ }
+
+ private class Default<T> implements Producer<T> {
+ private final Supplier<T> mSupplier;
+
+ public Default(Supplier<T> supplier) {
+ mSupplier = supplier;
+ }
+
+ @Override
+ public T get() {
+ return mSupplier.get();
+ }
+
+ @Override
+ public void destroy() {
+
+ }
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
index 03c46e8..91acf04 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
@@ -17,8 +17,11 @@
import android.content.Context;
import android.content.Intent;
+import android.database.ContentObserver;
import android.net.NetworkCapabilities;
+import android.os.Handler;
import android.os.Looper;
+import android.provider.Settings.Global;
import android.telephony.PhoneStateListener;
import android.telephony.ServiceState;
import android.telephony.SignalStrength;
@@ -49,6 +52,7 @@
private final SubscriptionDefaults mDefaults;
private final String mNetworkNameDefault;
private final String mNetworkNameSeparator;
+ private final ContentObserver mObserver;
@VisibleForTesting
final PhoneStateListener mPhoneStateListener;
// Save entire info for logging, we only use the id.
@@ -97,6 +101,12 @@
mLastState.iconGroup = mCurrentState.iconGroup = mDefaultIcons;
// Get initial data sim state.
updateDataSim();
+ mObserver = new ContentObserver(new Handler(receiverLooper)) {
+ @Override
+ public void onChange(boolean selfChange) {
+ updateTelephony();
+ }
+ };
}
public void setConfiguration(Config config) {
@@ -144,6 +154,11 @@
| PhoneStateListener.LISTEN_DATA_CONNECTION_STATE
| PhoneStateListener.LISTEN_DATA_ACTIVITY
| PhoneStateListener.LISTEN_CARRIER_NETWORK_CHANGE);
+ mContext.getContentResolver().registerContentObserver(Global.getUriFor(Global.MOBILE_DATA),
+ true, mObserver);
+ mContext.getContentResolver().registerContentObserver(Global.getUriFor(
+ Global.MOBILE_DATA + mSubscriptionInfo.getSubscriptionId()),
+ true, mObserver);
}
/**
@@ -151,6 +166,7 @@
*/
public void unregisterListener() {
mPhone.listen(mPhoneStateListener, 0);
+ mContext.getContentResolver().unregisterContentObserver(mObserver);
}
/**
@@ -242,11 +258,11 @@
description = mCurrentState.isEmergency ? null : mCurrentState.networkName;
}
boolean activityIn = mCurrentState.dataConnected
- && !mCurrentState.carrierNetworkChangeMode
- && mCurrentState.activityIn;
+ && !mCurrentState.carrierNetworkChangeMode
+ && mCurrentState.activityIn;
boolean activityOut = mCurrentState.dataConnected
- && !mCurrentState.carrierNetworkChangeMode
- && mCurrentState.activityOut;
+ && !mCurrentState.carrierNetworkChangeMode
+ && mCurrentState.activityOut;
showDataIcon &= mCurrentState.isDefault || dataDisabled;
int typeIcon = showDataIcon ? icons.mDataType : 0;
callback.setMobileDataIndicators(statusIcon, qsIcon, typeIcon, qsTypeIcon,
@@ -294,7 +310,7 @@
final int iconMode = mServiceState.getCdmaEriIconMode();
return mServiceState.getCdmaEriIconIndex() != EriInfo.ROAMING_INDICATOR_OFF
&& (iconMode == EriInfo.ROAMING_ICON_MODE_NORMAL
- || iconMode == EriInfo.ROAMING_ICON_MODE_FLASH);
+ || iconMode == EriInfo.ROAMING_ICON_MODE_FLASH);
} else {
return mServiceState != null && mServiceState.getRoaming();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java
index eb47a3c..5657560 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java
@@ -43,7 +43,6 @@
void addEmergencyListener(EmergencyListener listener);
void removeEmergencyListener(EmergencyListener listener);
- void setUserSetupComplete(boolean userSetup);
boolean hasEmergencyCryptKeeperText();
boolean isRadioOn();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
index d7c919d..51d931e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
@@ -551,17 +551,11 @@
updateAirplaneMode(true /* force */);
}
- public void setUserSetupComplete(final boolean userSetup) {
- mReceiverHandler.post(new Runnable() {
- @Override
- public void run() {
- handleSetUserSetupComplete(userSetup);
- }
- });
+ private void setUserSetupComplete(final boolean userSetup) {
+ mReceiverHandler.post(() -> handleSetUserSetupComplete(userSetup));
}
- @VisibleForTesting
- void handleSetUserSetupComplete(boolean userSetup) {
+ private void handleSetUserSetupComplete(boolean userSetup) {
mUserSetup = userSetup;
for (MobileSignalController controller : mMobileSignalControllers.values()) {
controller.setUserSetupComplete(mUserSetup);
@@ -723,6 +717,7 @@
mDemoMode = true;
mDemoInetCondition = mInetCondition;
mDemoWifiState = mWifiSignalController.getState();
+ mDemoWifiState.ssid = "DemoMode";
} else if (mDemoMode && command.equals(COMMAND_EXIT)) {
if (DEBUG) Log.d(TAG, "Exiting demo mode");
mDemoMode = false;
@@ -768,6 +763,25 @@
: Math.min(Integer.parseInt(level), WifiIcons.WIFI_LEVEL_COUNT - 1);
mDemoWifiState.connected = mDemoWifiState.level >= 0;
}
+ String activity = args.getString("activity");
+ if (activity != null) {
+ switch (activity) {
+ case "inout":
+ mWifiSignalController.setActivity(WifiManager.DATA_ACTIVITY_INOUT);
+ break;
+ case "in":
+ mWifiSignalController.setActivity(WifiManager.DATA_ACTIVITY_IN);
+ break;
+ case "out":
+ mWifiSignalController.setActivity(WifiManager.DATA_ACTIVITY_OUT);
+ break;
+ default:
+ mWifiSignalController.setActivity(WifiManager.DATA_ACTIVITY_NONE);
+ break;
+ }
+ } else {
+ mWifiSignalController.setActivity(WifiManager.DATA_ACTIVITY_NONE);
+ }
mDemoWifiState.enabled = show;
mWifiSignalController.notifyListeners();
}
@@ -837,7 +851,23 @@
}
String activity = args.getString("activity");
if (activity != null) {
- controller.setActivity(Integer.parseInt(activity));
+ controller.getState().dataConnected = true;
+ switch (activity) {
+ case "inout":
+ controller.setActivity(TelephonyManager.DATA_ACTIVITY_INOUT);
+ break;
+ case "in":
+ controller.setActivity(TelephonyManager.DATA_ACTIVITY_IN);
+ break;
+ case "out":
+ controller.setActivity(TelephonyManager.DATA_ACTIVITY_OUT);
+ break;
+ default:
+ controller.setActivity(TelephonyManager.DATA_ACTIVITY_NONE);
+ break;
+ }
+ } else {
+ controller.setActivity(TelephonyManager.DATA_ACTIVITY_NONE);
}
controller.getState().enabled = show;
controller.notifyListeners();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
index 6df4a21..a776e99 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
@@ -59,7 +59,7 @@
import com.android.systemui.SystemUISecondaryUserService;
import com.android.systemui.plugins.qs.QS.DetailAdapter;
import com.android.systemui.qs.tiles.UserDetailView;
-import com.android.systemui.ActivityStarter;
+import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.statusbar.phone.SystemUIDialog;
import com.android.systemui.util.NotificationChannels;
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/DemoModeFragment.java b/packages/SystemUI/src/com/android/systemui/tuner/DemoModeFragment.java
index 0a962f1..7c98e13 100644
--- a/packages/SystemUI/src/com/android/systemui/tuner/DemoModeFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/tuner/DemoModeFragment.java
@@ -163,7 +163,7 @@
intent.putExtra("sims", "1");
intent.putExtra("nosim", "false");
intent.putExtra("level", "4");
- intent.putExtra("datatypel", "");
+ intent.putExtra("datatype", "lte");
getContext().sendBroadcast(intent);
// Need to send this after so that the sim controller already exists.
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/LockscreenFragment.java b/packages/SystemUI/src/com/android/systemui/tuner/LockscreenFragment.java
index 410d3d2..2df1793 100644
--- a/packages/SystemUI/src/com/android/systemui/tuner/LockscreenFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/tuner/LockscreenFragment.java
@@ -52,11 +52,13 @@
import com.android.systemui.plugins.IntentButtonProvider.IntentButton;
import com.android.systemui.statusbar.ScalingDrawableWrapper;
import com.android.systemui.statusbar.phone.ExpandableIndicator;
+import com.android.systemui.statusbar.policy.ExtensionController.TunerFactory;
import com.android.systemui.tuner.ShortcutParser.Shortcut;
import com.android.systemui.tuner.TunerService.Tunable;
import java.util.ArrayList;
import java.util.List;
+import java.util.Map;
import java.util.function.Consumer;
public class LockscreenFragment extends PreferenceFragment {
@@ -313,26 +315,39 @@
}
}
- public static IntentButton getIntentButton(Context context, String buttonStr,
- IntentButton plugin, IntentButton def) {
- // Plugin wins.
- if (plugin != null) return plugin;
- // Then tuner options.
- if (!TextUtils.isEmpty(buttonStr)) {
- if (buttonStr.contains("::")) {
- Shortcut shortcut = getShortcutInfo(context, buttonStr);
- if (shortcut != null) {
- return new ShortcutButton(context, shortcut);
- }
- } else if (buttonStr.contains("/")) {
- ActivityInfo info = getActivityinfo(context, buttonStr);
- if (info != null) {
- return new ActivityButton(context, info);
+ public static class LockButtonFactory implements TunerFactory<IntentButton> {
+
+ private final String mKey;
+ private final Context mContext;
+
+ public LockButtonFactory(Context context, String key) {
+ mContext = context;
+ mKey = key;
+ }
+
+ @Override
+ public String[] keys() {
+ return new String[]{mKey};
+ }
+
+ @Override
+ public IntentButton create(Map<String, String> settings) {
+ String buttonStr = settings.get(mKey);
+ if (!TextUtils.isEmpty(buttonStr)) {
+ if (buttonStr.contains("::")) {
+ Shortcut shortcut = getShortcutInfo(mContext, buttonStr);
+ if (shortcut != null) {
+ return new ShortcutButton(mContext, shortcut);
+ }
+ } else if (buttonStr.contains("/")) {
+ ActivityInfo info = getActivityinfo(mContext, buttonStr);
+ if (info != null) {
+ return new ActivityButton(mContext, info);
+ }
}
}
+ return null;
}
- // Then default.
- return def;
}
private static class ShortcutButton implements IntentButton {
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogComponent.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogComponent.java
index 0a1d34f..9d0ecec 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogComponent.java
@@ -25,7 +25,7 @@
import android.os.Handler;
import android.view.WindowManager;
-import com.android.systemui.ActivityStarter;
+import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.Dependency;
import com.android.systemui.SystemUI;
import com.android.systemui.SystemUIFactory;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/SysuiTestCase.java b/packages/SystemUI/tests/src/com/android/systemui/SysuiTestCase.java
index 6c454e1..c0e7e80 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/SysuiTestCase.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/SysuiTestCase.java
@@ -23,7 +23,6 @@
import android.os.MessageQueue;
import android.support.test.InstrumentationRegistry;
import android.util.ArrayMap;
-import android.util.Log;
import com.android.systemui.Dependency.DependencyKey;
import com.android.systemui.utils.TestableContext;
@@ -32,8 +31,6 @@
import org.junit.After;
import org.junit.Before;
-import java.lang.Thread.UncaughtExceptionHandler;
-
/**
* Base class that does System UI specific setup.
*/
@@ -92,8 +89,10 @@
return null;
}
- public <T> void injectMockDependency(Class<T> cls) {
- injectTestDependency(cls, mock(cls));
+ public <T> T injectMockDependency(Class<T> cls) {
+ final T mock = mock(cls);
+ mDependency.injectTestDependency(cls, mock);
+ return mock;
}
public <T> void injectTestDependency(Class<T> cls, T obj) {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/plugins/PluginManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/plugins/PluginManagerTest.java
index 09ac5a6..053e5cf2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/plugins/PluginManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/plugins/PluginManagerTest.java
@@ -76,7 +76,7 @@
public void testOneShot() {
Plugin mockPlugin = mock(Plugin.class);
when(mMockPluginInstance.getPlugin()).thenReturn(new PluginInfo(null, null, mockPlugin,
- null));
+ null, null));
Plugin result = mPluginManager.getOneShotPlugin("myAction", TestPlugin.class);
assertTrue(result == mockPlugin);
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationMenuRowTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationMenuRowTest.java
index 72f6ca8..b8be4fa 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationMenuRowTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationMenuRowTest.java
@@ -25,7 +25,7 @@
import org.junit.runner.RunWith;
@RunWith(SysUIRunner.class)
-@RunWithLooper
+@RunWithLooper(setAsMainLooper = true)
public class NotificationMenuRowTest extends LeakCheckedTest {
@Before
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/QuickStatusBarHeaderTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/QuickStatusBarHeaderTest.java
new file mode 100644
index 0000000..99cecff
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/QuickStatusBarHeaderTest.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the
+ * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+package com.android.systemui.statusbar.phone;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
+
+import android.os.Handler;
+import android.os.Looper;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.FrameLayout;
+import android.widget.TextView;
+
+import com.android.systemui.R;
+import com.android.systemui.R.layout;
+import com.android.systemui.SysUIRunner;
+import com.android.systemui.utils.TestableLooper;
+import com.android.systemui.utils.TestableLooper.RunWithLooper;
+import com.android.systemui.utils.ViewUtils;
+import com.android.systemui.utils.leaks.LeakCheckedTest;
+
+import org.junit.Before;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.ArrayList;
+
+@RunWith(SysUIRunner.class)
+@RunWithLooper(setAsMainLooper = true)
+public class QuickStatusBarHeaderTest extends LeakCheckedTest {
+
+ @Before
+ public void setup() throws NoSuchFieldException, IllegalAccessException {
+ injectLeakCheckedDependencies(ALL_SUPPORTED_CLASSES);
+ }
+
+ @Test
+ @Ignore("Flaky")
+ public void testRoamingStuck() throws Exception {
+ TestableLooper looper = TestableLooper.get(this);
+ assertEquals(Looper.myLooper(), looper.getLooper());
+ assertEquals(Looper.myLooper(), Looper.getMainLooper());
+ QuickStatusBarHeader header = (QuickStatusBarHeader) LayoutInflater.from(mContext).inflate(
+ layout.quick_status_bar_expanded_header, null);
+ header.setExpanded(true);
+
+ ViewUtils.attachView(header);
+ looper.processMessages(1);
+ TextView emergencyText = (TextView) header.findViewById(
+ R.id.header_emergency_calls_only);
+ int subId = 0;
+ header.setMobileDataIndicators(null, null, 0, 0, false,
+ false, null, null, false, subId, true);
+ looper.processAllMessages();
+ assertEquals(mContext.getString(R.string.accessibility_data_connection_roaming),
+ emergencyText.getText());
+ assertEquals(View.VISIBLE, emergencyText.getVisibility());
+
+ header.setSubs(new ArrayList<>());
+ subId = 1;
+ header.setMobileDataIndicators(null, null, 0, 0, false,
+ false, null, null, false, subId, false);
+ looper.processAllMessages();
+
+ assertNotEquals(View.VISIBLE, emergencyText.getVisibility());
+ assertEquals(Looper.myLooper(), Looper.getMainLooper());
+ ViewUtils.detachView(header);
+ looper.processAllMessages();
+ }
+
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/ExtensionControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/ExtensionControllerTest.java
new file mode 100644
index 0000000..e3a5ef0
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/ExtensionControllerTest.java
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the
+ * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+package com.android.systemui.statusbar.policy;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+
+import com.android.systemui.Dependency;
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.plugins.OverlayPlugin;
+import com.android.systemui.plugins.PluginManager;
+import com.android.systemui.statusbar.policy.ExtensionController.Extension;
+import com.android.systemui.statusbar.policy.ExtensionController.TunerFactory;
+import com.android.systemui.tuner.TunerService;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import java.util.Map;
+import java.util.function.Consumer;
+
+public class ExtensionControllerTest extends SysuiTestCase {
+
+ private PluginManager mPluginManager;
+ private TunerService mTunerService;
+ private ExtensionController mExtensionController;
+
+ @Before
+ public void setup() {
+ mPluginManager = injectMockDependency(PluginManager.class);
+ mTunerService = injectMockDependency(TunerService.class);
+ mExtensionController = Dependency.get(ExtensionController.class);
+ }
+
+ @Test
+ public void testPlugin() {
+ Extension ext = mExtensionController.newExtension(OverlayPlugin.class)
+ .withPlugin(OverlayPlugin.class)
+ .build();
+ verify(mPluginManager).addPluginListener(eq(OverlayPlugin.ACTION), any(),
+ eq(OverlayPlugin.class));
+
+ ext.destroy();
+ verify(mPluginManager).removePluginListener(any());
+ }
+
+ @Test
+ public void testTuner() {
+ String[] keys = new String[] { "key1", "key2" };
+ TunerFactory<Object> factory = new ExtensionController.TunerFactory() {
+ @Override
+ public String[] keys() {
+ return keys;
+ }
+
+ @Override
+ public Object create(Map settings) {
+ return null;
+ }
+ };
+ Extension ext = mExtensionController.newExtension(Object.class)
+ .withTunerFactory(factory)
+ .build();
+ verify(mTunerService).addTunable(any(), eq(keys[0]), eq(keys[1]));
+
+ ext.destroy();
+ verify(mTunerService).removeTunable(any());
+ }
+
+ @Test
+ public void testDefault() {
+ Object o = new Object();
+ Extension ext = mExtensionController.newExtension(Object.class)
+ .withDefault(() -> o)
+ .build();
+ assertEquals(o, ext.get());
+ }
+
+ @Test
+ public void testCallback() {
+ Consumer<Object> callback = mock(Consumer.class);
+ final Object o = new Object();
+ mExtensionController.newExtension(Object.class)
+ .withDefault(() -> o)
+ .withCallback(callback)
+ .build();
+ verify(callback).accept(eq(o));
+ }
+
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java
index 0e5f513..19b4b17 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java
@@ -31,6 +31,7 @@
import android.util.Log;
import com.android.internal.telephony.cdma.EriInfo;
import com.android.settingslib.net.DataUsageController;
+import com.android.systemui.statusbar.policy.DeviceProvisionedController.DeviceProvisionedListener;
import com.android.systemui.statusbar.policy.NetworkController.IconState;
import com.android.systemui.statusbar.policy.NetworkController.SignalCallback;
import com.android.systemui.statusbar.policy.NetworkControllerImpl.Config;
@@ -43,6 +44,8 @@
import org.junit.runner.Description;
import org.mockito.ArgumentCaptor;
import org.mockito.Mockito;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
import java.io.PrintWriter;
import java.io.StringWriter;
@@ -56,6 +59,7 @@
import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.anyString;
import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
@@ -82,6 +86,8 @@
protected CallbackHandler mCallbackHandler;
protected SubscriptionDefaults mMockSubDefaults;
protected NetworkScoreManager mMockNetworkScoreManager;
+ protected DeviceProvisionedController mMockProvisionController;
+ protected DeviceProvisionedListener mUserCallback;
protected int mSubId;
@@ -120,11 +126,21 @@
mConfig = new Config();
mConfig.hspaDataDistinguishable = true;
mCallbackHandler = mock(CallbackHandler.class);
+
+ mMockProvisionController = mock(DeviceProvisionedController.class);
+ when(mMockProvisionController.isUserSetup(anyInt())).thenReturn(true);
+ doAnswer(invocation -> {
+ mUserCallback = (DeviceProvisionedListener) invocation.getArguments()[0];
+ mUserCallback.onUserSetupChanged();
+ mUserCallback.onDeviceProvisionedChanged();
+ return null;
+ }).when(mMockProvisionController).addCallback(any());
+
mNetworkController = new NetworkControllerImpl(mContext, mMockCm, mMockNetworkScoreManager,
mMockTm, mMockWm, mMockSm,
mConfig, Looper.getMainLooper(), mCallbackHandler,
mock(AccessPointControllerImpl.class), mock(DataUsageController.class),
- mMockSubDefaults, mock(DeviceProvisionedController.class));
+ mMockSubDefaults, mMockProvisionController);
setupNetworkController();
// Trigger blank callbacks to always get the current state (some tests don't trigger
@@ -139,7 +155,6 @@
when(mMockTm.getDataEnabled(mSubId)).thenReturn(true);
setDefaultSubId(mSubId);
setSubscriptions(mSubId);
- mNetworkController.handleSetUserSetupComplete(true);
mMobileSignalController = mNetworkController.mMobileSignalControllers.get(mSubId);
mPhoneStateListener = mMobileSignalController.mPhoneStateListener;
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java
index d7f961c..ba20999 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java
@@ -1,16 +1,19 @@
package com.android.systemui.statusbar.policy;
+import static org.mockito.Matchers.anyInt;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
import android.net.NetworkCapabilities;
import android.os.Looper;
import android.support.test.runner.AndroidJUnit4;
import android.telephony.TelephonyManager;
import android.test.suitebuilder.annotation.SmallTest;
+
import com.android.settingslib.net.DataUsageController;
+
import org.junit.Test;
import org.junit.runner.RunWith;
-import org.mockito.Mockito;
@SmallTest
@RunWith(AndroidJUnit4.class)
@@ -106,7 +109,7 @@
@Test
public void testDataDisabledIcon() {
setupNetworkController();
- Mockito.when(mMockTm.getDataEnabled(mSubId)).thenReturn(false);
+ when(mMockTm.getDataEnabled(mSubId)).thenReturn(false);
setupDefaultSignal();
updateDataConnectionState(TelephonyManager.DATA_DISCONNECTED, 0);
setConnectivity(NetworkCapabilities.TRANSPORT_CELLULAR, false, false);
@@ -118,11 +121,12 @@
@Test
public void testDataDisabledIcon_UserNotSetup() {
setupNetworkController();
- Mockito.when(mMockTm.getDataEnabled(mSubId)).thenReturn(false);
+ when(mMockTm.getDataEnabled(mSubId)).thenReturn(false);
setupDefaultSignal();
updateDataConnectionState(TelephonyManager.DATA_DISCONNECTED, 0);
setConnectivity(NetworkCapabilities.TRANSPORT_CELLULAR, false, false);
- mNetworkController.handleSetUserSetupComplete(false);
+ when(mMockProvisionController.isUserSetup(anyInt())).thenReturn(false);
+ mUserCallback.onUserSetupChanged();
// Don't show the X until the device is setup.
verifyDataIndicators(0, 0);
@@ -154,7 +158,7 @@
verifyDataIndicators(TelephonyIcons.DATA_LTE[1][0 /* No direction */],
TelephonyIcons.QS_DATA_LTE);
- Mockito.when(mServiceState.getDataNetworkType())
+ when(mServiceState.getDataNetworkType())
.thenReturn(TelephonyManager.NETWORK_TYPE_HSPA);
updateServiceState();
verifyDataIndicators(TelephonyIcons.DATA_H[1][0 /* No direction */],
diff --git a/packages/SystemUI/tests/src/com/android/systemui/utils/TestableLooper.java b/packages/SystemUI/tests/src/com/android/systemui/utils/TestableLooper.java
index d275973..8902e0c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/utils/TestableLooper.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/utils/TestableLooper.java
@@ -244,9 +244,11 @@
mLooper.setAsMainLooper();
}
- mBase.evaluate();
-
- mLooper.destroy();
+ try {
+ mBase.evaluate();
+ } finally {
+ mLooper.destroy();
+ }
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/utils/ViewUtils.java b/packages/SystemUI/tests/src/com/android/systemui/utils/ViewUtils.java
index 07e5f66..678b9f4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/utils/ViewUtils.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/utils/ViewUtils.java
@@ -14,9 +14,11 @@
package com.android.systemui.utils;
+import android.content.pm.ApplicationInfo;
import android.graphics.PixelFormat;
import android.os.Handler;
import android.os.Looper;
+import android.util.Log;
import android.view.View;
import android.view.WindowManager;
import android.view.WindowManager.LayoutParams;
@@ -27,18 +29,19 @@
public class ViewUtils {
public static void attachView(View view) {
+ // Make sure hardware acceleration isn't turned on.
+ view.getContext().getApplicationInfo().flags &=
+ ~(ApplicationInfo.FLAG_HARDWARE_ACCELERATED);
WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT,
LayoutParams.TYPE_APPLICATION_OVERLAY,
0, PixelFormat.TRANSLUCENT);
- Handler handler = new Handler(Looper.getMainLooper());
- handler.post(() -> InstrumentationRegistry.getContext()
- .getSystemService(WindowManager.class).addView(view, lp));
+ InstrumentationRegistry.getContext()
+ .getSystemService(WindowManager.class).addView(view, lp);
}
public static void detachView(View view) {
- Handler handler = new Handler(Looper.getMainLooper());
- handler.post(() -> InstrumentationRegistry.getContext()
- .getSystemService(WindowManager.class).removeView(view));
+ InstrumentationRegistry.getContext()
+ .getSystemService(WindowManager.class).removeViewImmediate(view);
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeExtensionController.java b/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeExtensionController.java
new file mode 100644
index 0000000..c0f5783
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeExtensionController.java
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the
+ * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+package com.android.systemui.utils.leaks;
+
+import static org.mockito.Mockito.mock;
+
+import com.android.systemui.statusbar.policy.ExtensionController;
+
+import java.util.function.Consumer;
+import java.util.function.Supplier;
+
+public class FakeExtensionController implements ExtensionController {
+
+ private final Tracker mTracker;
+
+ public FakeExtensionController(LeakCheckedTest test) {
+ mTracker = test.getTracker("extension");
+ }
+
+ @Override
+ public <T> ExtensionBuilder<T> newExtension(Class<T> cls) {
+ final Object o = new Object();
+ mTracker.getLeakInfo(o).addAllocation(new Throwable());
+ return new FakeExtensionBuilder(o);
+ }
+
+ private class FakeExtensionBuilder<T> implements ExtensionBuilder<T> {
+ private final Object mAllocation;
+
+ public FakeExtensionBuilder(Object o) {
+ mAllocation = o;
+ }
+
+ @Override
+ public ExtensionBuilder<T> withTunerFactory(TunerFactory<T> factory) {
+ return this;
+ }
+
+ @Override
+ public <P extends T> ExtensionBuilder<T> withPlugin(Class<P> cls) {
+ return this;
+ }
+
+ @Override
+ public <P extends T> ExtensionBuilder<T> withPlugin(Class<P> cls, String action) {
+ return this;
+ }
+
+ @Override
+ public <P> ExtensionBuilder<T> withPlugin(Class<P> cls, String action, PluginConverter<T, P> converter) {
+ return this;
+ }
+
+ @Override
+ public ExtensionBuilder<T> withDefault(Supplier<T> def) {
+ return this;
+ }
+
+ @Override
+ public ExtensionBuilder<T> withCallback(Consumer<T> callback) {
+ return this;
+ }
+
+ @Override
+ public Extension build() {
+ return new FakeExtension(mAllocation);
+ }
+ }
+
+ private class FakeExtension<T> implements Extension<T> {
+ private final Object mAllocation;
+
+ public FakeExtension(Object allocation) {
+ mAllocation = allocation;
+ }
+
+ @Override
+ public T get() {
+ // TODO: Support defaults or things.
+ return null;
+ }
+
+ @Override
+ public void destroy() {
+ mTracker.getLeakInfo(mAllocation).clearAllocations();
+ }
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeNetworkController.java b/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeNetworkController.java
index 5497686..47ed5ca 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeNetworkController.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeNetworkController.java
@@ -47,11 +47,6 @@
}
@Override
- public void setUserSetupComplete(boolean userSetup) {
-
- }
-
- @Override
public boolean hasEmergencyCryptKeeperText() {
return false;
}
diff --git a/proto/src/metrics_constants.proto b/proto/src/metrics_constants.proto
index c81bd1b..c1c385a 100644
--- a/proto/src/metrics_constants.proto
+++ b/proto/src/metrics_constants.proto
@@ -3458,6 +3458,20 @@
// OPEN: Settings > Apps > Default Apps > Assist > Default voice input
DEFAULT_VOICE_INPUT_PICKER = 844;
+ // OPEN: Settings > Storage > [Profile]
+ SETTINGS_STORAGE_PROFILE = 845;
+
+ // OPEN: Settings > Security & screen lock -> Encryption & crendentials
+ // CATEGORY: SETTINGS
+ // OS: O
+ ENCRYPTION_AND_CREDENTIAL = 846;
+
+ // ACTION: Settings > About device > Build number
+ ACTION_SETTINGS_BUILD_NUMBER_PREF = 847;
+
+ // FIELD: Whether developer mode has already been enabled when clicking build number preference
+ FIELD_SETTINGS_BUILD_NUMBER_DEVELOPER_MODE_ENABLED = 848;
+
// ---- End O Constants, all O constants go above this line ----
// Add new aosp constants above this line.
diff --git a/proto/src/wifi.proto b/proto/src/wifi.proto
index 9416ac1..7eefb7e 100644
--- a/proto/src/wifi.proto
+++ b/proto/src/wifi.proto
@@ -435,9 +435,28 @@
// Number of occurrences of a soft AP session return code
message SoftApReturnCodeCount {
- // Return code of the soft AP session
- optional int32 return_code = 1;
+
+ enum SoftApStartResult {
+
+ // SoftApManager return code unknown
+ SOFT_AP_RETURN_CODE_UNKNOWN = 0;
+
+ // SoftAp started successfully
+ SOFT_AP_STARTED_SUCCESSFULLY = 1;
+
+ // Catch all for failures with no specific failure reason
+ SOFT_AP_FAILED_GENERAL_ERROR = 2;
+
+ // SoftAp failed to start due to NO_CHANNEL error
+ SOFT_AP_FAILED_NO_CHANNEL = 3;
+ }
+
+ // Historical, no longer used for writing as of 01/2017.
+ optional int32 return_code = 1 [deprecated = true];
// Occurrences of this soft AP return code
optional int32 count = 2;
+
+ // Result of attempt to start SoftAp
+ optional SoftApStartResult start_result = 3;
}
diff --git a/rs/jni/Android.mk b/rs/jni/Android.mk
index bf3681b..447a47d 100644
--- a/rs/jni/Android.mk
+++ b/rs/jni/Android.mk
@@ -19,22 +19,17 @@
LOCAL_STATIC_LIBRARIES :=
-rs_generated_include_dir := $(call intermediates-dir-for,SHARED_LIBRARIES,libRS,,)
-
LOCAL_C_INCLUDES += \
$(JNI_H_INCLUDE) \
frameworks/rs \
frameworks/base/core/jni \
- frameworks/base/libs/hwui \
- $(rs_generated_include_dir)
+ frameworks/base/libs/hwui
LOCAL_CFLAGS += -Wno-unused-parameter
LOCAL_CFLAGS += -Wall -Werror -Wunused -Wunreachable-code
-LOCAL_ADDITIONAL_DEPENDENCIES := $(addprefix $(rs_generated_include_dir)/,rsgApiFuncDecl.h)
LOCAL_MODULE:= librs_jni
-LOCAL_ADDITIONAL_DEPENDENCIES += $(rs_generated_source)
LOCAL_MODULE_TAGS := optional
-LOCAL_REQUIRED_MODULES := libRS libRSDriver
+LOCAL_REQUIRED_MODULES := libRS
include $(BUILD_SHARED_LIBRARY)
diff --git a/rs/jni/android_renderscript_RenderScript.cpp b/rs/jni/android_renderscript_RenderScript.cpp
index af370ff..2300da3 100644
--- a/rs/jni/android_renderscript_RenderScript.cpp
+++ b/rs/jni/android_renderscript_RenderScript.cpp
@@ -35,8 +35,8 @@
#include "android_runtime/android_util_AssetManager.h"
#include "android/graphics/GraphicsJNI.h"
-#include <rs.h>
#include <rsEnv.h>
+#include <rsApiStubs.h>
#include <gui/Surface.h>
#include <gui/GLConsumer.h>
#include <android_runtime/android_graphics_SurfaceTexture.h>
@@ -1134,7 +1134,7 @@
// we will pack mType; mKind; mNormalized; mVectorSize; NumSubElements
assert(dataSize == 5);
- uintptr_t elementData[5];
+ uint32_t elementData[5];
rsaElementGetNativeData((RsContext)con, (RsElement)id, elementData, dataSize);
for(jint i = 0; i < dataSize; i ++) {
@@ -1157,7 +1157,7 @@
uintptr_t *ids = (uintptr_t*)malloc(dataSize * sizeof(uintptr_t));
const char **names = (const char **)malloc(dataSize * sizeof(const char *));
- uint32_t *arraySizes = (uint32_t *)malloc(dataSize * sizeof(uint32_t));
+ size_t *arraySizes = (size_t *)malloc(dataSize * sizeof(size_t));
rsaElementGetSubElements((RsContext)con, (RsElement)id, ids, names, arraySizes,
(uint32_t)dataSize);
diff --git a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
index 4d2b106..c50623e 100644
--- a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
+++ b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
@@ -709,7 +709,7 @@
}
private boolean isUserRunningAndUnlocked(@UserIdInt int userId) {
- return mUserManager.isUserRunning(userId) && StorageManager.isUserKeyUnlocked(userId);
+ return mUserManager.isUserUnlockingOrUnlocked(userId);
}
@Override
diff --git a/services/autofill/java/com/android/server/autofill/AnchoredWindow.java b/services/autofill/java/com/android/server/autofill/AnchoredWindow.java
deleted file mode 100644
index 64c6abd..0000000
--- a/services/autofill/java/com/android/server/autofill/AnchoredWindow.java
+++ /dev/null
@@ -1,292 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.server.autofill;
-
-import static com.android.server.autofill.Helper.DEBUG;
-
-import android.annotation.Nullable;
-import android.content.Context;
-import android.graphics.PixelFormat;
-import android.graphics.Rect;
-import android.os.IBinder;
-import android.util.Slog;
-import android.view.Gravity;
-import android.view.MotionEvent;
-import android.view.View;
-import android.view.View.MeasureSpec;
-import android.view.WindowManager;
-import android.view.WindowManager.LayoutParams;
-import android.widget.FrameLayout;
-
-/**
- * A window above the application that is smartly anchored to a rectangular region.
- */
-final class AnchoredWindow implements View.OnLayoutChangeListener, View.OnTouchListener {
- private static final String TAG = "AutoFill";
-
- private static final int NULL_HEIGHT = -1;
-
- private final WindowManager mWm;
- private final IBinder mAppToken;
- private final View mContentView;
-
- private final View mWindowSizeListenerView;
- private final int mMinMargin;
-
- private int mLastHeight = NULL_HEIGHT;
- @Nullable
- private Rect mLastBounds;
- @Nullable
- private Rect mLastDisplayBounds;
-
- /**
- * Constructor.
- *
- * @param wm window manager that draws the content on a window
- * @param appToken token to pass to window manager
- * @param contentView content of the window
- */
- AnchoredWindow(WindowManager wm, IBinder appToken, View contentView) {
- mWm = wm;
- mAppToken = appToken;
- mContentView = contentView;
-
- mContentView.addOnLayoutChangeListener(this);
-
- Context context = contentView.getContext();
-
- mWindowSizeListenerView = new FrameLayout(context);
- mWindowSizeListenerView.addOnLayoutChangeListener(this);
-
- mMinMargin = context.getResources().getDimensionPixelSize(
- com.android.internal.R.dimen.autofill_fill_min_margin);
- }
-
- /**
- * Shows the window.
- *
- * @param bounds the region the window should be anchored to
- */
- void show(Rect bounds) {
- if (DEBUG) Slog.d(TAG, "show bounds=" + bounds);
-
- if (!mWindowSizeListenerView.isAttachedToWindow()) {
- if (DEBUG) Slog.d(TAG, "adding mWindowSizeListenerView");
- LayoutParams params = createWindowLayoutParams(
- mAppToken,
- LayoutParams.FLAG_NOT_TOUCHABLE); // not touchable
- params.gravity = Gravity.LEFT | Gravity.TOP;
- params.x = 0;
- params.y = 0;
- params.width = LayoutParams.MATCH_PARENT;
- params.height = LayoutParams.MATCH_PARENT;
- mWm.addView(mWindowSizeListenerView, params);
- }
-
- updateBounds(bounds);
- }
-
- /**
- * Hides the window.
- */
- void hide() {
- if (DEBUG) Slog.d(TAG, "hide");
-
- mLastHeight = NULL_HEIGHT;
- mLastBounds = null;
- mLastDisplayBounds = null;
-
- if (mWindowSizeListenerView.isAttachedToWindow()) {
- if (DEBUG) Slog.d(TAG, "removing mWindowSizeListenerView");
- mWm.removeView(mWindowSizeListenerView);
- }
-
- if (mContentView.isAttachedToWindow()) {
- if (DEBUG) Slog.d(TAG, "removing mContentView");
- mContentView.setOnTouchListener(null);
- mWm.removeView(mContentView);
- }
- }
-
- @Override
- public void onLayoutChange(View view, int left, int top, int right, int bottom,
- int oldLeft, int oldTop, int oldRight, int oldBottom) {
- if (view == mWindowSizeListenerView) {
- if (DEBUG) Slog.d(TAG, "onLayoutChange() for mWindowSizeListenerView");
- // mWindowSizeListenerView layout changed, get the size of the display bounds and updateLocked
- // the window.
- final Rect displayBounds = new Rect();
- view.getBoundsOnScreen(displayBounds);
- updateDisplayBounds(displayBounds);
- } else if (view == mContentView) {
- // mContentView layout changed, updateLocked the window in case its height changed.
- if (DEBUG) Slog.d(TAG, "onLayoutChange() for mContentView");
- updateHeight();
- }
- }
-
- // When the window is touched outside, hide the window.
- @Override
- public boolean onTouch(View view, MotionEvent event) {
- if (view == mContentView && event.getAction() == MotionEvent.ACTION_OUTSIDE) {
- hide();
- return true;
- }
- return false;
- }
-
- private boolean updateHeight() {
- final Rect displayBounds = mLastDisplayBounds;
- if (displayBounds == null) {
- return false;
- }
-
- mContentView.measure(
- MeasureSpec.makeMeasureSpec(displayBounds.width(), MeasureSpec.AT_MOST),
- MeasureSpec.makeMeasureSpec(displayBounds.height(), MeasureSpec.AT_MOST));
- int height = mContentView.getMeasuredHeight();
- if (height != mLastHeight) {
- if (DEBUG) Slog.d(TAG, "updateLocked height=" + height);
- mLastHeight = height;
- update(height, mLastBounds, displayBounds);
- return true;
- } else {
- return false;
- }
- }
-
- private void updateBounds(Rect bounds) {
- if (!bounds.equals(mLastBounds)) {
- if (DEBUG) Slog.d(TAG, "updateLocked bounds=" + bounds);
- mLastBounds = bounds;
-
- update(mLastHeight, bounds, mLastDisplayBounds);
- }
- }
-
- private void updateDisplayBounds(Rect displayBounds) {
- if (!displayBounds.equals(mLastDisplayBounds)) {
- if (DEBUG) Slog.d(TAG, "updateLocked displayBounds=" + displayBounds);
- mLastDisplayBounds = displayBounds;
-
- if (!updateHeight()) {
- update(mLastHeight, mLastBounds, displayBounds);
- }
- }
- }
-
- // Updates the window if height, bounds, and displayBounds are not null.
- // Caller should ensure that something changed before calling.
- private void update(int height, @Nullable Rect bounds, @Nullable Rect displayBounds) {
- if (height == NULL_HEIGHT || bounds == null || displayBounds == null) {
- return;
- }
-
- if (DEBUG) Slog.d(TAG, "updateLocked height=" + height + ", bounds=" + bounds
- + ", displayBounds=" + displayBounds);
-
- final LayoutParams params = createWindowLayoutParams(mAppToken,
- LayoutParams.FLAG_NOT_TOUCH_MODAL // outside touches go to windows behind us
- | LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH); // outside touches trigger MotionEvent
- params.setTitle("AutoFill Fill"); // used for debugging
- updatePosition(params, height, mMinMargin, bounds, displayBounds);
- if (!mContentView.isAttachedToWindow()) {
- if (DEBUG) Slog.d(TAG, "adding mContentView");
- mWm.addView(mContentView, params);
- mContentView.setOnTouchListener(this);
- } else {
- if (DEBUG) Slog.d(TAG, "updating mContentView");
- mWm.updateViewLayout(mContentView, params);
- }
- }
-
- /**
- * Updates the position of the window by altering the {@link LayoutParams}.
- *
- * <p>The window can be anchored either above or below the bounds. Anchoring the window below
- * the bounds is preferred, if it fits. Otherwise, anchor the window on the side with more
- * space.
- *
- * @param params the params to updateLocked
- * @param height the requested height of the window
- * @param minMargin the minimum margin between the window and the display bounds
- * @param bounds the region the window should be anchored to
- * @param displayBounds the region in which the window may be displayed
- */
- private static void updatePosition(
- LayoutParams params,
- int height,
- int minMargin,
- Rect bounds,
- Rect displayBounds) {
- boolean below;
- int verticalSpace;
- final int verticalSpaceBelow = displayBounds.bottom - bounds.bottom - minMargin;
- if (height <= verticalSpaceBelow) {
- // Fits below bounds.
- below = true;
- verticalSpace = height;
- } else {
- final int verticalSpaceAbove = bounds.top - displayBounds.top - minMargin;
- if (height <= verticalSpaceAbove) {
- // Fits above bounds.
- below = false;
- verticalSpace = height;
- } else {
- // Pick above/below based on which has the most space.
- if (verticalSpaceBelow >= verticalSpaceAbove) {
- below = true;
- verticalSpace = verticalSpaceBelow;
- } else {
- below = false;
- verticalSpace = verticalSpaceAbove;
- }
- }
- }
-
- int gravity;
- int y;
- if (below) {
- if (DEBUG) Slog.d(TAG, "anchorBelow");
- gravity = Gravity.TOP | Gravity.LEFT;
- y = bounds.bottom - displayBounds.top;
- } else {
- if (DEBUG) Slog.d(TAG, "anchorAbove");
- gravity = Gravity.BOTTOM | Gravity.LEFT;
- y = displayBounds.bottom - bounds.top;
- }
-
- final int x = bounds.left - displayBounds.left;
-
- params.gravity = gravity;
- params.x = x;
- params.y = y;
- params.width = bounds.width();
- params.height = verticalSpace;
- }
-
- private static LayoutParams createWindowLayoutParams(IBinder appToken, int flags) {
- final LayoutParams params = new LayoutParams();
- params.token = appToken;
- params.type = LayoutParams.TYPE_PHONE;
- params.flags =
- flags
- | LayoutParams.FLAG_NOT_FOCUSABLE // don't receive input events
- | LayoutParams.FLAG_ALT_FOCUSABLE_IM; // resize for soft input
- params.format = PixelFormat.TRANSLUCENT;
- return params;
- }
-}
diff --git a/services/autofill/java/com/android/server/autofill/AutoFillManagerService.java b/services/autofill/java/com/android/server/autofill/AutoFillManagerService.java
index 3257812..7a85d4e 100644
--- a/services/autofill/java/com/android/server/autofill/AutoFillManagerService.java
+++ b/services/autofill/java/com/android/server/autofill/AutoFillManagerService.java
@@ -18,7 +18,6 @@
import static android.Manifest.permission.MANAGE_AUTO_FILL;
import static android.content.Context.AUTO_FILL_MANAGER_SERVICE;
-import static com.android.server.autofill.Helper.DEBUG;
import static com.android.server.autofill.Helper.VERBOSE;
import android.Manifest;
@@ -57,6 +56,7 @@
import com.android.server.FgThread;
import com.android.server.LocalServices;
import com.android.server.SystemService;
+import com.android.server.autofill.ui.AutoFillUI;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -100,14 +100,16 @@
private SparseArray<AutoFillManagerServiceImpl> mServicesCache = new SparseArray<>();
// TODO(b/33197203): set a different max (or disable it) on low-memory devices.
- private final LocalLog mRequestsHistory = new LocalLog(100);
+ private final LocalLog mRequestsHistory = new LocalLog(20);
private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
if (Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(intent.getAction())) {
final String reason = intent.getStringExtra("reason");
- if (DEBUG) Slog.d(TAG, "close system dialogs: " + reason);
+ if (VERBOSE) {
+ Slog.v(TAG, "close system dialogs: " + reason);
+ }
mUi.hideAll();
}
}
@@ -246,7 +248,9 @@
private IBinder getTopActivityForUser() {
final List<IBinder> topActivities = LocalServices
.getService(ActivityManagerInternal.class).getTopVisibleActivities();
- if (DEBUG) Slog.d(TAG, "Top activities (" + topActivities.size() + "): " + topActivities);
+ if (VERBOSE) {
+ Slog.v(TAG, "Top activities (" + topActivities.size() + "): " + topActivities);
+ }
if (topActivities.isEmpty()) {
Slog.w(TAG, "Could not get top activity");
return null;
@@ -271,29 +275,20 @@
}
@Override
- public void startSession(IBinder activityToken, IBinder appCallback, AutoFillId autoFillId,
- Rect bounds, AutoFillValue value, int userId) {
+ public void startSession(IBinder activityToken, IBinder windowToken, IBinder appCallback,
+ AutoFillId autoFillId, Rect bounds, AutoFillValue value, int userId) {
// TODO(b/33197203): make sure it's called by resumed / focused activity
- if (VERBOSE) {
- Slog.v(TAG, "startSession: autoFillId=" + autoFillId + ", bounds=" + bounds
- + ", value=" + value);
- }
-
synchronized (mLock) {
final AutoFillManagerServiceImpl service = getServiceForUserLocked(userId);
- service.startSessionLocked(activityToken, appCallback, autoFillId, bounds, value);
+ service.startSessionLocked(activityToken, windowToken, appCallback,
+ autoFillId, bounds, value);
}
}
@Override
public void updateSession(IBinder activityToken, AutoFillId id, Rect bounds,
AutoFillValue value, int flags, int userId) {
- if (DEBUG) {
- Slog.d(TAG, "updateSession: flags=" + flags + ", autoFillId=" + id
- + ", bounds=" + bounds + ", value=" + value);
- }
-
synchronized (mLock) {
final AutoFillManagerServiceImpl service = mServicesCache.get(
UserHandle.getCallingUserId());
@@ -305,8 +300,6 @@
@Override
public void finishSession(IBinder activityToken, int userId) {
- if (VERBOSE) Slog.v(TAG, "finishSession(): " + activityToken);
-
synchronized (mLock) {
final AutoFillManagerServiceImpl service = mServicesCache.get(
UserHandle.getCallingUserId());
diff --git a/services/autofill/java/com/android/server/autofill/AutoFillManagerServiceImpl.java b/services/autofill/java/com/android/server/autofill/AutoFillManagerServiceImpl.java
index ec3d356..bfc6e83 100644
--- a/services/autofill/java/com/android/server/autofill/AutoFillManagerServiceImpl.java
+++ b/services/autofill/java/com/android/server/autofill/AutoFillManagerServiceImpl.java
@@ -56,6 +56,7 @@
import android.service.autofill.Dataset;
import android.service.autofill.FillResponse;
import android.service.autofill.IAutoFillService;
+import android.service.autofill.SaveInfo;
import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.ArraySet;
@@ -70,6 +71,7 @@
import com.android.internal.annotations.GuardedBy;
import com.android.internal.os.HandlerCaller;
import com.android.internal.os.IResultReceiver;
+import com.android.server.autofill.ui.AutoFillUI;
import java.io.PrintWriter;
import java.util.ArrayList;
@@ -103,7 +105,7 @@
handleSessionSave((IBinder) msg.obj);
break;
default:
- Slog.d(TAG, "invalid msg: " + msg);
+ Slog.w(TAG, "invalid msg on handler: " + msg);
}
};
@@ -127,17 +129,18 @@
private final IResultReceiver mAssistReceiver = new IResultReceiver.Stub() {
@Override
public void send(int resultCode, Bundle resultData) throws RemoteException {
- if (DEBUG) Slog.d(TAG, "resultCode on mAssistReceiver: " + resultCode);
+ if (VERBOSE) {
+ Slog.v(TAG, "resultCode on mAssistReceiver: " + resultCode);
+ }
final AssistStructure structure = resultData.getParcelable(KEY_STRUCTURE);
if (structure == null) {
- Slog.w(TAG, "no assist structure for id " + resultCode);
+ Slog.wtf(TAG, "no assist structure for id " + resultCode);
return;
}
final Bundle receiverExtras = resultData.getBundle(KEY_RECEIVER_EXTRAS);
if (receiverExtras == null) {
- // Should not happen
Slog.wtf(TAG, "No " + KEY_RECEIVER_EXTRAS + " on receiver");
return;
}
@@ -194,7 +197,7 @@
final ApplicationInfo info = pm.getApplicationInfo(packageName, 0);
return pm.getApplicationLabel(info);
} catch (Exception e) {
- Slog.w(TAG, "Could not get label for " + packageName + ": " + e);
+ Slog.e(TAG, "Could not get label for " + packageName + ": " + e);
return packageName;
}
}
@@ -210,7 +213,7 @@
serviceInfo = AppGlobals.getPackageManager().getServiceInfo(serviceComponent,
0, mUserId);
} catch (RuntimeException | RemoteException e) {
- Slog.e(TAG, "Bad auto-fill service name " + componentName, e);
+ Slog.e(TAG, "Bad auto-fill service name " + componentName + ": " + e);
return;
}
}
@@ -234,7 +237,7 @@
sendStateToClients();
}
} catch (PackageManager.NameNotFoundException e) {
- Slog.e(TAG, "Bad auto-fill service name " + componentName, e);
+ Slog.e(TAG, "Bad auto-fill service name " + componentName + ": " + e);
}
}
@@ -272,15 +275,15 @@
}
}
- void startSessionLocked(IBinder activityToken, IBinder appCallbackToken, AutoFillId autoFillId,
- Rect bounds, AutoFillValue value) {
+ void startSessionLocked(IBinder activityToken, IBinder windowToken, IBinder appCallbackToken,
+ AutoFillId autoFillId, Rect bounds, AutoFillValue value) {
if (!hasService()) {
return;
}
- final String historyItem = "s=" + new ComponentName(mInfo.getServiceInfo().packageName,
- mInfo.getServiceInfo().name) + " u=" + mUserId + " a=" + activityToken
- + " i=" + autoFillId + " b=" + bounds + " v=" + value;
+ final String historyItem = "s=" + mInfo.getServiceInfo().packageName
+ + " u=" + mUserId + " a=" + activityToken
+ + " i=" + autoFillId + " b=" + bounds;
mRequestsHistory.log(historyItem);
// TODO(b/33197203): Handle partitioning
@@ -290,7 +293,8 @@
return;
}
- final Session newSession = createSessionByTokenLocked(activityToken, appCallbackToken);
+ final Session newSession = createSessionByTokenLocked(activityToken,
+ windowToken, appCallbackToken);
newSession.updateLocked(autoFillId, bounds, value, FLAG_START_SESSION);
}
@@ -308,8 +312,10 @@
session.showSaveLocked();
}
- private Session createSessionByTokenLocked(IBinder activityToken, IBinder appCallbackToken) {
- final Session newSession = new Session(mContext, activityToken, appCallbackToken);
+ private Session createSessionByTokenLocked(IBinder activityToken, IBinder windowToken,
+ IBinder appCallbackToken) {
+ final Session newSession = new Session(mContext, activityToken,
+ windowToken, appCallbackToken);
mSessions.put(activityToken, newSession);
/*
@@ -327,8 +333,6 @@
try {
if (!ActivityManager.getService().requestAutoFillData(mAssistReceiver,
receiverExtras, activityToken)) {
- // TODO(b/33197203): might need a way to warn user (perhaps a new method on
- // AutoFillService).
Slog.w(TAG, "failed to request auto-fill data for " + activityToken);
}
} finally {
@@ -345,7 +349,9 @@
// TODO(b/33197203): add MetricsLogger call
final Session session = mSessions.get(activityToken);
if (session == null) {
- Slog.w(TAG, "updateSessionLocked(): session gone for " + activityToken);
+ if (VERBOSE) {
+ Slog.v(TAG, "updateSessionLocked(): session gone for " + activityToken);
+ }
return;
}
@@ -365,7 +371,9 @@
}
void destroyLocked() {
- if (VERBOSE) Slog.v(TAG, "destroyLocked()");
+ if (VERBOSE) {
+ Slog.v(TAG, "destroyLocked()");
+ }
for (Session session : mSessions.values()) {
session.destroyLocked();
@@ -376,7 +384,7 @@
void dumpLocked(String prefix, PrintWriter pw) {
final String prefix2 = prefix + " ";
- pw.print(prefix); pw.println("Component:"); pw.println(mInfo != null
+ pw.print(prefix); pw.print("Component:"); pw.println(mInfo != null
? mInfo.getServiceInfo().getComponentName() : null);
if (VERBOSE) {
@@ -522,8 +530,6 @@
@Override
public String toString() {
- if (!DEBUG) return super.toString();
-
return "ViewState: [id=" + mId + ", value=" + mAutoFillValue + ", bounds=" + mBounds
+ ", updated = " + mValueUpdated + "]";
}
@@ -556,6 +562,7 @@
final class Session implements RemoteFillService.FillServiceCallbacks, ViewState.Listener,
AutoFillUI.AutoFillUiCallback {
private final IBinder mActivityToken;
+ private final IBinder mWindowToken;
@GuardedBy("mLock")
private final Map<AutoFillId, ViewState> mViewStates = new ArrayMap<>();
@@ -587,15 +594,19 @@
@GuardedBy("mLock")
private AssistStructure mStructure;
- private Session(Context context, IBinder activityToken, IBinder client) {
+ private Session(Context context, IBinder activityToken, IBinder windowToken,
+ IBinder client) {
mRemoteFillService = new RemoteFillService(context,
mInfo.getServiceInfo().getComponentName(), mUserId, this);
mActivityToken = activityToken;
+ mWindowToken = windowToken;
mClient = IAutoFillManagerClient.Stub.asInterface(client);
try {
client.linkToDeath(() -> {
- if (DEBUG) Slog.d(TAG, "app binder died");
+ if (DEBUG) {
+ Slog.d(TAG, "app binder died");
+ }
removeSelf();
}, 0);
@@ -662,7 +673,9 @@
// AutoFillUiCallback
@Override
public void fill(Dataset dataset) {
- autoFill(dataset);
+ mHandlerCaller.getHandler().post(() -> {
+ autoFill(dataset);
+ });
}
// AutoFillUiCallback
@@ -696,26 +709,30 @@
*/
public void showSaveLocked() {
if (mStructure == null) {
- // Sanity check; should not happen...
Slog.wtf(TAG, "showSaveLocked(): no mStructure");
return;
}
if (mCurrentResponse == null) {
- // Happens when the activity / session was finished before the service replied.
- Slog.d(TAG, "showSaveLocked(): no mCurrentResponse yet");
+ // Happens when the activity / session was finished before the service replied, or
+ // when the service cannot auto-fill it (and returned a null response).
+ if (DEBUG) {
+ Slog.d(TAG, "showSaveLocked(): no mCurrentResponse");
+ }
return;
}
- final ArraySet<AutoFillId> savableIds = mCurrentResponse.getSavableIds();
- if (VERBOSE) Slog.v(TAG, "showSaveLocked(): savableIds=" + savableIds);
+ final SaveInfo saveInfo = mCurrentResponse.getSaveInfo();
+ if (DEBUG) {
+ Slog.d(TAG, "showSaveLocked(): saveInfo=" + saveInfo);
+ }
- if (savableIds.isEmpty()) {
- if (DEBUG) Slog.d(TAG, "showSaveLocked(): service doesn't want to save");
+ if (saveInfo == null || saveInfo.getSavableIds() == null
+ || saveInfo.getSavableIds().isEmpty()) {
return;
}
- final int size = savableIds.size();
+ final int size = saveInfo.getSavableIds().size();
for (int i = 0; i < size; i++) {
- final AutoFillId id = savableIds.valueAt(i);
+ final AutoFillId id = saveInfo.getSavableIds().valueAt(i);
final ViewState state = mViewStates.get(id);
if (state != null && state.mValueUpdated) {
final AutoFillValue filledValue = findValue(mAutoFilledDataset, id);
@@ -726,27 +743,35 @@
Slog.d(TAG, "finishSessionLocked(): found a change on " + id + ": "
+ state.mAutoFillValue);
}
- getUiForShowing().showSaveUi();
+ getUiForShowing().showSaveUi(
+ mInfo.getServiceInfo().loadLabel(mContext.getPackageManager()),
+ saveInfo);
return;
}
}
// Nothing changed...
- if (DEBUG) Slog.d(TAG, "showSaveLocked(): with no changes, comes no responsibilities");
+ if (DEBUG) {
+ Slog.d(TAG, "showSaveLocked(): with no changes, comes no responsibilities");
+ }
}
/**
* Calls service when user requested save.
*/
private void callSaveLocked() {
- if (DEBUG) Slog.d(TAG, "callSaveLocked(): mViewStates=" + mViewStates);
+ if (DEBUG) {
+ Slog.d(TAG, "callSaveLocked(): mViewStates=" + mViewStates);
+ }
final Bundle extras = this.mCurrentResponse.getExtras();
for (Entry<AutoFillId, ViewState> entry : mViewStates.entrySet()) {
final AutoFillValue value = entry.getValue().mAutoFillValue;
if (value == null) {
- if (VERBOSE) Slog.v(TAG, "callSaveLocked(): skipping " + entry.getKey());
+ if (VERBOSE) {
+ Slog.v(TAG, "callSaveLocked(): skipping " + entry.getKey());
+ }
continue;
}
final AutoFillId id = entry.getKey();
@@ -755,7 +780,9 @@
Slog.w(TAG, "callSaveLocked(): did not find node with id " + id);
continue;
}
- if (DEBUG) Slog.d(TAG, "callSaveLocked(): updating " + id + " to " + value);
+ if (VERBOSE) {
+ Slog.v(TAG, "callSaveLocked(): updating " + id + " to " + value);
+ }
node.updateAutoFillValue(value);
}
@@ -771,11 +798,9 @@
}
void updateLocked(AutoFillId id, Rect bounds, AutoFillValue value, int flags) {
- if (DEBUG) Slog.d(TAG, "updateLocked(): id=" + id + ", flags=" + flags);
-
if (mAutoFilledDataset != null && (flags & FLAG_VALUE_CHANGED) == 0) {
// TODO(b/33197203): ignoring because we don't support partitions yet
- if (DEBUG) Slog.d(TAG, "updateLocked(): ignoring " + flags + " after auto-filled");
+ Slog.d(TAG, "updateLocked(): ignoring " + flags + " after app was auto-filled");
return;
}
@@ -810,8 +835,9 @@
viewState.mAutoFillValue = value;
// Update the chooser UI
- mUi.updateFillUi(value.coerceToString());
+ getUiForShowing().filterFillUi(value.coerceToString());
}
+
return;
}
@@ -841,7 +867,7 @@
return;
}
- Slog.w(TAG, "unknown flags " + flags);
+ Slog.w(TAG, "updateLocked(): unknown flags " + flags);
}
@Override
@@ -860,8 +886,10 @@
}
private void processResponseLocked(FillResponse response) {
- if (DEBUG) Slog.d(TAG, "processResponseLocked(authRequired="
- + response.getAuthentication() + "):" + response);
+ if (DEBUG) {
+ Slog.d(TAG, "processResponseLocked(auth=" + response.getAuthentication()
+ + "):" + response);
+ }
// TODO(b/33197203): add MetricsLogger calls
@@ -945,7 +973,9 @@
void autoFillApp(Dataset dataset) {
synchronized (mLock) {
try {
- if (DEBUG) Slog.d(TAG, "autoFillApp(): the buck is on the app: " + dataset);
+ if (DEBUG) {
+ Slog.d(TAG, "autoFillApp(): the buck is on the app: " + dataset);
+ }
mClient.autoFill(dataset.getFieldIds(), dataset.getFieldValues());
} catch (RemoteException e) {
Slog.w(TAG, "Error auto-filling activity: " + e);
@@ -955,7 +985,7 @@
private AutoFillUI getUiForShowing() {
synchronized (mLock) {
- mUi.setCallbackLocked(this, mActivityToken);
+ mUi.setCallback(this, mWindowToken);
return mUi;
}
}
@@ -995,11 +1025,13 @@
private void destroyLocked() {
mRemoteFillService.destroy();
- mUi.setCallbackLocked(null, null);
+ mUi.setCallback(null, null);
}
private void removeSelf() {
- if (VERBOSE) Slog.v(TAG, "removeSelf()");
+ if (VERBOSE) {
+ Slog.v(TAG, "removeSelf()");
+ }
synchronized (mLock) {
destroyLocked();
diff --git a/services/autofill/java/com/android/server/autofill/AutoFillUI.java b/services/autofill/java/com/android/server/autofill/AutoFillUI.java
deleted file mode 100644
index ee485df..0000000
--- a/services/autofill/java/com/android/server/autofill/AutoFillUI.java
+++ /dev/null
@@ -1,271 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.server.autofill;
-
-import static com.android.server.autofill.Helper.DEBUG;
-
-import android.annotation.Nullable;
-import android.content.Context;
-import android.content.IntentSender;
-import android.graphics.Rect;
-import android.os.Handler;
-import android.os.IBinder;
-import android.service.autofill.Dataset;
-import android.service.autofill.FillResponse;
-import android.text.format.DateUtils;
-import android.util.Slog;
-import android.view.Gravity;
-import android.view.View;
-import android.view.WindowManager;
-import android.view.WindowManager.LayoutParams;
-import android.view.autofill.AutoFillId;
-import android.widget.Toast;
-
-import com.android.server.UiThread;
-
-import java.io.PrintWriter;
-
-/**
- * Handles all auto-fill related UI tasks.
- */
-// TODO(b/33197203): document exactly what once the auto-fill bar is implemented
-final class AutoFillUI {
- private static final String TAG = "AutoFillUI";
-
- private static final long SNACK_BAR_LIFETIME_MS = 5 * DateUtils.SECOND_IN_MILLIS;
-
- private static final int MSG_HIDE_SNACK_BAR = 1;
-
- private final Handler mHandler = UiThread.getHandler();
-
- private final Context mContext;
-
- private final WindowManager mWm;
-
- private AnchoredWindow mFillWindow;
-
- private DatasetPicker mDatasetPicker;
-
- private AutoFillUiCallback mCallback;
-
- private IBinder mActivityToken;
-
- /**
- * Custom snackbar UI used for saving autofill or other informational messages.
- */
- private View mSnackbar;
-
- AutoFillUI(Context context) {
- mContext = context;
- mWm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
- }
-
- void setCallbackLocked(AutoFillUiCallback callback, IBinder activityToken) {
- mHandler.post(() -> {
- if (callback != mCallback && activityToken != mActivityToken) {
- hideAllUiThread();
- mCallback = callback;
- mActivityToken = activityToken;
- }
- });
- }
-
- /**
- * Displays an error message to the user.
- */
- void showError(CharSequence message) {
- // TODO(b/33197203): proper implementation
- UiThread.getHandler().post(() -> {
- if (!hasCallback()) {
- return;
- }
- hideAllUiThread();
- Toast.makeText(mContext, "AutoFill error: " + message, Toast.LENGTH_LONG).show();
- });
- }
-
- /**
- * Hides the fill UI.
- */
- void hideFillUi() {
- mHandler.post(() -> hideFillUiUiThread());
- }
-
- @android.annotation.UiThread
- private void hideFillUiUiThread() {
- if (mFillWindow != null) {
- if (DEBUG) Slog.d(TAG, "hideFillUiUiThread(): hide" + mFillWindow);
- mFillWindow.hide();
- }
- mFillWindow = null;
- mDatasetPicker = null;
- }
-
- void updateFillUi(@Nullable String filterText) {
- mHandler.post(() -> {
- if (!hasCallback()) {
- return;
- }
- hideSnackbarUiThread();
- if (mDatasetPicker != null) {
- mDatasetPicker.update(filterText);
- }
- });
- }
-
- /**
- * Shows the fill UI, removing the previous fill UI if the has changed.
- *
- * @param focusedId the currently focused field
- * @param response the current fill response
- * @param bounds bounds of the view to be filled, used if changed
- * @param filterText text of the view to be filled, used if changed
- */
- void showFillUi(AutoFillId focusedId, @Nullable FillResponse response, Rect bounds,
- String filterText) {
- mHandler.post(() -> {
- if (!hasCallback()) {
- return;
- }
- hideSnackbarUiThread();
- final View content;
- if (response.getPresentation() != null) {
- content = response.getPresentation().apply(mContext, null);
- content.setOnClickListener((view) -> {
- if (mCallback != null) {
- mCallback.authenticate(response.getAuthentication());
- }
- hideFillUiUiThread();
- });
- } else {
- mDatasetPicker = new DatasetPicker(mContext, response.getDatasets(),
- focusedId, new DatasetPicker.Listener() {
- @Override
- public void onDatasetPicked(Dataset dataset) {
- if (mCallback != null) {
- mCallback.fill(dataset);
- }
- hideFillUiUiThread();
- }
-
- @Override
- public void onCanceled() {
- hideFillUiUiThread();
- }
- });
- mDatasetPicker.update(filterText);
- content = mDatasetPicker;
- }
-
- mFillWindow = new AnchoredWindow(mWm, mActivityToken, content);
- mFillWindow.show(bounds);
- });
- }
-
- /**
- * Shows the UI asking the user to save for auto-fill.
- */
- void showSaveUi() {
- mHandler.post(() -> {
- if (!hasCallback()) {
- return;
- }
- hideAllUiThread();
- showSnackbarUiThread(new SavePrompt(mContext,
- new SavePrompt.OnSaveListener() {
- @Override
- public void onSaveClick() {
- hideSnackbarUiThread();
- // TODO(b/33197203): add MetricsLogger call
- mCallback.save();
- }
-
- @Override
- public void onCancelClick() {
- // TODO(b/33197203): add MetricsLogger call
- hideSnackbarUiThread();
- }
- }));
- });
- }
-
- /**
- * Hides all UI affordances.
- */
- void hideAll() {
- mHandler.post(() -> hideAllUiThread());
- }
-
- @android.annotation.UiThread
- private void hideAllUiThread() {
- hideSnackbarUiThread();
- hideFillUiUiThread();
- }
-
- void dump(PrintWriter pw) {
- pw.println("AufoFill UI");
- final String prefix = " ";
- pw.print(prefix); pw.print("mActivityToken: "); pw.println(mActivityToken);
- pw.print(prefix); pw.print("mSnackBar: "); pw.println(mSnackbar);
- }
-
- //similar to a snackbar, but can be a bit custom since it is more than just text. This will
- //allow two buttons for saving or not saving the autofill for instance as well.
- @android.annotation.UiThread
- private void showSnackbarUiThread(View snackBar) {
- final LayoutParams params = new LayoutParams();
- params.type = LayoutParams.TYPE_PHONE; // TODO(b/33197203) use app window token
- params.flags =
- LayoutParams.FLAG_NOT_FOCUSABLE // don't receive input events,
- | LayoutParams.FLAG_ALT_FOCUSABLE_IM // resize for soft input
- | LayoutParams.FLAG_NOT_TOUCH_MODAL; // outside touches go to windows behind us
- params.softInputMode =
- LayoutParams.SOFT_INPUT_ADJUST_PAN; // pan with soft input
- params.gravity = Gravity.BOTTOM | Gravity.START;
- params.width = LayoutParams.MATCH_PARENT;
- params.height = LayoutParams.WRAP_CONTENT;
-
- mHandler.post(() -> {
- mSnackbar = snackBar;
- mWm.addView(mSnackbar, params);
- });
-
- if (DEBUG) {
- Slog.d(TAG, "showSnackbar(): auto dismissing it in " + SNACK_BAR_LIFETIME_MS + " ms");
- }
- mHandler.sendMessageDelayed(mHandler
- .obtainMessage(MSG_HIDE_SNACK_BAR), SNACK_BAR_LIFETIME_MS);
- }
-
- @android.annotation.UiThread
- private void hideSnackbarUiThread() {
- mHandler.removeMessages(MSG_HIDE_SNACK_BAR);
- if (mSnackbar != null) {
- mWm.removeView(mSnackbar);
- mSnackbar = null;
- }
- }
-
- private boolean hasCallback() {
- return mCallback != null;
- }
-
- interface AutoFillUiCallback {
- void authenticate(IntentSender intent);
- void fill(Dataset dataset);
- void save();
- }
-}
diff --git a/services/autofill/java/com/android/server/autofill/DatasetPicker.java b/services/autofill/java/com/android/server/autofill/DatasetPicker.java
deleted file mode 100644
index e25f2ce..0000000
--- a/services/autofill/java/com/android/server/autofill/DatasetPicker.java
+++ /dev/null
@@ -1,115 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.server.autofill;
-
-import android.content.Context;
-import android.service.autofill.Dataset;
-import android.util.ArraySet;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.autofill.AutoFillId;
-import android.view.autofill.AutoFillValue;
-import android.widget.AdapterView;
-import android.widget.AdapterView.OnItemClickListener;
-import android.widget.ArrayAdapter;
-import android.widget.FrameLayout;
-import android.widget.ListView;
-import android.widget.RemoteViews;
-import com.android.internal.R;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * This class manages the dataset selection UI.
- */
-final class DatasetPicker extends FrameLayout implements OnItemClickListener {
- interface Listener {
- void onDatasetPicked(Dataset dataset);
- void onCanceled();
- }
-
- private final Listener mListener;
-
- private final ArrayAdapter<ViewItem> mAdapter;
-
- DatasetPicker(Context context, ArrayList<Dataset> datasets, AutoFillId filteredViewId,
- Listener listener) {
- super(context);
- mListener = listener;
-
- final List<ViewItem> items = new ArrayList<>(datasets.size());
- for (Dataset dataset : datasets) {
- final int index = dataset.getFieldIds().indexOf(filteredViewId);
- if (index >= 0) {
- AutoFillValue value = dataset.getFieldValues().get(index);
- items.add(new ViewItem(dataset, value.coerceToString()));
- }
- }
-
- mAdapter = new ArrayAdapter<ViewItem>(context, 0, items) {
- @Override
- public View getView(int position, View convertView, ViewGroup parent) {
- RemoteViews presentation = getItem(position).getDataset().getPresentation();
- return presentation.apply(context, parent);
- }
- };
-
- LayoutInflater inflater = LayoutInflater.from(context);
- ListView content = (ListView) inflater.inflate(
- com.android.internal.R.layout.autofill_dataset_picker, this, true)
- .findViewById(com.android.internal.R.id.list);
- content.setAdapter(mAdapter);
- content.setOnItemClickListener(this);
- }
-
- public void update(String prefix) {
- mAdapter.getFilter().filter(prefix, (count) -> {
- if (count <= 0 && mListener != null) {
- mListener.onCanceled();
- }
- });
- }
-
- @Override
- public void onItemClick(AdapterView<?> adapterView, View view, int pos, long id) {
- if (mListener != null) {
- final ViewItem vi = (ViewItem) adapterView.getItemAtPosition(pos);
- mListener.onDatasetPicked(vi.getDataset());
- }
- }
-
- private static class ViewItem {
- private final String mValue;
- private final Dataset mDataset;
-
- ViewItem(Dataset dataset, String value) {
- mDataset = dataset;
- mValue = value;
- }
-
- public Dataset getDataset() {
- return mDataset;
- }
-
- @Override
- public String toString() {
- // used by ArrayAdapter
- return mValue;
- }
- }
-}
diff --git a/services/autofill/java/com/android/server/autofill/SavePrompt.java b/services/autofill/java/com/android/server/autofill/SavePrompt.java
deleted file mode 100644
index 85c6d7d..0000000
--- a/services/autofill/java/com/android/server/autofill/SavePrompt.java
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.autofill;
-
-import android.content.Context;
-import android.widget.RelativeLayout;
-import android.widget.TextView;
-import android.view.LayoutInflater;
-import android.view.View;
-
-import com.android.internal.R;
-
-/**
- * Autofill Save Prompt
- */
-final class SavePrompt extends RelativeLayout {
- public interface OnSaveListener {
- void onSaveClick();
- void onCancelClick();
- }
-
- private final TextView mNoButton;
- private final TextView mYesButton;
- private final OnSaveListener mListener;
-
- SavePrompt(Context context, OnSaveListener listener) {
- super(context);
- mListener = listener;
- LayoutInflater inflater = LayoutInflater.from(context);
- View view = inflater.inflate(R.layout.autofill_save, this);
-
- mNoButton = (TextView) view.findViewById(R.id.autofill_save_no);
- mNoButton.setOnClickListener((v) -> {
- mListener.onCancelClick();
- });
-
- mYesButton = (TextView) view.findViewById(R.id.autofill_save_yes);
- mYesButton.setOnClickListener((v) -> {
- mListener.onSaveClick();
- });
-
- }
-}
diff --git a/services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java b/services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java
new file mode 100644
index 0000000..949a80c
--- /dev/null
+++ b/services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java
@@ -0,0 +1,241 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.server.autofill.ui;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.Context;
+import android.content.IntentSender;
+import android.graphics.Rect;
+import android.os.Handler;
+import android.os.IBinder;
+import android.service.autofill.Dataset;
+import android.service.autofill.FillResponse;
+import android.service.autofill.SaveInfo;
+import android.text.TextUtils;
+import android.view.autofill.AutoFillId;
+import android.widget.Toast;
+
+import com.android.server.UiThread;
+
+import java.io.PrintWriter;
+
+/**
+ * Handles all auto-fill related UI tasks. The UI has two components:
+ * fill UI that shows a popup style window anchored at the focused
+ * input field for choosing a dataset to fill or trigger the response
+ * authentication flow; save UI that shows a toast style window for
+ * managing saving of user edits.
+ */
+public final class AutoFillUI {
+ private final Handler mHandler = UiThread.getHandler();
+ private final @NonNull Context mContext;
+
+ private @Nullable FillUi mFillUi;
+ private @Nullable SaveUi mSaveUi;
+
+ private @Nullable AutoFillUiCallback mCallback;
+ private @Nullable IBinder mWindowToken;
+
+ public interface AutoFillUiCallback {
+ void authenticate(@NonNull IntentSender intent);
+ void fill(@NonNull Dataset dataset);
+ void save();
+ }
+
+ public AutoFillUI(@NonNull Context context) {
+ mContext = context;
+ }
+
+ public void setCallback(@Nullable AutoFillUiCallback callback,
+ @Nullable IBinder windowToken) {
+ mHandler.post(() -> {
+ if (mCallback != callback || mWindowToken != windowToken) {
+ hideAllUiThread();
+ mCallback = callback;
+ mWindowToken = windowToken;
+ }
+ });
+ }
+
+ /**
+ * Displays an error message to the user.
+ */
+ public void showError(@Nullable CharSequence message) {
+ mHandler.post(() -> {
+ if (!hasCallback()) {
+ return;
+ }
+ hideAllUiThread();
+ if (!TextUtils.isEmpty(message)) {
+ Toast.makeText(mContext, message, Toast.LENGTH_LONG).show();
+ }
+ });
+ }
+
+ /**
+ * Hides the fill UI.
+ */
+ public void hideFillUi() {
+ mHandler.post(this::hideFillUiUiThread);
+ }
+
+ /**
+ * Filters the options in the fill UI.
+ *
+ * @param filterText The filter prefix.
+ */
+ public void filterFillUi(@Nullable String filterText) {
+ mHandler.post(() -> {
+ if (!hasCallback()) {
+ return;
+ }
+ hideSaveUiUiThread();
+ if (mFillUi != null) {
+ mFillUi.filter(filterText);
+ }
+ });
+ }
+
+ /**
+ * Updates the position of the fill UI.
+ *
+ * @param anchoredBounds The bounds of the anchor view.
+ */
+ public void updateFillUi(@NonNull Rect anchoredBounds) {
+ mHandler.post(() -> {
+ if (!hasCallback()) {
+ return;
+ }
+ hideSaveUiUiThread();
+ if (mFillUi != null) {
+ mFillUi.update(anchoredBounds);
+ }
+ });
+ }
+
+ /**
+ * Shows the fill UI, removing the previous fill UI if the has changed.
+ *
+ * @param focusedId the currently focused field
+ * @param response the current fill response
+ * @param anchorBounds bounds of the focused view
+ * @param filterText text of the view to be filled
+ */
+ public void showFillUi(@NonNull AutoFillId focusedId, @NonNull FillResponse response,
+ @NonNull Rect anchorBounds, @Nullable String filterText) {
+ mHandler.post(() -> {
+ if (!hasCallback()) {
+ return;
+ }
+ hideAllUiThread();
+ mFillUi = new FillUi(mContext, response, focusedId,
+ mWindowToken, anchorBounds, filterText, new FillUi.Callback() {
+ @Override
+ public void onResponsePicked(FillResponse response) {
+ hideFillUiUiThread();
+ if (mCallback != null) {
+ mCallback.authenticate(response.getAuthentication());
+ }
+ }
+
+ @Override
+ public void onDatasetPicked(Dataset dataset) {
+ hideFillUiUiThread();
+ if (mCallback != null) {
+ mCallback.fill(dataset);
+ }
+ // TODO(b/33197203): add MetricsLogger call
+ }
+
+ @Override
+ public void onCanceled() {
+ hideFillUiUiThread();
+ // TODO(b/33197203): add MetricsLogger call
+ }
+ });
+ });
+ }
+
+ /**
+ * Shows the UI asking the user to save for auto-fill.
+ */
+ public void showSaveUi(@NonNull CharSequence providerLabel, @NonNull SaveInfo info) {
+ mHandler.post(() -> {
+ if (!hasCallback()) {
+ return;
+ }
+ hideAllUiThread();
+ mSaveUi = new SaveUi(mContext, providerLabel, info,
+ new SaveUi.OnSaveListener() {
+ @Override
+ public void onSave() {
+ hideSaveUiUiThread();
+ if (mCallback != null) {
+ mCallback.save();
+ }
+ // TODO(b/33197203): add MetricsLogger call
+ }
+
+ @Override
+ public void onCancel() {
+ // TODO(b/33197203): add MetricsLogger call
+ hideSaveUiUiThread();
+ }
+ });
+ });
+ }
+
+ /**
+ * Hides all UI affordances.
+ */
+ public void hideAll() {
+ mHandler.post(this::hideAllUiThread);
+ }
+
+ public void dump(PrintWriter pw) {
+ pw.println("AufoFill UI");
+ final String prefix = " ";
+ pw.print(prefix); pw.print("showsFillUi: "); pw.println(mFillUi != null);
+ pw.print(prefix); pw.print("showsSaveUi: "); pw.println(mSaveUi != null);
+ }
+
+ @android.annotation.UiThread
+ private void hideFillUiUiThread() {
+ if (mFillUi != null) {
+ mFillUi.destroy();
+ mFillUi = null;
+ }
+ }
+
+ @android.annotation.UiThread
+ private void hideSaveUiUiThread() {
+ if (mSaveUi != null) {
+ mSaveUi.destroy();
+ mSaveUi = null;
+ }
+ }
+
+ @android.annotation.UiThread
+ private void hideAllUiThread() {
+ hideFillUiUiThread();
+ hideSaveUiUiThread();
+ }
+
+ private boolean hasCallback() {
+ return mCallback != null;
+ }
+}
diff --git a/services/autofill/java/com/android/server/autofill/ui/FillUi.java b/services/autofill/java/com/android/server/autofill/ui/FillUi.java
new file mode 100644
index 0000000..0d5fbbe
--- /dev/null
+++ b/services/autofill/java/com/android/server/autofill/ui/FillUi.java
@@ -0,0 +1,348 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.server.autofill.ui;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.Context;
+import android.graphics.PixelFormat;
+import android.graphics.Point;
+import android.graphics.Rect;
+import android.os.IBinder;
+import android.service.autofill.Dataset;
+import android.service.autofill.FillResponse;
+import android.util.Slog;
+import android.view.Gravity;
+import android.view.LayoutInflater;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.View.MeasureSpec;
+import android.view.ViewGroup;
+import android.view.WindowManager;
+import android.view.autofill.AutoFillId;
+import android.view.autofill.AutoFillValue;
+import android.widget.ArrayAdapter;
+import android.widget.ListView;
+import com.android.internal.R;
+import com.android.internal.R;
+import libcore.util.Objects;
+
+import java.util.ArrayList;
+
+final class FillUi {
+ private static final String TAG = "FillUi";
+
+ interface Callback {
+ void onResponsePicked(@NonNull FillResponse response);
+ void onDatasetPicked(@NonNull Dataset dataset);
+ void onCanceled();
+ }
+
+ private final Rect mAnchorBounds = new Rect();
+
+ private final @NonNull AnchoredWindow mWindow;
+
+ private final @NonNull Callback mCallback;
+
+ private final @Nullable ArrayAdapter<ViewItem> mAdapter;
+
+ private @Nullable String mFilterText;
+
+ private int mContentWidth;
+ private int mContentHeight;
+
+ private boolean mDestroyed;
+
+ FillUi(@NonNull Context context, @NonNull FillResponse response,
+ @NonNull AutoFillId focusedViewId, @NonNull IBinder windowToken,
+ @NonNull Rect anchorBounds, @Nullable String filterText,
+ @NonNull Callback callback) {
+ mAnchorBounds.set(anchorBounds);
+ mCallback = callback;
+
+ if (response.getAuthentication() != null) {
+ final View content;
+ try {
+ content = response.getPresentation().apply(context, null);
+ } catch (RuntimeException e) {
+ callback.onCanceled();
+ Slog.e(TAG, "Error inflating remote views", e);
+ mWindow = null;
+ mAdapter = null;
+ return;
+ }
+ final int widthMeasureSpec = MeasureSpec.makeMeasureSpec(MeasureSpec.UNSPECIFIED, 0);
+ final int heightMeasureSpec = MeasureSpec.makeMeasureSpec(MeasureSpec.UNSPECIFIED, 0);
+ content.measure(widthMeasureSpec, heightMeasureSpec);
+ content.setOnClickListener(v -> mCallback.onResponsePicked(response));
+ mContentWidth = content.getMeasuredWidth();
+ mContentHeight = content.getMeasuredHeight();
+ mAdapter = null;
+
+ mWindow = new AnchoredWindow(windowToken, content);
+ mWindow.update(mContentWidth, mContentHeight, mAnchorBounds);
+ } else {
+ final int datasetCount = response.getDatasets().size();
+ final ArrayList<ViewItem> items = new ArrayList<>(datasetCount);
+ for (int i = 0; i < datasetCount; i++) {
+ final Dataset dataset = response.getDatasets().get(i);
+ final int index = dataset.getFieldIds().indexOf(focusedViewId);
+ if (index >= 0) {
+ AutoFillValue value = dataset.getFieldValues().get(index);
+ final View view;
+ try {
+ view = dataset.getPresentation().apply(context, null);
+ } catch (RuntimeException e) {
+ Slog.e(TAG, "Error inflating remote views", e);
+ continue;
+ }
+ items.add(new ViewItem(dataset, value.coerceToString()
+ .toLowerCase(), view));
+ }
+ }
+
+ mAdapter = new ArrayAdapter<ViewItem>(context, 0, items) {
+ @Override
+ public View getView(int position, View convertView, ViewGroup parent) {
+ return getItem(position).getView();
+ }
+ };
+
+ final LayoutInflater inflater = LayoutInflater.from(context);
+ final ListView listView = (ListView) inflater.inflate(
+ com.android.internal.R.layout.autofill_dataset_picker, null);
+ listView.setAdapter(mAdapter);
+ listView.setOnItemClickListener((adapter, view, position, id) -> {
+ final ViewItem vi = mAdapter.getItem(position);
+ mCallback.onDatasetPicked(vi.getDataset());
+ });
+
+ filter(filterText);
+ mWindow = new AnchoredWindow(windowToken, listView);
+ }
+ }
+
+ public void update(@NonNull Rect anchorBounds) {
+ throwIfDestroyed();
+ if (!mAnchorBounds.equals(anchorBounds)) {
+ mAnchorBounds.set(anchorBounds);
+ mWindow.update(mContentWidth, mContentHeight, anchorBounds);
+ }
+ }
+
+ public void filter(@Nullable String filterText) {
+ throwIfDestroyed();
+ if (mAdapter == null) {
+ return;
+ }
+ if (Objects.equal(mFilterText, filterText)) {
+ return;
+ }
+ mFilterText = filterText;
+ mAdapter.getFilter().filter(filterText, (count) -> {
+ if (mDestroyed) {
+ return;
+ }
+ if (count <= 0) {
+ mCallback.onCanceled();
+ } else {
+ if (updateContentSize()) {
+ mWindow.update(mContentWidth, mContentHeight, mAnchorBounds);
+ }
+ }
+ });
+ }
+
+ public void destroy() {
+ throwIfDestroyed();
+ mWindow.destroy();
+ mDestroyed = true;
+ }
+
+ private boolean updateContentSize() {
+ if (mAdapter == null) {
+ return false;
+ }
+ boolean changed = false;
+ if (mAdapter.getCount() <= 0) {
+ if (mContentWidth != 0) {
+ mContentWidth = 0;
+ changed = true;
+ }
+ if (mContentHeight != 0) {
+ mContentHeight = 0;
+ changed = true;
+ }
+ return changed;
+ }
+
+ mContentWidth = 0;
+ mContentHeight = 0;
+
+ final int widthMeasureSpec = MeasureSpec.makeMeasureSpec(MeasureSpec.UNSPECIFIED, 0);
+ final int heightMeasureSpec = MeasureSpec.makeMeasureSpec(MeasureSpec.UNSPECIFIED, 0);
+ final int itemCount = mAdapter.getCount();
+ for (int i = 0; i < itemCount; i++) {
+ View view = mAdapter.getItem(i).getView();
+ view.measure(widthMeasureSpec, heightMeasureSpec);
+ final int newContentWidth = Math.max(mContentWidth, view.getMeasuredWidth());
+ if (newContentWidth != mContentWidth) {
+ mContentWidth = newContentWidth;
+ changed = true;
+ }
+ final int newContentHeight = mContentHeight + view.getMeasuredHeight();
+ if (newContentHeight != mContentHeight) {
+ mContentHeight = newContentHeight;
+ changed = true;
+ }
+ }
+ return changed;
+ }
+
+ private void throwIfDestroyed() {
+ if (mDestroyed) {
+ throw new IllegalStateException("cannot interact with a destroyed instance");
+ }
+ }
+
+ private static class ViewItem {
+ private final String mValue;
+ private final Dataset mDataset;
+ private final View mView;
+
+ ViewItem(Dataset dataset, String value, View view) {
+ mDataset = dataset;
+ mValue = value.toLowerCase();
+ mView = view;
+ }
+
+ public View getView() {
+ return mView;
+ }
+
+ public Dataset getDataset() {
+ return mDataset;
+ }
+
+ @Override
+ public String toString() {
+ // Used for filtering in the adapter
+ return mValue;
+ }
+ }
+
+ final class AnchoredWindow implements View.OnTouchListener {
+ private final Point mTempPoint = new Point();
+
+ private final WindowManager mWm;
+
+ private final IBinder mActivityToken;
+ private final View mContentView;
+
+ /**
+ * Constructor.
+ *
+ * @param activityToken token to pass to window manager
+ * @param contentView content of the window
+ */
+ AnchoredWindow(IBinder activityToken, View contentView) {
+ mWm = contentView.getContext().getSystemService(WindowManager.class);
+ mActivityToken = activityToken;
+ mContentView = contentView;
+ }
+
+ /**
+ * Hides the window.
+ */
+ void destroy() {
+ if (mContentView.isAttachedToWindow()) {
+ mContentView.setOnTouchListener(null);
+ mWm.removeView(mContentView);
+ }
+ }
+
+ @Override
+ public boolean onTouch(View view, MotionEvent event) {
+ // When the window is touched outside, hide the window.
+ if (view == mContentView && event.getAction() == MotionEvent.ACTION_OUTSIDE) {
+ mCallback.onCanceled();
+ return true;
+ }
+ return false;
+ }
+
+ public void update(int desiredWidth, int desiredHeight, Rect anchorBounds) {
+ final WindowManager.LayoutParams params = new WindowManager.LayoutParams();
+ params.setTitle("FillUi");
+ params.token = mActivityToken;
+ params.type = WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG;
+ params.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
+ | WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM
+ | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
+ | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
+ | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
+ params.format = PixelFormat.TRANSLUCENT;
+
+ mWm.getDefaultDisplay().getRealSize(mTempPoint);
+ final int screenWidth = mTempPoint.x;
+ final int screenHeight = mTempPoint.y;
+
+ // Try to place the window at the start of the anchor view if
+ // there is space to fit the content, otherwise fit as much of
+ // the window as possible moving it to the left using all available
+ // screen width.
+ params.x = Math.min(anchorBounds.left, Math.max(screenWidth - desiredWidth, 0));
+ params.width = Math.min(screenWidth, desiredWidth);
+
+ // Try to fit below using all available space with top-start gravity
+ // and if that fails try to fit above using all available space with
+ // bottom-start gravity.
+ final int verticalSpaceBelow = screenHeight - anchorBounds.bottom;
+ if (desiredHeight <= verticalSpaceBelow) {
+ // Fits below bounds.
+ params.height = desiredHeight;
+ params.gravity = Gravity.TOP | Gravity.START;
+ params.y = anchorBounds.bottom;
+ } else {
+ final int verticalSpaceAbove = anchorBounds.top;
+ if (desiredHeight <= verticalSpaceAbove) {
+ // Fits above bounds.
+ params.height = desiredHeight;
+ params.gravity = Gravity.BOTTOM | Gravity.START;
+ params.y = anchorBounds.top + desiredHeight;
+ } else {
+ // Pick above/below based on which has the most space.
+ if (verticalSpaceBelow >= verticalSpaceAbove) {
+ params.height = verticalSpaceBelow;
+ params.gravity = Gravity.TOP | Gravity.START;
+ params.y = anchorBounds.bottom;
+ } else {
+ params.height = verticalSpaceAbove;
+ params.gravity = Gravity.BOTTOM | Gravity.START;
+ params.y = anchorBounds.top + desiredHeight;
+ }
+ }
+ }
+
+ if (!mContentView.isAttachedToWindow()) {
+ mWm.addView(mContentView, params);
+ mContentView.setOnTouchListener(this);
+ } else {
+ mWm.updateViewLayout(mContentView, params);
+ }
+ }
+ }
+}
diff --git a/services/autofill/java/com/android/server/autofill/ui/SaveUi.java b/services/autofill/java/com/android/server/autofill/ui/SaveUi.java
new file mode 100644
index 0000000..afe93c7
--- /dev/null
+++ b/services/autofill/java/com/android/server/autofill/ui/SaveUi.java
@@ -0,0 +1,130 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.autofill.ui;
+
+import android.annotation.NonNull;
+import android.app.Dialog;
+import android.content.Context;
+import android.os.Handler;
+import android.service.autofill.SaveInfo;
+import android.text.format.DateUtils;
+import android.view.Gravity;
+import android.view.Window;
+import android.view.WindowManager;
+import android.widget.TextView;
+import android.view.LayoutInflater;
+import android.view.View;
+
+import com.android.internal.R;
+import com.android.server.UiThread;
+
+/**
+ * Autofill Save Prompt
+ */
+final class SaveUi {
+ public interface OnSaveListener {
+ void onSave();
+ void onCancel();
+ }
+
+ private static final long LIFETIME_MILLIS = 5 * DateUtils.SECOND_IN_MILLIS;
+
+ private final Handler mHandler = UiThread.getHandler();
+
+ private final @NonNull Dialog mDialog;
+
+ private final @NonNull OnSaveListener mListener;
+
+ private boolean mDestroyed;
+
+ SaveUi(@NonNull Context context, @NonNull CharSequence providerLabel, @NonNull SaveInfo info,
+ @NonNull OnSaveListener listener) {
+ mListener = listener;
+
+ final LayoutInflater inflater = LayoutInflater.from(context);
+ final View view = inflater.inflate(R.layout.autofill_save, null);
+
+ final TextView titleView = (TextView) view.findViewById(R.id.autofill_save_title);
+ final String type;
+
+ switch(info.getType()) {
+ case SaveInfo.SAVE_DATA_TYPE_PASSWORD:
+ type = context.getString(R.string.autofill_save_type_password);
+ break;
+ case SaveInfo.SAVE_DATA_TYPE_ADDRESS:
+ type = context.getString(R.string.autofill_save_type_address);
+ break;
+ case SaveInfo.SAVE_DATA_TYPE_CREDIT_CARD:
+ type = context.getString(R.string.autofill_save_type_credit_card);
+ break;
+ default:
+ type = null;
+ }
+
+ final String title = (type == null)
+ ? context.getString(R.string.autofill_save_title, providerLabel)
+ : context.getString(R.string.autofill_save_title_with_type, type, providerLabel);
+
+ titleView.setText(title);
+ final CharSequence subTitle = info.getDescription();
+ if (subTitle != null) {
+ final TextView subTitleView = (TextView) view.findViewById(R.id.autofill_save_subtitle);
+ subTitleView.setText(subTitle);
+ subTitleView.setVisibility(View.VISIBLE);
+ }
+
+ final View noButton = view.findViewById(R.id.autofill_save_no);
+ noButton.setOnClickListener((v) -> mListener.onCancel());
+
+ final View yesButton = view.findViewById(R.id.autofill_save_yes);
+ yesButton.setOnClickListener((v) -> mListener.onSave());
+
+ final View closeButton = view.findViewById(R.id.autofill_save_close);
+ closeButton.setOnClickListener((v) -> mListener.onCancel());
+
+ mDialog = new Dialog(context, R.style.Theme_Material_Panel);
+ mDialog.setContentView(view);
+
+ final Window window = mDialog.getWindow();
+ window.setType(WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY);
+ window.addFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
+ | WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM
+ | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
+ | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH);
+ window.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN);
+ window.setGravity(Gravity.BOTTOM | Gravity.CENTER);
+ window.setCloseOnTouchOutside(true);
+ window.getAttributes().width = WindowManager.LayoutParams.MATCH_PARENT;
+
+ mDialog.show();
+
+ mHandler.postDelayed(() -> mListener.onCancel(), LIFETIME_MILLIS);
+ }
+
+ void destroy() {
+ throwIfDestroyed();
+ mHandler.removeCallbacksAndMessages(mListener);
+ mDialog.dismiss();
+ mDestroyed = true;
+ }
+
+ private void throwIfDestroyed() {
+ if (mDestroyed) {
+ throw new IllegalStateException("cannot interact with a destroyed instance");
+ }
+ }
+}
diff --git a/services/backup/java/com/android/server/backup/BackupManagerService.java b/services/backup/java/com/android/server/backup/BackupManagerService.java
index b459f74..4f8b8af 100644
--- a/services/backup/java/com/android/server/backup/BackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/BackupManagerService.java
@@ -38,15 +38,15 @@
import android.app.backup.BackupTransport;
import android.app.backup.FullBackup;
import android.app.backup.FullBackupDataOutput;
-import android.app.backup.IBackupObserver;
-import android.app.backup.IBackupManagerMonitor;
-import android.app.backup.RestoreDescription;
-import android.app.backup.RestoreSet;
import android.app.backup.IBackupManager;
+import android.app.backup.IBackupManagerMonitor;
+import android.app.backup.IBackupObserver;
import android.app.backup.IFullBackupRestoreObserver;
import android.app.backup.IRestoreObserver;
import android.app.backup.IRestoreSession;
import android.app.backup.ISelectBackupTransportCallback;
+import android.app.backup.RestoreDescription;
+import android.app.backup.RestoreSet;
import android.app.backup.SelectBackupTransportCallback;
import android.content.ActivityNotFoundException;
import android.content.BroadcastReceiver;
@@ -136,6 +136,7 @@
import java.security.spec.InvalidKeySpecException;
import java.security.spec.KeySpec;
import java.text.SimpleDateFormat;
+import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
@@ -146,6 +147,7 @@
import java.util.List;
import java.util.Map.Entry;
import java.util.Objects;
+import java.util.Queue;
import java.util.Random;
import java.util.Set;
import java.util.TreeMap;
@@ -327,6 +329,11 @@
final Object mClearDataLock = new Object();
volatile boolean mClearingData;
+ @GuardedBy("mPendingRestores")
+ private boolean mIsRestoreInProgress;
+ @GuardedBy("mPendingRestores")
+ private final Queue<PerformUnifiedRestoreTask> mPendingRestores = new ArrayDeque<>();
+
ActiveRestoreSession mActiveRestoreSession;
// Watch the device provisioning operation during setup
@@ -909,11 +916,28 @@
{
RestoreParams params = (RestoreParams)msg.obj;
Slog.d(TAG, "MSG_RUN_RESTORE observer=" + params.observer);
- BackupRestoreTask task = new PerformUnifiedRestoreTask(params.transport,
+
+ PerformUnifiedRestoreTask task = new PerformUnifiedRestoreTask(params.transport,
params.observer, params.monitor, params.token, params.pkgInfo,
params.pmToken, params.isSystemRestore, params.filterSet);
- Message restoreMsg = obtainMessage(MSG_BACKUP_RESTORE_STEP, task);
- sendMessage(restoreMsg);
+
+ synchronized (mPendingRestores) {
+ if (mIsRestoreInProgress) {
+ if (DEBUG) {
+ Slog.d(TAG, "Restore in progress, queueing.");
+ }
+ mPendingRestores.add(task);
+ // This task will be picked up and executed when the the currently running
+ // restore task finishes.
+ } else {
+ if (DEBUG) {
+ Slog.d(TAG, "Starting restore.");
+ }
+ mIsRestoreInProgress = true;
+ Message restoreMsg = obtainMessage(MSG_BACKUP_RESTORE_STEP, task);
+ sendMessage(restoreMsg);
+ }
+ }
break;
}
@@ -2658,19 +2682,32 @@
mStateDir = new File(mBaseStateDir, dirName);
mCurrentOpToken = generateToken();
- mCurrentState = BackupState.INITIAL;
mFinished = false;
- CountDownLatch latch = new CountDownLatch(1);
- String[] fullBackups =
- mPendingFullBackups.toArray(new String[mPendingFullBackups.size()]);
- mFullBackupTask =
- new PerformFullTransportBackupTask(/*fullBackupRestoreObserver*/ null,
- fullBackups, /*updateSchedule*/ false, /*runningJob*/ null, latch,
- mObserver, mMonitor,mUserInitiated);
+ synchronized (mCurrentOpLock) {
+ if (isBackupOperationInProgress()) {
+ if (DEBUG) {
+ Slog.d(TAG, "Skipping backup since one is already in progress.");
+ }
+ mCancelAll = true;
+ mFullBackupTask = null;
+ mCurrentState = BackupState.FINAL;
+ addBackupTrace("Skipped. Backup already in progress.");
+ } else {
+ mCurrentState = BackupState.INITIAL;
+ CountDownLatch latch = new CountDownLatch(1);
+ String[] fullBackups =
+ mPendingFullBackups.toArray(new String[mPendingFullBackups.size()]);
+ mFullBackupTask =
+ new PerformFullTransportBackupTask(/*fullBackupRestoreObserver*/ null,
+ fullBackups, /*updateSchedule*/ false, /*runningJob*/ null,
+ latch,
+ mObserver, mMonitor, mUserInitiated);
- registerTask();
- addBackupTrace("STATE => INITIAL");
+ registerTask();
+ addBackupTrace("STATE => INITIAL");
+ }
+ }
}
/**
@@ -3053,7 +3090,9 @@
mWakelock.acquire();
(new Thread(mFullBackupTask, "full-transport-requested")).start();
} else if (mCancelAll) {
- mFullBackupTask.unregisterTask();
+ if (mFullBackupTask != null) {
+ mFullBackupTask.unregisterTask();
+ }
sendBackupFinished(mObserver, BackupManager.ERROR_BACKUP_CANCELLED);
} else {
mFullBackupTask.unregisterTask();
@@ -3537,6 +3576,18 @@
}
}
+ private boolean isBackupOperationInProgress() {
+ synchronized (mCurrentOpLock) {
+ for (int i = 0; i < mCurrentOperations.size(); i++) {
+ Operation op = mCurrentOperations.valueAt(i);
+ if (op.type == OP_TYPE_BACKUP && op.state == OP_PENDING) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
// ----- Full backup/restore to a file/socket -----
@@ -4519,6 +4570,14 @@
mCurrentOpToken = generateToken();
mBackupRunnerOpToken = generateToken();
+ if (isBackupOperationInProgress()) {
+ if (DEBUG) {
+ Slog.d(TAG, "Skipping full backup. A backup is already in progress.");
+ }
+ mCancelAll = true;
+ return;
+ }
+
registerTask();
for (String pkg : whichPackages) {
@@ -9148,6 +9207,24 @@
// done; we can finally release the wakelock and be legitimately done.
Slog.i(TAG, "Restore complete.");
+
+ synchronized (mPendingRestores) {
+ if (mPendingRestores.size() > 0) {
+ if (DEBUG) {
+ Slog.d(TAG, "Starting next pending restore.");
+ }
+ PerformUnifiedRestoreTask task = mPendingRestores.remove();
+ mBackupHandler.sendMessage(
+ mBackupHandler.obtainMessage(MSG_BACKUP_RESTORE_STEP, task));
+
+ } else {
+ mIsRestoreInProgress = false;
+ if (MORE_DEBUG) {
+ Slog.d(TAG, "No pending restores.");
+ }
+ }
+ }
+
mWakelock.release();
}
diff --git a/services/core/java/com/android/server/AppOpsService.java b/services/core/java/com/android/server/AppOpsService.java
index dc0e3e1..de11f36 100644
--- a/services/core/java/com/android/server/AppOpsService.java
+++ b/services/core/java/com/android/server/AppOpsService.java
@@ -167,14 +167,10 @@
}
}
- final SparseArray<ArrayList<Callback>> mOpModeWatchers
- = new SparseArray<ArrayList<Callback>>();
- final ArrayMap<String, ArrayList<Callback>> mPackageModeWatchers
- = new ArrayMap<String, ArrayList<Callback>>();
- final ArrayMap<IBinder, Callback> mModeWatchers
- = new ArrayMap<IBinder, Callback>();
- final SparseArray<SparseArray<Restriction>> mAudioRestrictions
- = new SparseArray<SparseArray<Restriction>>();
+ final SparseArray<ArraySet<Callback>> mOpModeWatchers = new SparseArray<>();
+ final ArrayMap<String, ArraySet<Callback>> mPackageModeWatchers = new ArrayMap<>();
+ final ArrayMap<IBinder, Callback> mModeWatchers = new ArrayMap<>();
+ final SparseArray<SparseArray<Restriction>> mAudioRestrictions = new SparseArray<>();
public final class Callback implements DeathRecipient {
final IAppOpsCallback mCallback;
@@ -545,11 +541,11 @@
ArrayMap<Callback, ArraySet<String>> callbackSpecs = null;
synchronized (this) {
- ArrayList<Callback> callbacks = mOpModeWatchers.get(code);
+ ArraySet<Callback> callbacks = mOpModeWatchers.get(code);
if (callbacks != null) {
final int callbackCount = callbacks.size();
for (int i = 0; i < callbackCount; i++) {
- Callback callback = callbacks.get(i);
+ Callback callback = callbacks.valueAt(i);
ArraySet<String> changedPackages = new ArraySet<>();
Collections.addAll(changedPackages, uidPackageNames);
callbackSpecs = new ArrayMap<>();
@@ -565,7 +561,7 @@
}
final int callbackCount = callbacks.size();
for (int i = 0; i < callbackCount; i++) {
- Callback callback = callbacks.get(i);
+ Callback callback = callbacks.valueAt(i);
ArraySet<String> changedPackages = callbackSpecs.get(callback);
if (changedPackages == null) {
changedPackages = new ArraySet<>();
@@ -623,17 +619,17 @@
if (op != null) {
if (op.mode != mode) {
op.mode = mode;
- ArrayList<Callback> cbs = mOpModeWatchers.get(code);
+ ArraySet<Callback> cbs = mOpModeWatchers.get(code);
if (cbs != null) {
if (repCbs == null) {
- repCbs = new ArrayList<Callback>();
+ repCbs = new ArrayList<>();
}
repCbs.addAll(cbs);
}
cbs = mPackageModeWatchers.get(packageName);
if (cbs != null) {
if (repCbs == null) {
- repCbs = new ArrayList<Callback>();
+ repCbs = new ArrayList<>();
}
repCbs.addAll(cbs);
}
@@ -666,7 +662,7 @@
private static HashMap<Callback, ArrayList<ChangeRec>> addCallbacks(
HashMap<Callback, ArrayList<ChangeRec>> callbacks,
- int op, int uid, String packageName, ArrayList<Callback> cbs) {
+ int op, int uid, String packageName, ArraySet<Callback> cbs) {
if (cbs == null) {
return callbacks;
}
@@ -674,8 +670,9 @@
callbacks = new HashMap<>();
}
boolean duplicate = false;
- for (int i=0; i<cbs.size(); i++) {
- Callback cb = cbs.get(i);
+ final int N = cbs.size();
+ for (int i=0; i<N; i++) {
+ Callback cb = cbs.valueAt(i);
ArrayList<ChangeRec> reports = callbacks.get(cb);
if (reports == null) {
reports = new ArrayList<>();
@@ -830,17 +827,17 @@
mModeWatchers.put(callback.asBinder(), cb);
}
if (op != AppOpsManager.OP_NONE) {
- ArrayList<Callback> cbs = mOpModeWatchers.get(op);
+ ArraySet<Callback> cbs = mOpModeWatchers.get(op);
if (cbs == null) {
- cbs = new ArrayList<Callback>();
+ cbs = new ArraySet<>();
mOpModeWatchers.put(op, cbs);
}
cbs.add(cb);
}
if (packageName != null) {
- ArrayList<Callback> cbs = mPackageModeWatchers.get(packageName);
+ ArraySet<Callback> cbs = mPackageModeWatchers.get(packageName);
if (cbs == null) {
- cbs = new ArrayList<Callback>();
+ cbs = new ArraySet<>();
mPackageModeWatchers.put(packageName, cbs);
}
cbs.add(cb);
@@ -858,14 +855,14 @@
if (cb != null) {
cb.unlinkToDeath();
for (int i=mOpModeWatchers.size()-1; i>=0; i--) {
- ArrayList<Callback> cbs = mOpModeWatchers.valueAt(i);
+ ArraySet<Callback> cbs = mOpModeWatchers.valueAt(i);
cbs.remove(cb);
if (cbs.size() <= 0) {
mOpModeWatchers.removeAt(i);
}
}
for (int i=mPackageModeWatchers.size()-1; i>=0; i--) {
- ArrayList<Callback> cbs = mPackageModeWatchers.valueAt(i);
+ ArraySet<Callback> cbs = mPackageModeWatchers.valueAt(i);
cbs.remove(cb);
if (cbs.size() <= 0) {
mPackageModeWatchers.removeAt(i);
@@ -2066,10 +2063,10 @@
for (int i=0; i<mOpModeWatchers.size(); i++) {
pw.print(" Op "); pw.print(AppOpsManager.opToName(mOpModeWatchers.keyAt(i)));
pw.println(":");
- ArrayList<Callback> callbacks = mOpModeWatchers.valueAt(i);
+ ArraySet<Callback> callbacks = mOpModeWatchers.valueAt(i);
for (int j=0; j<callbacks.size(); j++) {
pw.print(" #"); pw.print(j); pw.print(": ");
- pw.println(callbacks.get(j));
+ pw.println(callbacks.valueAt(j));
}
}
}
@@ -2079,10 +2076,10 @@
for (int i=0; i<mPackageModeWatchers.size(); i++) {
pw.print(" Pkg "); pw.print(mPackageModeWatchers.keyAt(i));
pw.println(":");
- ArrayList<Callback> callbacks = mPackageModeWatchers.valueAt(i);
+ ArraySet<Callback> callbacks = mPackageModeWatchers.valueAt(i);
for (int j=0; j<callbacks.size(); j++) {
pw.print(" #"); pw.print(j); pw.print(": ");
- pw.println(callbacks.get(j));
+ pw.println(callbacks.valueAt(j));
}
}
}
@@ -2310,23 +2307,23 @@
}
private void notifyWatchersOfChange(int code) {
- final ArrayList<Callback> clonedCallbacks;
+ final ArraySet<Callback> clonedCallbacks;
synchronized (this) {
- ArrayList<Callback> callbacks = mOpModeWatchers.get(code);
+ ArraySet<Callback> callbacks = mOpModeWatchers.get(code);
if (callbacks == null) {
return;
}
- clonedCallbacks = new ArrayList<>(callbacks);
+ clonedCallbacks = new ArraySet<>(callbacks);
}
// There are components watching for mode changes such as window manager
// and location manager which are in our process. The callbacks in these
- // components may require permissions our remote caller does not have.s
+ // components may require permissions our remote caller does not have.
final long identity = Binder.clearCallingIdentity();
try {
final int callbackCount = clonedCallbacks.size();
for (int i = 0; i < callbackCount; i++) {
- Callback callback = clonedCallbacks.get(i);
+ Callback callback = clonedCallbacks.valueAt(i);
try {
callback.mCallback.opChanged(code, -1, null);
} catch (RemoteException e) {
diff --git a/services/core/java/com/android/server/BatteryService.java b/services/core/java/com/android/server/BatteryService.java
index 6248cab..81f137e 100644
--- a/services/core/java/com/android/server/BatteryService.java
+++ b/services/core/java/com/android/server/BatteryService.java
@@ -130,6 +130,8 @@
private int mLastMaxChargingVoltage;
private int mLastChargeCounter;
+ private int mSequence = 1;
+
private int mInvalidCharger;
private int mLastInvalidCharger;
@@ -448,27 +450,29 @@
}
}
- sendIntentLocked();
+ mSequence++;
// Separate broadcast is sent for power connected / not connected
// since the standard intent will not wake any applications and some
// applications may want to have smart behavior based on this.
if (mPlugType != 0 && mLastPlugType == 0) {
+ final Intent statusIntent = new Intent(Intent.ACTION_POWER_CONNECTED);
+ statusIntent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
+ statusIntent.putExtra(BatteryManager.EXTRA_SEQUENCE, mSequence);
mHandler.post(new Runnable() {
@Override
public void run() {
- Intent statusIntent = new Intent(Intent.ACTION_POWER_CONNECTED);
- statusIntent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
mContext.sendBroadcastAsUser(statusIntent, UserHandle.ALL);
}
});
}
else if (mPlugType == 0 && mLastPlugType != 0) {
+ final Intent statusIntent = new Intent(Intent.ACTION_POWER_DISCONNECTED);
+ statusIntent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
+ statusIntent.putExtra(BatteryManager.EXTRA_SEQUENCE, mSequence);
mHandler.post(new Runnable() {
@Override
public void run() {
- Intent statusIntent = new Intent(Intent.ACTION_POWER_DISCONNECTED);
- statusIntent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
mContext.sendBroadcastAsUser(statusIntent, UserHandle.ALL);
}
});
@@ -476,26 +480,33 @@
if (shouldSendBatteryLowLocked()) {
mSentLowBatteryBroadcast = true;
+ final Intent statusIntent = new Intent(Intent.ACTION_BATTERY_LOW);
+ statusIntent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
+ statusIntent.putExtra(BatteryManager.EXTRA_SEQUENCE, mSequence);
mHandler.post(new Runnable() {
@Override
public void run() {
- Intent statusIntent = new Intent(Intent.ACTION_BATTERY_LOW);
- statusIntent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
mContext.sendBroadcastAsUser(statusIntent, UserHandle.ALL);
}
});
} else if (mSentLowBatteryBroadcast && mLastBatteryLevel >= mLowBatteryCloseWarningLevel) {
mSentLowBatteryBroadcast = false;
+ final Intent statusIntent = new Intent(Intent.ACTION_BATTERY_OKAY);
+ statusIntent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
+ statusIntent.putExtra(BatteryManager.EXTRA_SEQUENCE, mSequence);
mHandler.post(new Runnable() {
@Override
public void run() {
- Intent statusIntent = new Intent(Intent.ACTION_BATTERY_OKAY);
- statusIntent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
mContext.sendBroadcastAsUser(statusIntent, UserHandle.ALL);
}
});
}
+ // We are doing this after sending the above broadcasts, so anything processing
+ // them will get the new sequence number at that point. (See for example how testing
+ // of JobScheduler's BatteryController works.)
+ sendIntentLocked();
+
// Update the battery LED
mLed.updateLightsLocked();
@@ -527,6 +538,7 @@
int icon = getIconLocked(mBatteryProps.batteryLevel);
+ intent.putExtra(BatteryManager.EXTRA_SEQUENCE, mSequence);
intent.putExtra(BatteryManager.EXTRA_STATUS, mBatteryProps.batteryStatus);
intent.putExtra(BatteryManager.EXTRA_HEALTH, mBatteryProps.batteryHealth);
intent.putExtra(BatteryManager.EXTRA_PRESENT, mBatteryProps.batteryPresent);
@@ -666,12 +678,28 @@
pw.println("Battery service (battery) commands:");
pw.println(" help");
pw.println(" Print this help text.");
- pw.println(" set [ac|usb|wireless|status|level|invalid] <value>");
+ pw.println(" set [-f] [ac|usb|wireless|status|level|invalid] <value>");
pw.println(" Force a battery property value, freezing battery state.");
- pw.println(" unplug");
+ pw.println(" -f: force a battery change broadcast be sent, prints new sequence.");
+ pw.println(" unplug [-f]");
pw.println(" Force battery unplugged, freezing battery state.");
- pw.println(" reset");
+ pw.println(" -f: force a battery change broadcast be sent, prints new sequence.");
+ pw.println(" reset [-f]");
pw.println(" Unfreeze battery state, returning to current hardware values.");
+ pw.println(" -f: force a battery change broadcast be sent, prints new sequence.");
+ }
+
+ static final int OPTION_FORCE_UPDATE = 1<<0;
+
+ int parseOptions(Shell shell) {
+ String opt;
+ int opts = 0;
+ while ((opt = shell.getNextOption()) != null) {
+ if ("-f".equals(opt)) {
+ opts |= OPTION_FORCE_UPDATE;
+ }
+ }
+ return opts;
}
int onShellCommand(Shell shell, String cmd) {
@@ -681,6 +709,7 @@
PrintWriter pw = shell.getOutPrintWriter();
switch (cmd) {
case "unplug": {
+ int opts = parseOptions(shell);
getContext().enforceCallingOrSelfPermission(
android.Manifest.permission.DEVICE_POWER, null);
if (!mUpdatesStopped) {
@@ -692,12 +721,13 @@
long ident = Binder.clearCallingIdentity();
try {
mUpdatesStopped = true;
- processValuesLocked(false);
+ processValuesFromShellLocked(pw, opts);
} finally {
Binder.restoreCallingIdentity(ident);
}
} break;
case "set": {
+ int opts = parseOptions(shell);
getContext().enforceCallingOrSelfPermission(
android.Manifest.permission.DEVICE_POWER, null);
final String key = shell.getNextArg();
@@ -745,7 +775,7 @@
long ident = Binder.clearCallingIdentity();
try {
mUpdatesStopped = true;
- processValuesLocked(false);
+ processValuesFromShellLocked(pw, opts);
} finally {
Binder.restoreCallingIdentity(ident);
}
@@ -756,6 +786,7 @@
}
} break;
case "reset": {
+ int opts = parseOptions(shell);
getContext().enforceCallingOrSelfPermission(
android.Manifest.permission.DEVICE_POWER, null);
long ident = Binder.clearCallingIdentity();
@@ -763,7 +794,7 @@
if (mUpdatesStopped) {
mUpdatesStopped = false;
mBatteryProps.set(mLastBatteryProps);
- processValuesLocked(false);
+ processValuesFromShellLocked(pw, opts);
}
} finally {
Binder.restoreCallingIdentity(ident);
@@ -775,6 +806,13 @@
return 0;
}
+ private void processValuesFromShellLocked(PrintWriter pw, int opts) {
+ processValuesLocked((opts & OPTION_FORCE_UPDATE) != 0);
+ if ((opts & OPTION_FORCE_UPDATE) != 0) {
+ pw.println(mSequence);
+ }
+ }
+
private void dumpInternal(FileDescriptor fd, PrintWriter pw, String[] args) {
synchronized (mLock) {
if (args == null || args.length == 0 || "-a".equals(args[0])) {
diff --git a/services/core/java/com/android/server/BluetoothManagerService.java b/services/core/java/com/android/server/BluetoothManagerService.java
index f315553..e8df38b 100644
--- a/services/core/java/com/android/server/BluetoothManagerService.java
+++ b/services/core/java/com/android/server/BluetoothManagerService.java
@@ -167,7 +167,7 @@
}
public String toString() {
- return android.text.format.DateFormat.format("MM-dd hh:mm:ss ", mTimestamp) +
+ return android.text.format.DateFormat.format("MM-dd HH:mm:ss ", mTimestamp) +
(mEnable ? " Enabled " : " Disabled ") + " by " + mPackageName;
}
diff --git a/services/core/java/com/android/server/GraphicsStatsService.java b/services/core/java/com/android/server/GraphicsStatsService.java
index bdd80e38..14a9a31 100644
--- a/services/core/java/com/android/server/GraphicsStatsService.java
+++ b/services/core/java/com/android/server/GraphicsStatsService.java
@@ -137,16 +137,21 @@
}
private void onAlarm() {
+ // We need to make a copy since some of the callbacks won't be proxy and thus
+ // can result in a re-entrant acquisition of mLock that would result in a modification
+ // of mActive during iteration.
+ ActiveBuffer[] activeCopy;
synchronized (mLock) {
mRotateIsScheduled = false;
scheduleRotateLocked();
- for (ActiveBuffer active : mActive) {
- try {
- active.mCallback.onRotateGraphicsStatsBuffer();
- } catch (RemoteException e) {
- Log.w(TAG, String.format("Failed to notify '%s' (pid=%d) to rotate buffers",
- active.mInfo.packageName, active.mPid), e);
- }
+ activeCopy = mActive.toArray(new ActiveBuffer[0]);
+ }
+ for (ActiveBuffer active : activeCopy) {
+ try {
+ active.mCallback.onRotateGraphicsStatsBuffer();
+ } catch (RemoteException e) {
+ Log.w(TAG, String.format("Failed to notify '%s' (pid=%d) to rotate buffers",
+ active.mInfo.packageName, active.mPid), e);
}
}
// Give a few seconds for everyone to rotate before doing the cleanup
diff --git a/services/core/java/com/android/server/InputMethodManagerService.java b/services/core/java/com/android/server/InputMethodManagerService.java
index fe5b3a2..69e481f 100644
--- a/services/core/java/com/android/server/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/InputMethodManagerService.java
@@ -28,6 +28,7 @@
import com.android.internal.inputmethod.InputMethodSubtypeSwitchingController.ImeSubtypeListItem;
import com.android.internal.inputmethod.InputMethodUtils;
import com.android.internal.inputmethod.InputMethodUtils.InputMethodSettings;
+import com.android.internal.notification.SystemNotificationChannels;
import com.android.internal.os.HandlerCaller;
import com.android.internal.os.SomeArgs;
import com.android.internal.os.TransferPipe;
@@ -881,7 +882,7 @@
final class MyPackageMonitor extends PackageMonitor {
/**
- * Set of packages to be monitored.
+ * Package names that are known to contain {@link InputMethodService}.
*
* <p>No need to include packages because of direct-boot unaware IMEs since we always rescan
* all the packages when the user is unlocked, and direct-boot awareness will not be changed
@@ -889,16 +890,36 @@
* rescanning.</p>
*/
@GuardedBy("mMethodMap")
- private ArraySet<String> mPackagesToMonitorComponentChange = new ArraySet<>();
+ final private ArraySet<String> mKnownImePackageNames = new ArraySet<>();
+
+ /**
+ * Packages that are appeared, disappeared, or modified for whatever reason.
+ *
+ * <p>Note: For now we intentionally use {@link ArrayList} instead of {@link ArraySet}
+ * because 1) the number of elements is almost always 1 or so, and 2) we do not care
+ * duplicate elements for our use case.</p>
+ *
+ * <p>This object must be accessed only from callback methods in {@link PackageMonitor},
+ * which should be bound to {@link #getRegisteredHandler()}.</p>
+ */
+ private final ArrayList<String> mChangedPackages = new ArrayList<>();
+
+ /**
+ * {@code true} if one or more packages that contain {@link InputMethodService} appeared.
+ *
+ * <p>This field must be accessed only from callback methods in {@link PackageMonitor},
+ * which should be bound to {@link #getRegisteredHandler()}.</p>
+ */
+ private boolean mImePackageAppeared = false;
@GuardedBy("mMethodMap")
- void clearPackagesToMonitorComponentChangeLocked() {
- mPackagesToMonitorComponentChange.clear();
+ void clearKnownImePackageNamesLocked() {
+ mKnownImePackageNames.clear();
}
@GuardedBy("mMethodMap")
- final void addPackageToMonitorComponentChangeLocked(@NonNull String packageName) {
- mPackagesToMonitorComponentChange.add(packageName);
+ final void addKnownImePackageNameLocked(@NonNull String packageName) {
+ mKnownImePackageNames.add(packageName);
}
@GuardedBy("mMethodMap")
@@ -943,19 +964,97 @@
}
@Override
- public boolean onPackageChanged(String packageName, int uid, String[] components) {
- // If this package is in the watch list, we want to check it.
- synchronized (mMethodMap) {
- return mPackagesToMonitorComponentChange.contains(packageName);
+ public void onBeginPackageChanges() {
+ clearPackageChangeState();
+ }
+
+ @Override
+ public void onPackageAppeared(String packageName, int reason) {
+ if (!mImePackageAppeared) {
+ final PackageManager pm = mContext.getPackageManager();
+ final List<ResolveInfo> services = pm.queryIntentServicesAsUser(
+ new Intent(InputMethod.SERVICE_INTERFACE).setPackage(packageName),
+ PackageManager.MATCH_DISABLED_COMPONENTS, getChangingUserId());
+ // No need to lock this because we access it only on getRegisteredHandler().
+ if (!services.isEmpty()) {
+ mImePackageAppeared = true;
+ }
+ }
+ // No need to lock this because we access it only on getRegisteredHandler().
+ mChangedPackages.add(packageName);
+ }
+
+ @Override
+ public void onPackageDisappeared(String packageName, int reason) {
+ // No need to lock this because we access it only on getRegisteredHandler().
+ mChangedPackages.add(packageName);
+ }
+
+ @Override
+ public void onPackageModified(String packageName) {
+ // No need to lock this because we access it only on getRegisteredHandler().
+ mChangedPackages.add(packageName);
+ }
+
+ @Override
+ public void onPackagesSuspended(String[] packages) {
+ // No need to lock this because we access it only on getRegisteredHandler().
+ for (String packageName : packages) {
+ mChangedPackages.add(packageName);
}
}
@Override
- public void onSomePackagesChanged() {
+ public void onPackagesUnsuspended(String[] packages) {
+ // No need to lock this because we access it only on getRegisteredHandler().
+ for (String packageName : packages) {
+ mChangedPackages.add(packageName);
+ }
+ }
+
+ @Override
+ public void onFinishPackageChanges() {
+ onFinishPackageChangesInternal();
+ clearPackageChangeState();
+ }
+
+ private void clearPackageChangeState() {
+ // No need to lock them because we access these fields only on getRegisteredHandler().
+ mChangedPackages.clear();
+ mImePackageAppeared = false;
+ }
+
+ private boolean shouldRebuildInputMethodListLocked() {
+ // This method is guaranteed to be called only by getRegisteredHandler().
+
+ // If there is any new package that contains at least one IME, then rebuilt the list
+ // of IMEs.
+ if (mImePackageAppeared) {
+ return true;
+ }
+
+ // Otherwise, check if mKnownImePackageNames and mChangedPackages have any intersection.
+ // TODO: Consider to create a utility method to do the following test. List.retainAll()
+ // is an option, but it may still do some extra operations that we do not need here.
+ final int N = mChangedPackages.size();
+ for (int i = 0; i < N; ++i) {
+ final String packageName = mChangedPackages.get(i);
+ if (mKnownImePackageNames.contains(packageName)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private void onFinishPackageChangesInternal() {
synchronized (mMethodMap) {
if (!isChangingPackagesOfCurrentUserLocked()) {
return;
}
+ if (!shouldRebuildInputMethodListLocked()) {
+ return;
+ }
+
InputMethodInfo curIm = null;
String curInputMethodId = mSettings.getSelectedInputMethod();
final int N = mMethodList.size();
@@ -1164,13 +1263,14 @@
Bundle extras = new Bundle();
extras.putBoolean(Notification.EXTRA_ALLOW_DURING_SETUP, true);
- mImeSwitcherNotification = new Notification.Builder(mContext)
- .setSmallIcon(com.android.internal.R.drawable.ic_notification_ime_default)
- .setWhen(0)
- .setOngoing(true)
- .addExtras(extras)
- .setCategory(Notification.CATEGORY_SYSTEM)
- .setColor(com.android.internal.R.color.system_notification_accent_color);
+ mImeSwitcherNotification =
+ new Notification.Builder(mContext, SystemNotificationChannels.VIRTUAL_KEYBOARD)
+ .setSmallIcon(com.android.internal.R.drawable.ic_notification_ime_default)
+ .setWhen(0)
+ .setOngoing(true)
+ .addExtras(extras)
+ .setCategory(Notification.CATEGORY_SYSTEM)
+ .setColor(com.android.internal.R.color.system_notification_accent_color);
Intent intent = new Intent(Settings.ACTION_SHOW_INPUT_METHOD_PICKER);
mImeSwitchPendingIntent = PendingIntent.getBroadcast(mContext, 0, intent, 0);
@@ -3283,7 +3383,7 @@
mMethodList.clear();
mMethodMap.clear();
mMethodMapUpdateCount++;
- mMyPackageMonitor.clearPackagesToMonitorComponentChangeLocked();
+ mMyPackageMonitor.clearKnownImePackageNamesLocked();
// Use for queryIntentServicesAsUser
final PackageManager pm = mContext.getPackageManager();
@@ -3339,10 +3439,9 @@
final int N = allInputMethodServices.size();
for (int i = 0; i < N; ++i) {
final ServiceInfo si = allInputMethodServices.get(i).serviceInfo;
- if (!android.Manifest.permission.BIND_INPUT_METHOD.equals(si.permission)) {
- continue;
+ if (android.Manifest.permission.BIND_INPUT_METHOD.equals(si.permission)) {
+ mMyPackageMonitor.addKnownImePackageNameLocked(si.packageName);
}
- mMyPackageMonitor.addPackageToMonitorComponentChangeLocked(si.packageName);
}
}
diff --git a/services/core/java/com/android/server/LocationManagerService.java b/services/core/java/com/android/server/LocationManagerService.java
index ef7780c..979096e 100644
--- a/services/core/java/com/android/server/LocationManagerService.java
+++ b/services/core/java/com/android/server/LocationManagerService.java
@@ -19,6 +19,7 @@
import android.app.ActivityManager;
import android.annotation.NonNull;
import android.content.pm.PackageManagerInternal;
+import android.util.ArrayMap;
import android.util.ArraySet;
import com.android.internal.content.PackageMonitor;
import com.android.internal.location.ProviderProperties;
@@ -104,6 +105,7 @@
import java.util.HashSet;
import java.util.List;
import java.util.Map;
+import java.util.Map.Entry;
import java.util.NoSuchElementException;
import java.util.Set;
@@ -225,6 +227,12 @@
private final ArraySet<String> mBackgroundThrottlePackageWhitelist = new ArraySet<>();
+ private final ArrayMap<IGnssMeasurementsListener, Identity> mGnssMeasurementsListeners =
+ new ArrayMap<>();
+
+ private final ArrayMap<IGnssNavigationMessageListener, Identity>
+ mGnssNavigationMessageListeners = new ArrayMap<>();
+
// current active user on the device - other users are denied location data
private int mCurrentUserId = UserHandle.USER_SYSTEM;
private int[] mCurrentUserProfiles = new int[] { UserHandle.USER_SYSTEM };
@@ -315,17 +323,17 @@
boolean foreground = isImportanceForeground(importance);
HashSet<String> affectedProviders = new HashSet<>(mRecordsByProvider.size());
synchronized (mLock) {
- for (Map.Entry<String, ArrayList<UpdateRecord>> entry
+ for (Entry<String, ArrayList<UpdateRecord>> entry
: mRecordsByProvider.entrySet()) {
String provider = entry.getKey();
for (UpdateRecord record : entry.getValue()) {
- if (record.mReceiver.mUid == uid
+ if (record.mReceiver.mIdentity.mUid == uid
&& record.mIsForegroundUid != foreground) {
if (D) Log.d(TAG, "request from uid " + uid + " is now "
+ (foreground ? "foreground" : "background)"));
record.mIsForegroundUid = foreground;
- if (!isThrottlingExemptLocked(record.mReceiver)) {
+ if (!isThrottlingExemptLocked(record.mReceiver.mIdentity)) {
affectedProviders.add(provider);
}
}
@@ -334,6 +342,33 @@
for (String provider : affectedProviders) {
applyRequirementsLocked(provider);
}
+
+ for (Entry<IGnssMeasurementsListener, Identity> entry
+ : mGnssMeasurementsListeners.entrySet()) {
+ if (entry.getValue().mUid == uid) {
+ if (D) Log.d(TAG, "gnss measurements listener from uid " + uid
+ + " is now " + (foreground ? "foreground" : "background)"));
+ if (foreground || isThrottlingExemptLocked(entry.getValue())) {
+ mGnssMeasurementsProvider.addListener(entry.getKey());
+ } else {
+ mGnssMeasurementsProvider.removeListener(entry.getKey());
+ }
+ }
+ }
+
+ for (Entry<IGnssNavigationMessageListener, Identity> entry
+ : mGnssNavigationMessageListeners.entrySet()) {
+ if (entry.getValue().mUid == uid) {
+ if (D) Log.d(TAG, "gnss navigation message listener from uid "
+ + uid + " is now "
+ + (foreground ? "foreground" : "background)"));
+ if (foreground || isThrottlingExemptLocked(entry.getValue())) {
+ mGnssNavigationMessageProvider.addListener(entry.getKey());
+ } else {
+ mGnssNavigationMessageProvider.removeListener(entry.getKey());
+ }
+ }
+ }
}
}
@@ -344,7 +379,7 @@
mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
updateUserProfiles(mCurrentUserId);
- updateThrottlingWhitelistLocked();
+ updateBackgroundThrottlingWhitelistLocked();
// prepare providers
loadProvidersLocked();
@@ -381,7 +416,7 @@
@Override
public void onChange(boolean selfChange) {
synchronized (mLock) {
- updateThrottlingWhitelistLocked();
+ updateBackgroundThrottlingWhitelistLocked();
updateProvidersLocked();
}
}
@@ -721,14 +756,24 @@
}
}
+ private static final class Identity {
+ final int mUid;
+ final int mPid;
+ final String mPackageName;
+
+ Identity(int uid, int pid, String packageName) {
+ mUid = uid;
+ mPid = pid;
+ mPackageName = packageName;
+ }
+ }
+
/**
* A wrapper class holding either an ILocationListener or a PendingIntent to receive
* location updates.
*/
private final class Receiver implements IBinder.DeathRecipient, PendingIntent.OnFinished {
- final int mUid; // uid of receiver
- final int mPid; // pid of receiver
- final String mPackageName; // package name of receiver
+ final Identity mIdentity;
final int mAllowedResolutionLevel; // resolution level allowed to receiver
final ILocationListener mListener;
@@ -756,9 +801,7 @@
mKey = intent;
}
mAllowedResolutionLevel = getAllowedResolutionLevel(pid, uid);
- mUid = uid;
- mPid = pid;
- mPackageName = packageName;
+ mIdentity = new Identity(uid, pid, packageName);
if (workSource != null && workSource.size() <= 0) {
workSource = null;
}
@@ -770,7 +813,7 @@
// construct/configure wakelock
mWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKELOCK_KEY);
if (workSource == null) {
- workSource = new WorkSource(mUid, mPackageName);
+ workSource = new WorkSource(mIdentity.mUid, mIdentity.mPackageName);
}
mWakeLock.setWorkSource(workSource);
}
@@ -865,13 +908,14 @@
int op) {
if (!currentlyMonitoring) {
if (allowMonitoring) {
- return mAppOps.startOpNoThrow(op, mUid, mPackageName)
+ return mAppOps.startOpNoThrow(op, mIdentity.mUid, mIdentity.mPackageName)
== AppOpsManager.MODE_ALLOWED;
}
} else {
- if (!allowMonitoring || mAppOps.checkOpNoThrow(op, mUid, mPackageName)
+ if (!allowMonitoring
+ || mAppOps.checkOpNoThrow(op, mIdentity.mUid, mIdentity.mPackageName)
!= AppOpsManager.MODE_ALLOWED) {
- mAppOps.finishOp(op, mUid, mPackageName);
+ mAppOps.finishOp(op, mIdentity.mUid, mIdentity.mPackageName);
return false;
}
}
@@ -1628,7 +1672,7 @@
ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
if (records != null) {
for (UpdateRecord record : records) {
- if (isCurrentProfile(UserHandle.getUserId(record.mReceiver.mUid))) {
+ if (isCurrentProfile(UserHandle.getUserId(record.mReceiver.mIdentity.mUid))) {
// Sends a notification message to the receiver
if (!record.mReceiver.callProviderEnabledLocked(provider, enabled)) {
if (deadReceivers == null) {
@@ -1673,16 +1717,16 @@
if (records != null) {
for (UpdateRecord record : records) {
- if (isCurrentProfile(UserHandle.getUserId(record.mReceiver.mUid))) {
+ if (isCurrentProfile(UserHandle.getUserId(record.mReceiver.mIdentity.mUid))) {
if (checkLocationAccess(
- record.mReceiver.mPid,
- record.mReceiver.mUid,
- record.mReceiver.mPackageName,
+ record.mReceiver.mIdentity.mPid,
+ record.mReceiver.mIdentity.mUid,
+ record.mReceiver.mIdentity.mPackageName,
record.mReceiver.mAllowedResolutionLevel)) {
LocationRequest locationRequest = record.mRequest;
long interval = locationRequest.getInterval();
- if (!isThrottlingExemptLocked(record.mReceiver)) {
+ if (!isThrottlingExemptLocked(record.mReceiver.mIdentity)) {
if (!record.mIsForegroundUid) {
interval = Math.max(interval, backgroundThrottleInterval);
}
@@ -1709,7 +1753,7 @@
// under that threshold.
long thresholdInterval = (providerRequest.interval + 1000) * 3 / 2;
for (UpdateRecord record : records) {
- if (isCurrentProfile(UserHandle.getUserId(record.mReceiver.mUid))) {
+ if (isCurrentProfile(UserHandle.getUserId(record.mReceiver.mIdentity.mUid))) {
LocationRequest locationRequest = record.mRequest;
// Don't assign battery blame for update records whose
@@ -1728,8 +1772,8 @@
} else {
// Assign blame to caller.
worksource.add(
- record.mReceiver.mUid,
- record.mReceiver.mPackageName);
+ record.mReceiver.mIdentity.mUid,
+ record.mReceiver.mIdentity.mPackageName);
}
}
}
@@ -1741,7 +1785,15 @@
p.setRequest(providerRequest, worksource);
}
- private void updateThrottlingWhitelistLocked() {
+ @Override
+ public String[] getBackgroundThrottlingWhitelist() {
+ synchronized (mLock) {
+ return mBackgroundThrottlePackageWhitelist.toArray(
+ new String[mBackgroundThrottlePackageWhitelist.size()]);
+ }
+ }
+
+ private void updateBackgroundThrottlingWhitelistLocked() {
String setting = Settings.Global.getString(
mContext.getContentResolver(),
Settings.Global.LOCATION_BACKGROUND_THROTTLE_PACKAGE_WHITELIST);
@@ -1756,17 +1808,17 @@
Arrays.asList(setting.split(",")));
}
- private boolean isThrottlingExemptLocked(Receiver receiver) {
- if (receiver.mUid == Process.SYSTEM_UID) {
+ private boolean isThrottlingExemptLocked(Identity identity) {
+ if (identity.mUid == Process.SYSTEM_UID) {
return true;
}
- if (mBackgroundThrottlePackageWhitelist.contains(receiver.mPackageName)) {
+ if (mBackgroundThrottlePackageWhitelist.contains(identity.mPackageName)) {
return true;
}
for (LocationProviderProxy provider : mProxyProviders) {
- if (receiver.mPackageName.equals(provider.getConnectedPackageName())) {
+ if (identity.mPackageName.equals(provider.getConnectedPackageName())) {
return true;
}
}
@@ -1790,7 +1842,7 @@
mRequest = request;
mReceiver = receiver;
mIsForegroundUid = isImportanceForeground(
- mActivityManager.getPackageImportance(mReceiver.mPackageName));
+ mActivityManager.getPackageImportance(mReceiver.mIdentity.mPackageName));
ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
if (records == null) {
@@ -1803,14 +1855,14 @@
// Update statistics for historical location requests by package/provider
mRequestStatistics.startRequesting(
- mReceiver.mPackageName, provider, request.getInterval());
+ mReceiver.mIdentity.mPackageName, provider, request.getInterval());
}
/**
* Method to be called when a record will no longer be used.
*/
void disposeLocked(boolean removeReceiver) {
- mRequestStatistics.stopRequesting(mReceiver.mPackageName, mProvider);
+ mRequestStatistics.stopRequesting(mReceiver.mIdentity.mPackageName, mProvider);
// remove from mRecordsByProvider
ArrayList<UpdateRecord> globalRecords = mRecordsByProvider.get(this.mProvider);
@@ -1834,8 +1886,8 @@
@Override
public String toString() {
- return "UpdateRecord[" + mProvider + " " + mReceiver.mPackageName
- + "(" + mReceiver.mUid + (mIsForegroundUid ? " foreground" : " background")
+ return "UpdateRecord[" + mProvider + " " + mReceiver.mIdentity.mPackageName
+ + "(" + mReceiver.mIdentity.mUid + (mIsForegroundUid ? " foreground" : " background")
+ ")" + " " + mRequest + "]";
}
}
@@ -1994,7 +2046,8 @@
if (D) Log.d(TAG, "request " + Integer.toHexString(System.identityHashCode(receiver))
+ " " + name + " " + request + " from " + packageName + "(" + uid + " "
+ (record.mIsForegroundUid ? "foreground" : "background")
- + (isThrottlingExemptLocked(receiver) ? " [whitelisted]" : "") + ")");
+ + (isThrottlingExemptLocked(receiver.mIdentity)
+ ? " [whitelisted]" : "") + ")");
UpdateRecord oldRecord = receiver.mUpdateRecords.put(name, record);
if (oldRecord != null) {
@@ -2227,13 +2280,33 @@
if (!hasGnssPermissions(packageName) || mGnssMeasurementsProvider == null) {
return false;
}
- return mGnssMeasurementsProvider.addListener(listener);
+
+ synchronized (mLock) {
+ Identity callerIdentity
+ = new Identity(Binder.getCallingUid(), Binder.getCallingPid(), packageName);
+ mGnssMeasurementsListeners.put(listener, callerIdentity);
+ long identity = Binder.clearCallingIdentity();
+ try {
+ if (isThrottlingExemptLocked(callerIdentity)
+ || isImportanceForeground(
+ mActivityManager.getPackageImportance(packageName))) {
+ return mGnssMeasurementsProvider.addListener(listener);
+ }
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+
+ return true;
+ }
}
@Override
public void removeGnssMeasurementsListener(IGnssMeasurementsListener listener) {
if (mGnssMeasurementsProvider != null) {
- mGnssMeasurementsProvider.removeListener(listener);
+ synchronized (mLock) {
+ mGnssMeasurementsListeners.remove(listener);
+ mGnssMeasurementsProvider.removeListener(listener);
+ }
}
}
@@ -2244,13 +2317,33 @@
if (!hasGnssPermissions(packageName) || mGnssNavigationMessageProvider == null) {
return false;
}
- return mGnssNavigationMessageProvider.addListener(listener);
+
+ synchronized (mLock) {
+ Identity callerIdentity
+ = new Identity(Binder.getCallingUid(), Binder.getCallingPid(), packageName);
+ mGnssNavigationMessageListeners.put(listener, callerIdentity);
+ long identity = Binder.clearCallingIdentity();
+ try {
+ if (isThrottlingExemptLocked(callerIdentity)
+ || isImportanceForeground(
+ mActivityManager.getPackageImportance(packageName))) {
+ return mGnssNavigationMessageProvider.addListener(listener);
+ }
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+
+ return true;
+ }
}
@Override
public void removeGnssNavigationMessageListener(IGnssNavigationMessageListener listener) {
if (mGnssNavigationMessageProvider != null) {
- mGnssNavigationMessageProvider.removeListener(listener);
+ synchronized (mLock) {
+ mGnssNavigationMessageListeners.remove(listener);
+ mGnssNavigationMessageProvider.removeListener(listener);
+ }
}
}
@@ -2529,26 +2622,30 @@
Receiver receiver = r.mReceiver;
boolean receiverDead = false;
- int receiverUserId = UserHandle.getUserId(receiver.mUid);
- if (!isCurrentProfile(receiverUserId) && !isUidALocationProvider(receiver.mUid)) {
+ int receiverUserId = UserHandle.getUserId(receiver.mIdentity.mUid);
+ if (!isCurrentProfile(receiverUserId)
+ && !isUidALocationProvider(receiver.mIdentity.mUid)) {
if (D) {
Log.d(TAG, "skipping loc update for background user " + receiverUserId +
" (current user: " + mCurrentUserId + ", app: " +
- receiver.mPackageName + ")");
+ receiver.mIdentity.mPackageName + ")");
}
continue;
}
- if (mBlacklist.isBlacklisted(receiver.mPackageName)) {
+ if (mBlacklist.isBlacklisted(receiver.mIdentity.mPackageName)) {
if (D) Log.d(TAG, "skipping loc update for blacklisted app: " +
- receiver.mPackageName);
+ receiver.mIdentity.mPackageName);
continue;
}
- if (!reportLocationAccessNoThrow(receiver.mPid, receiver.mUid, receiver.mPackageName,
+ if (!reportLocationAccessNoThrow(
+ receiver.mIdentity.mPid,
+ receiver.mIdentity.mUid,
+ receiver.mIdentity.mPackageName,
receiver.mAllowedResolutionLevel)) {
if (D) Log.d(TAG, "skipping loc update for no op app: " +
- receiver.mPackageName);
+ receiver.mIdentity.mPackageName);
continue;
}
@@ -2671,7 +2768,7 @@
ArrayList<Receiver> deadReceivers = null;
for (Receiver receiver : mReceivers.values()) {
- if (receiver.mPackageName.equals(packageName)) {
+ if (receiver.mIdentity.mPackageName.equals(packageName)) {
if (deadReceivers == null) {
deadReceivers = new ArrayList<>();
}
diff --git a/services/core/java/com/android/server/LockSettingsService.java b/services/core/java/com/android/server/LockSettingsService.java
index f76ddc7..0a9610f 100644
--- a/services/core/java/com/android/server/LockSettingsService.java
+++ b/services/core/java/com/android/server/LockSettingsService.java
@@ -76,6 +76,7 @@
import android.util.Slog;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.notification.SystemNotificationChannels;
import com.android.internal.util.ArrayUtils;
import com.android.internal.widget.ICheckCredentialProgressCallback;
import com.android.internal.widget.ILockSettings;
@@ -442,21 +443,20 @@
// Suppress all notifications on non-FBE devices for now
if (!StorageManager.isFileEncryptedNativeOrEmulated()) return;
- Notification notification = new Notification.Builder(mContext)
- .setSmallIcon(com.android.internal.R.drawable.ic_user_secure)
- .setWhen(0)
- .setOngoing(true)
- .setTicker(title)
- .setDefaults(0) // please be quiet
- .setPriority(Notification.PRIORITY_MAX)
- .setColor(mContext.getColor(
- com.android.internal.R.color.system_notification_accent_color))
- .setContentTitle(title)
- .setContentText(message)
- .setSubText(detail)
- .setVisibility(Notification.VISIBILITY_PUBLIC)
- .setContentIntent(intent)
- .build();
+ Notification notification =
+ new Notification.Builder(mContext, SystemNotificationChannels.SECURITY)
+ .setSmallIcon(com.android.internal.R.drawable.ic_user_secure)
+ .setWhen(0)
+ .setOngoing(true)
+ .setTicker(title)
+ .setColor(mContext.getColor(
+ com.android.internal.R.color.system_notification_accent_color))
+ .setContentTitle(title)
+ .setContentText(message)
+ .setSubText(detail)
+ .setVisibility(Notification.VISIBILITY_PUBLIC)
+ .setContentIntent(intent)
+ .build();
mNotificationManager.notifyAsUser(null, FBE_ENCRYPTED_NOTIFICATION, notification, user);
}
diff --git a/services/core/java/com/android/server/NetworkScoreService.java b/services/core/java/com/android/server/NetworkScoreService.java
index b33538cb..b83dbd6 100644
--- a/services/core/java/com/android/server/NetworkScoreService.java
+++ b/services/core/java/com/android/server/NetworkScoreService.java
@@ -35,8 +35,7 @@
import android.net.INetworkScoreService;
import android.net.NetworkKey;
import android.net.NetworkScoreManager;
-import android.net.NetworkScorerAppManager;
-import android.net.NetworkScorerAppManager.NetworkScorerAppData;
+import android.net.NetworkScorerAppData;
import android.net.RecommendationRequest;
import android.net.RecommendationResult;
import android.net.ScoredNetwork;
@@ -132,10 +131,10 @@
* manages the service connection.
*/
private class NetworkScorerPackageMonitor extends PackageMonitor {
- final List<String> mPackagesToWatch;
+ final String mPackageToWatch;
- private NetworkScorerPackageMonitor(List<String> packagesToWatch) {
- mPackagesToWatch = packagesToWatch;
+ private NetworkScorerPackageMonitor(String packageToWatch) {
+ mPackageToWatch = packageToWatch;
}
@Override
@@ -168,37 +167,27 @@
evaluateBinding(packageName, true /* forceUnbind */);
}
- private void evaluateBinding(String scorerPackageName, boolean forceUnbind) {
- if (!mPackagesToWatch.contains(scorerPackageName)) {
+ private void evaluateBinding(String changedPackageName, boolean forceUnbind) {
+ if (!mPackageToWatch.equals(changedPackageName)) {
// Early exit when we don't care about the package that has changed.
return;
}
if (DBG) {
- Log.d(TAG, "Evaluating binding for: " + scorerPackageName
+ Log.d(TAG, "Evaluating binding for: " + changedPackageName
+ ", forceUnbind=" + forceUnbind);
}
+
final NetworkScorerAppData activeScorer = mNetworkScorerAppManager.getActiveScorer();
if (activeScorer == null) {
// Package change has invalidated a scorer, this will also unbind any service
// connection.
if (DBG) Log.d(TAG, "No active scorers available.");
- unbindFromScoringServiceIfNeeded();
- } else if (activeScorer.getRecommendationServicePackageName().equals(scorerPackageName))
- {
- // The active scoring service changed in some way.
- if (DBG) {
- Log.d(TAG, "Possible change to the active scorer: "
- + activeScorer.getRecommendationServicePackageName());
- }
+ refreshBinding();
+ } else { // The scoring service changed in some way.
if (forceUnbind) {
unbindFromScoringServiceIfNeeded();
}
- bindToScoringServiceIfNeeded(activeScorer);
- } else {
- // One of the scoring apps on the device has changed and we may no longer be
- // bound to the correct scoring app. The logic in bindToScoringServiceIfNeeded()
- // will sort that out to leave us bound to the most recent active scorer.
if (DBG) {
Log.d(TAG, "Binding to " + activeScorer.getRecommendationServiceComponent()
+ " if needed.");
@@ -272,60 +261,71 @@
/** Called when the system is ready to run third-party code but before it actually does so. */
void systemReady() {
if (DBG) Log.d(TAG, "systemReady");
- registerPackageMonitorIfNeeded();
registerRecommendationSettingsObserver();
- refreshRecommendationRequestTimeoutMs();
}
/** Called when the system is ready for us to start third-party code. */
void systemRunning() {
if (DBG) Log.d(TAG, "systemRunning");
- bindToScoringServiceIfNeeded();
}
- private void onUserUnlocked(int userId) {
+ @VisibleForTesting
+ void onUserUnlocked(int userId) {
+ if (DBG) Log.d(TAG, "onUserUnlocked(" + userId + ")");
+ refreshBinding();
+ }
+
+ private void refreshBinding() {
+ if (DBG) Log.d(TAG, "refreshBinding()");
+ // Apply the default package name if the Setting isn't set.
+ mNetworkScorerAppManager.revertToDefaultIfNoActive();
registerPackageMonitorIfNeeded();
bindToScoringServiceIfNeeded();
}
private void registerRecommendationSettingsObserver() {
- final List<String> providerPackages =
- mNetworkScorerAppManager.getPotentialRecommendationProviderPackages();
- if (!providerPackages.isEmpty()) {
- final Uri enabledUri = Global.getUriFor(Global.NETWORK_RECOMMENDATIONS_ENABLED);
- mContentObserver.observe(enabledUri,
- ServiceHandler.MSG_RECOMMENDATIONS_ENABLED_CHANGED);
- }
+ final Uri packageNameUri = Global.getUriFor(Global.NETWORK_RECOMMENDATIONS_PACKAGE);
+ mContentObserver.observe(packageNameUri,
+ ServiceHandler.MSG_RECOMMENDATIONS_PACKAGE_CHANGED);
final Uri timeoutUri = Global.getUriFor(Global.NETWORK_RECOMMENDATION_REQUEST_TIMEOUT_MS);
mContentObserver.observe(timeoutUri,
ServiceHandler.MSG_RECOMMENDATION_REQUEST_TIMEOUT_CHANGED);
}
+ /**
+ * Ensures the package manager is registered to monitor the current active scorer.
+ * If a discrepancy is found any previous monitor will be cleaned up
+ * and a new monitor will be created.
+ *
+ * This method is idempotent.
+ */
private void registerPackageMonitorIfNeeded() {
- if (DBG) Log.d(TAG, "registerPackageMonitorIfNeeded");
- final List<String> providerPackages =
- mNetworkScorerAppManager.getPotentialRecommendationProviderPackages();
+ if (DBG) Log.d(TAG, "registerPackageMonitorIfNeeded()");
+ final NetworkScorerAppData appData = mNetworkScorerAppManager.getActiveScorer();
synchronized (mPackageMonitorLock) {
// Unregister the current monitor if needed.
- if (mPackageMonitor != null) {
+ if (mPackageMonitor != null && (appData == null
+ || !appData.getRecommendationServicePackageName().equals(
+ mPackageMonitor.mPackageToWatch))) {
if (DBG) {
Log.d(TAG, "Unregistering package monitor for "
- + mPackageMonitor.mPackagesToWatch);
+ + mPackageMonitor.mPackageToWatch);
}
mPackageMonitor.unregister();
mPackageMonitor = null;
}
- // Create and register the monitor if there are packages that could be providers.
- if (!providerPackages.isEmpty()) {
- mPackageMonitor = new NetworkScorerPackageMonitor(providerPackages);
+ // Create and register the monitor if a scorer is active.
+ if (appData != null && mPackageMonitor == null) {
+ mPackageMonitor = new NetworkScorerPackageMonitor(
+ appData.getRecommendationServicePackageName());
// TODO: Need to update when we support per-user scorers. http://b/23422763
mPackageMonitor.register(mContext, null /* thread */, UserHandle.SYSTEM,
false /* externalStorage */);
if (DBG) {
Log.d(TAG, "Registered package monitor for "
- + mPackageMonitor.mPackagesToWatch);
+ + mPackageMonitor.mPackageToWatch);
}
}
}
@@ -337,6 +337,13 @@
bindToScoringServiceIfNeeded(scorerData);
}
+ /**
+ * Ensures the service connection is bound to the current active scorer.
+ * If a discrepancy is found any previous connection will be cleaned up
+ * and a new connection will be created.
+ *
+ * This method is idempotent.
+ */
private void bindToScoringServiceIfNeeded(NetworkScorerAppData appData) {
if (DBG) Log.d(TAG, "bindToScoringServiceIfNeeded(" + appData + ")");
if (appData != null) {
@@ -365,6 +372,8 @@
synchronized (mServiceConnectionLock) {
if (mServiceConnection != null) {
mServiceConnection.disconnect(mContext);
+ if (DBG) Log.d(TAG, "Disconnected from: "
+ + mServiceConnection.mAppData.getRecommendationServiceComponent());
}
mServiceConnection = null;
}
@@ -653,17 +662,13 @@
@Override
public boolean setActiveScorer(String packageName) {
- // TODO: For now, since SCORE_NETWORKS requires an app to be privileged, we allow such apps
- // to directly set the scorer app rather than having to use the consent dialog. The
- // assumption is that anyone bundling a scorer app with the system is trusted by the OEM to
- // do the right thing and not enable this feature without explaining it to the user.
- // In the future, should this API be opened to 3p apps, we will need to lock this down and
- // figure out another way to streamline the UX.
+ // Only the system can set the active scorer
+ if (!isCallerSystemProcess(getCallingUid()) || !callerCanRequestScores()) {
+ throw new SecurityException(
+ "Caller is neither the system process nor a score requester.");
+ }
- mContext.enforceCallingOrSelfPermission(permission.SCORE_NETWORKS, TAG);
-
- // Scorers (recommendation providers) are selected and no longer set.
- return false;
+ return mNetworkScorerAppManager.setActiveScorer(packageName);
}
/**
@@ -700,7 +705,6 @@
return null;
}
-
/**
* Returns metadata about the active scorer or <code>null</code> if there is no active scorer.
*/
@@ -727,18 +731,24 @@
*/
@Override
public List<NetworkScorerAppData> getAllValidScorers() {
+ // Only the system can access this data.
+ if (!isCallerSystemProcess(getCallingUid()) || !callerCanRequestScores()) {
+ throw new SecurityException(
+ "Caller is neither the system process nor a score requester.");
+ }
+
return mNetworkScorerAppManager.getAllValidScorers();
}
@Override
public void disableScoring() {
// Only the active scorer or the system should be allowed to disable scoring.
- if (isCallerActiveScorer(getCallingUid()) || callerCanRequestScores()) {
- // no-op for now but we could write to the setting if needed.
- } else {
+ if (!isCallerActiveScorer(getCallingUid()) || !callerCanRequestScores()) {
throw new SecurityException(
"Caller is neither the active scorer nor the scorer manager.");
}
+
+ // no-op for now but we could write to the setting if needed.
}
/** Clear scores. Callers are responsible for checking permissions as appropriate. */
@@ -1159,7 +1169,7 @@
@VisibleForTesting
public final class ServiceHandler extends Handler {
public static final int MSG_RECOMMENDATION_REQUEST_TIMEOUT = 1;
- public static final int MSG_RECOMMENDATIONS_ENABLED_CHANGED = 2;
+ public static final int MSG_RECOMMENDATIONS_PACKAGE_CHANGED = 2;
public static final int MSG_RECOMMENDATION_REQUEST_TIMEOUT_CHANGED = 3;
public ServiceHandler(Looper looper) {
@@ -1181,8 +1191,8 @@
sendDefaultRecommendationResponse(request, remoteCallback);
break;
- case MSG_RECOMMENDATIONS_ENABLED_CHANGED:
- bindToScoringServiceIfNeeded();
+ case MSG_RECOMMENDATIONS_PACKAGE_CHANGED:
+ refreshBinding();
break;
case MSG_RECOMMENDATION_REQUEST_TIMEOUT_CHANGED:
diff --git a/services/core/java/com/android/server/NetworkScorerAppManager.java b/services/core/java/com/android/server/NetworkScorerAppManager.java
new file mode 100644
index 0000000..2f4485a
--- /dev/null
+++ b/services/core/java/com/android/server/NetworkScorerAppManager.java
@@ -0,0 +1,245 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.server;
+
+import android.Manifest.permission;
+import android.annotation.Nullable;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.content.pm.ServiceInfo;
+import android.net.NetworkScoreManager;
+import android.net.NetworkScorerAppData;
+import android.provider.Settings;
+import android.text.TextUtils;
+import android.util.Log;
+
+import com.android.internal.R;
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Internal class for discovering and managing the network scorer/recommendation application.
+ *
+ * @hide
+ */
+@VisibleForTesting
+public class NetworkScorerAppManager {
+ private static final String TAG = "NetworkScorerAppManager";
+ private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+ private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE);
+ private final Context mContext;
+ private final SettingsFacade mSettingsFacade;
+
+ public NetworkScorerAppManager(Context context) {
+ this(context, new SettingsFacade());
+ }
+
+ @VisibleForTesting
+ public NetworkScorerAppManager(Context context, SettingsFacade settingsFacade) {
+ mContext = context;
+ mSettingsFacade = settingsFacade;
+ }
+
+ /**
+ * Returns the list of available scorer apps. The list will be empty if there are
+ * no valid scorers.
+ */
+ @VisibleForTesting
+ public List<NetworkScorerAppData> getAllValidScorers() {
+ if (VERBOSE) Log.v(TAG, "getAllValidScorers()");
+ final PackageManager pm = mContext.getPackageManager();
+ final Intent serviceIntent = new Intent(NetworkScoreManager.ACTION_RECOMMEND_NETWORKS);
+ final List<ResolveInfo> resolveInfos =
+ pm.queryIntentServices(serviceIntent, PackageManager.GET_META_DATA);
+ if (resolveInfos == null || resolveInfos.isEmpty()) {
+ if (DEBUG) Log.d(TAG, "Found 0 Services able to handle " + serviceIntent);
+ return Collections.emptyList();
+ }
+
+ List<NetworkScorerAppData> appDataList = new ArrayList<>();
+ for (int i = 0; i < resolveInfos.size(); i++) {
+ final ServiceInfo serviceInfo = resolveInfos.get(i).serviceInfo;
+ if (hasPermissions(serviceInfo.packageName)) {
+ if (VERBOSE) {
+ Log.v(TAG, serviceInfo.packageName + " is a valid scorer/recommender.");
+ }
+ final ComponentName serviceComponentName =
+ new ComponentName(serviceInfo.packageName, serviceInfo.name);
+ final ComponentName useOpenWifiNetworksActivity =
+ findUseOpenWifiNetworksActivity(serviceInfo);
+ appDataList.add(
+ new NetworkScorerAppData(serviceInfo.applicationInfo.uid,
+ serviceComponentName, useOpenWifiNetworksActivity));
+ } else {
+ if (VERBOSE) Log.v(TAG, serviceInfo.packageName
+ + " is NOT a valid scorer/recommender.");
+ }
+ }
+
+ return appDataList;
+ }
+
+ @Nullable
+ private ComponentName findUseOpenWifiNetworksActivity(ServiceInfo serviceInfo) {
+ if (serviceInfo.metaData == null) {
+ if (DEBUG) {
+ Log.d(TAG, "No metadata found on " + serviceInfo.getComponentName());
+ }
+ return null;
+ }
+ final String useOpenWifiPackage = serviceInfo.metaData
+ .getString(NetworkScoreManager.USE_OPEN_WIFI_PACKAGE_META_DATA);
+ if (TextUtils.isEmpty(useOpenWifiPackage)) {
+ if (DEBUG) {
+ Log.d(TAG, "No use_open_wifi_package metadata found on "
+ + serviceInfo.getComponentName());
+ }
+ return null;
+ }
+ final Intent enableUseOpenWifiIntent = new Intent(NetworkScoreManager.ACTION_CUSTOM_ENABLE)
+ .setPackage(useOpenWifiPackage);
+ final ResolveInfo resolveActivityInfo = mContext.getPackageManager()
+ .resolveActivity(enableUseOpenWifiIntent, 0 /* flags */);
+ if (VERBOSE) {
+ Log.d(TAG, "Resolved " + enableUseOpenWifiIntent + " to " + resolveActivityInfo);
+ }
+
+ if (resolveActivityInfo != null && resolveActivityInfo.activityInfo != null) {
+ return resolveActivityInfo.activityInfo.getComponentName();
+ }
+
+ return null;
+ }
+
+ /**
+ * Get the application to use for scoring networks.
+ *
+ * @return the scorer app info or null if scoring is disabled (including if no scorer was ever
+ * selected) or if the previously-set scorer is no longer a valid scorer app (e.g. because
+ * it was disabled or uninstalled).
+ */
+ @Nullable
+ @VisibleForTesting
+ public NetworkScorerAppData getActiveScorer() {
+ return getScorer(getNetworkRecommendationsPackage());
+ }
+
+ private NetworkScorerAppData getScorer(String packageName) {
+ if (TextUtils.isEmpty(packageName)) {
+ return null;
+ }
+
+ // Otherwise return the recommendation provider (which may be null).
+ List<NetworkScorerAppData> apps = getAllValidScorers();
+ for (int i = 0; i < apps.size(); i++) {
+ NetworkScorerAppData app = apps.get(i);
+ if (app.getRecommendationServicePackageName().equals(packageName)) {
+ return app;
+ }
+ }
+
+ return null;
+ }
+
+ private boolean hasPermissions(String packageName) {
+ final PackageManager pm = mContext.getPackageManager();
+ return pm.checkPermission(permission.SCORE_NETWORKS, packageName)
+ == PackageManager.PERMISSION_GRANTED;
+ }
+
+ /**
+ * Set the specified package as the default scorer application.
+ *
+ * <p>The caller must have permission to write to {@link Settings.Global}.
+ *
+ * @param packageName the packageName of the new scorer to use. If null, the scoring app will
+ * revert back to the configured default. Otherwise, the scorer will only
+ * be set if it is a valid scorer application.
+ * @return true if the scorer was changed, or false if the package is not a valid scorer or
+ * a valid network recommendation provider exists.
+ */
+ @VisibleForTesting
+ public boolean setActiveScorer(String packageName) {
+ String oldPackageName = getNetworkRecommendationsPackage();
+ if (TextUtils.equals(oldPackageName, packageName)) {
+ // No change.
+ return true;
+ }
+
+ Log.i(TAG, "Changing network scorer from " + oldPackageName + " to " + packageName);
+
+ if (packageName == null) {
+ // revert to the default setting.
+ setNetworkRecommendationsPackage(getDefaultPackageSetting());
+ return true;
+ } else {
+ // We only make the change if the new package is valid.
+ if (getScorer(packageName) != null) {
+ setNetworkRecommendationsPackage(packageName);
+ return true;
+ } else {
+ Log.w(TAG, "Requested network scorer is not valid: " + packageName);
+ return false;
+ }
+ }
+ }
+
+ /**
+ * If the active scorer is null then revert to the default scorer.
+ */
+ @VisibleForTesting
+ public void revertToDefaultIfNoActive() {
+ if (getActiveScorer() == null) {
+ final String defaultPackage = getDefaultPackageSetting();
+ setNetworkRecommendationsPackage(defaultPackage);
+ Log.i(TAG, "Defaulted the network recommendations app to: " + defaultPackage);
+ }
+ }
+
+ private String getDefaultPackageSetting() {
+ return mContext.getResources().getString(
+ R.string.config_defaultNetworkRecommendationProviderPackage);
+ }
+
+ private String getNetworkRecommendationsPackage() {
+ return mSettingsFacade.getString(mContext, Settings.Global.NETWORK_RECOMMENDATIONS_PACKAGE);
+ }
+
+ private void setNetworkRecommendationsPackage(String packageName) {
+ mSettingsFacade.putString(mContext,
+ Settings.Global.NETWORK_RECOMMENDATIONS_PACKAGE, packageName);
+ }
+
+ /**
+ * Wrapper around Settings to make testing easier.
+ */
+ public static class SettingsFacade {
+ public boolean putString(Context context, String name, String value) {
+ return Settings.Global.putString(context.getContentResolver(), name, value);
+ }
+
+ public String getString(Context context, String name) {
+ return Settings.Global.getString(context.getContentResolver(), name);
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/RescueParty.java b/services/core/java/com/android/server/RescueParty.java
index 33351ff..480b08a 100644
--- a/services/core/java/com/android/server/RescueParty.java
+++ b/services/core/java/com/android/server/RescueParty.java
@@ -19,13 +19,9 @@
import android.content.ContentResolver;
import android.content.Context;
import android.content.pm.UserInfo;
-import android.os.BatteryManager;
-import android.os.BatteryProperties;
import android.os.Build;
-import android.os.IBatteryPropertiesListener;
-import android.os.IBatteryPropertiesRegistrar;
+import android.os.FileUtils;
import android.os.RecoverySystem;
-import android.os.ServiceManager;
import android.os.SystemClock;
import android.os.SystemProperties;
import android.os.UserHandle;
@@ -34,14 +30,12 @@
import android.text.format.DateUtils;
import android.util.ExceptionUtils;
import android.util.MathUtils;
-import android.util.MutableBoolean;
import android.util.Slog;
import android.util.SparseArray;
import com.android.internal.util.ArrayUtils;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
+import java.io.File;
/**
* Utilities to help rescue the system from crash loops. Callers are expected to
@@ -325,30 +319,13 @@
/**
* Hacky test to check if the device has an active USB connection, which is
- * a good proxy for someone doing local development work. It uses a low
- * level call since we may not have started {@link BatteryManager} yet.
+ * a good proxy for someone doing local development work.
*/
private static boolean isUsbActive() {
- final MutableBoolean res = new MutableBoolean(false);
- final CountDownLatch latch = new CountDownLatch(1);
- final IBatteryPropertiesListener listener = new IBatteryPropertiesListener.Stub() {
- @Override
- public void batteryPropertiesChanged(BatteryProperties props) {
- res.value = props.chargerUsbOnline;
- latch.countDown();
- }
- };
-
try {
- final IBatteryPropertiesRegistrar bpr = IBatteryPropertiesRegistrar.Stub
- .asInterface(ServiceManager.getService("batteryproperties"));
- bpr.registerListener(listener);
- try {
- latch.await(5, TimeUnit.SECONDS);
- } finally {
- bpr.unregisterListener(listener);
- }
- return res.value;
+ final String state = FileUtils
+ .readTextFile(new File("/sys/class/android_usb/android0/state"), 128, "");
+ return "CONFIGURED".equals(state.trim());
} catch (Throwable t) {
Slog.w(TAG, "Failed to determine if device was on USB", t);
return false;
diff --git a/services/core/java/com/android/server/SystemService.java b/services/core/java/com/android/server/SystemService.java
index ce3166d..421d5a6 100644
--- a/services/core/java/com/android/server/SystemService.java
+++ b/services/core/java/com/android/server/SystemService.java
@@ -19,6 +19,7 @@
import android.content.Context;
import android.os.IBinder;
import android.os.ServiceManager;
+import android.os.UserManager;
/**
* The base class for services running in the system process. Override and implement
@@ -133,9 +134,16 @@
public void onStartUser(int userHandle) {}
/**
- * Called when an existing user is unlocked. This means the
- * credential-encrypted storage for that user is now available, and
- * encryption-aware component filtering is no longer in effect.
+ * Called when an existing user is in the process of being unlocked. This
+ * means the credential-encrypted storage for that user is now available,
+ * and encryption-aware component filtering is no longer in effect.
+ * <p>
+ * While dispatching this event to services, the user is in the
+ * {@code STATE_RUNNING_UNLOCKING} state, and once dispatching is finished
+ * the user will transition into the {@code STATE_RUNNING_UNLOCKED} state.
+ * Code written inside system services should use
+ * {@link UserManager#isUserUnlockingOrUnlocked(int)} to handle both of
+ * these states.
*
* @param userHandle The identifier of the user.
*/
diff --git a/services/core/java/com/android/server/SystemServiceManager.java b/services/core/java/com/android/server/SystemServiceManager.java
index 3f97d4f..cb13a3d 100644
--- a/services/core/java/com/android/server/SystemServiceManager.java
+++ b/services/core/java/com/android/server/SystemServiceManager.java
@@ -16,6 +16,7 @@
package com.android.server;
+import android.annotation.NonNull;
import android.content.Context;
import android.os.Trace;
import android.util.Slog;
@@ -105,22 +106,25 @@
+ ": service constructor threw an exception", ex);
}
- // 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);
- }
+ startService(service);
return service;
} finally {
Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
}
}
+ public void startService(@NonNull final SystemService service) {
+ // Register it.
+ mServices.add(service);
+ // Start it.
+ try {
+ service.onStart();
+ } catch (RuntimeException ex) {
+ throw new RuntimeException("Failed to start service " + service.getClass().getName()
+ + ": onStart threw an exception", ex);
+ }
+ }
+
/**
* Starts the specified boot phase for all system services that have been started up to
* this point.
diff --git a/services/core/java/com/android/server/UiModeManagerService.java b/services/core/java/com/android/server/UiModeManagerService.java
index acacb9e..5115fde 100644
--- a/services/core/java/com/android/server/UiModeManagerService.java
+++ b/services/core/java/com/android/server/UiModeManagerService.java
@@ -58,6 +58,7 @@
import com.android.internal.R;
import com.android.internal.app.DisableCarModeActivity;
+import com.android.internal.notification.SystemNotificationChannels;
import com.android.server.power.ShutdownThread;
import com.android.server.twilight.TwilightListener;
import com.android.server.twilight.TwilightManager;
@@ -739,7 +740,8 @@
if (mCarModeEnabled) {
Intent carModeOffIntent = new Intent(context, DisableCarModeActivity.class);
- Notification.Builder n = new Notification.Builder(context)
+ Notification.Builder n =
+ new Notification.Builder(context, SystemNotificationChannels.CAR_MODE)
.setSmallIcon(R.drawable.stat_notify_car_mode)
.setDefaults(Notification.DEFAULT_LIGHTS)
.setOngoing(true)
diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java
index 1b2c75d..dc73b63 100644
--- a/services/core/java/com/android/server/accounts/AccountManagerService.java
+++ b/services/core/java/com/android/server/accounts/AccountManagerService.java
@@ -92,6 +92,7 @@
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.content.PackageMonitor;
+import com.android.internal.notification.SystemNotificationChannels;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.IndentingPrintWriter;
import com.android.internal.util.Preconditions;
@@ -2780,16 +2781,17 @@
}
UserHandle user = UserHandle.of(userId);
Context contextForUser = getContextForUser(user);
- Notification n = new Notification.Builder(contextForUser)
- .setSmallIcon(android.R.drawable.stat_sys_warning)
- .setWhen(0)
- .setColor(contextForUser.getColor(
- com.android.internal.R.color.system_notification_accent_color))
- .setContentTitle(title)
- .setContentText(subtitle)
- .setContentIntent(PendingIntent.getActivityAsUser(mContext, 0, intent,
- PendingIntent.FLAG_CANCEL_CURRENT, null, user))
- .build();
+ Notification n =
+ new Notification.Builder(contextForUser, SystemNotificationChannels.ACCOUNT)
+ .setSmallIcon(android.R.drawable.stat_sys_warning)
+ .setWhen(0)
+ .setColor(contextForUser.getColor(
+ com.android.internal.R.color.system_notification_accent_color))
+ .setContentTitle(title)
+ .setContentText(subtitle)
+ .setContentIntent(PendingIntent.getActivityAsUser(mContext, 0, intent,
+ PendingIntent.FLAG_CANCEL_CURRENT, null, user))
+ .build();
installNotification(getCredentialPermissionNotificationId(
account, authTokenType, uid), n, packageName, user.getIdentifier());
}
@@ -4844,7 +4846,8 @@
final String notificationTitleFormat =
contextForUser.getText(R.string.notification_title).toString();
- Notification n = new Notification.Builder(contextForUser)
+ Notification n =
+ new Notification.Builder(contextForUser, SystemNotificationChannels.ACCOUNT)
.setWhen(0)
.setSmallIcon(android.R.drawable.stat_sys_warning)
.setColor(contextForUser.getColor(
@@ -4864,6 +4867,7 @@
private void installNotification(int notificationId, final Notification notification,
String packageName, int userId) {
+ SystemNotificationChannels.createAccountChannelForPackage(packageName, mContext);
final long token = clearCallingIdentity();
try {
INotificationManager notificationManager = mInjector.getNotificationManager();
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index 2bc131f..b4f8f61 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -2810,14 +2810,13 @@
}
List<ActivityManager.RunningServiceInfo> getRunningServiceInfoLocked(int maxNum, int flags,
- int callingUid, boolean allowed) {
+ int callingUid, boolean allowed, boolean canInteractAcrossUsers) {
ArrayList<ActivityManager.RunningServiceInfo> res
= new ArrayList<ActivityManager.RunningServiceInfo>();
final long ident = Binder.clearCallingIdentity();
try {
- if (ActivityManager.checkUidPermission(INTERACT_ACROSS_USERS_FULL, callingUid)
- == PERMISSION_GRANTED) {
+ if (canInteractAcrossUsers) {
int[] users = mAm.mUserController.getUsers();
for (int ui=0; ui<users.length && res.size() < maxNum; ui++) {
ArrayMap<ComponentName, ServiceRecord> alls = getServicesLocked(users[ui]);
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 03d2e0b..d22e49b 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -316,6 +316,7 @@
import android.view.View;
import android.view.WindowManager;
+import com.android.internal.notification.SystemNotificationChannels;
import com.google.android.collect.Lists;
import com.google.android.collect.Maps;
@@ -1986,7 +1987,8 @@
Context context = mContext.createPackageContext(process.info.packageName, 0);
String text = mContext.getString(R.string.heavy_weight_notification,
context.getApplicationInfo().loadLabel(context.getPackageManager()));
- Notification notification = new Notification.Builder(context)
+ Notification notification =
+ new Notification.Builder(context, SystemNotificationChannels.DEVELOPER)
.setSmallIcon(com.android.internal.R.drawable.stat_sys_adb)
.setWhen(0)
.setOngoing(true)
@@ -2236,7 +2238,8 @@
intent.putExtra(DumpHeapActivity.KEY_DIRECT_LAUNCH, reportPackage);
}
int userId = UserHandle.getUserId(uid);
- Notification notification = new Notification.Builder(mContext)
+ Notification notification =
+ new Notification.Builder(mContext, SystemNotificationChannels.DEVELOPER)
.setSmallIcon(com.android.internal.R.drawable.stat_sys_adb)
.setWhen(0)
.setOngoing(true)
@@ -3064,15 +3067,24 @@
startRunningVoiceLocked(r.task.voiceSession, r.info.applicationInfo.uid);
} else {
finishRunningVoiceLocked();
- IVoiceInteractionSession session;
- if (mLastResumedActivity != null
- && ((session = mLastResumedActivity.task.voiceSession) != null
- || (session = mLastResumedActivity.voiceSession) != null)) {
- // We had been in a voice interaction session, but now focused has
- // move to something different. Just finish the session, we can't
- // return to it and retain the proper state and synchronization with
- // the voice interaction service.
- finishVoiceTask(session);
+
+ if (mLastResumedActivity != null) {
+ final IVoiceInteractionSession session;
+
+ if (mLastResumedActivity.task != null
+ && mLastResumedActivity.task.voiceSession != null) {
+ session = mLastResumedActivity.task.voiceSession;
+ } else {
+ session = mLastResumedActivity.voiceSession;
+ }
+
+ if (session != null) {
+ // We had been in a voice interaction session, but now focused has
+ // move to something different. Just finish the session, we can't
+ // return to it and retain the proper state and synchronization with
+ // the voice interaction service.
+ finishVoiceTask(session);
+ }
}
}
@@ -7735,7 +7747,7 @@
aspectRatio);
mStackSupervisor.moveActivityToPinnedStackLocked(r, "enterPictureInPictureMode",
bounds, true /* moveHomeStackToFront */);
- final ActivityStack stack = mStackSupervisor.getStack(PINNED_STACK_ID);
+ final PinnedActivityStack stack = mStackSupervisor.getStack(PINNED_STACK_ID);
stack.setPictureInPictureAspectRatio(aspectRatio);
stack.setPictureInPictureActions(actions);
@@ -7789,9 +7801,9 @@
// Only update the saved args from the args that are set
r.pictureInPictureArgs.copyOnlySet(args);
- final ActivityStack stack = r.getStack();
- if (stack.getStackId() == PINNED_STACK_ID) {
+ if (r.getStack().getStackId() == PINNED_STACK_ID) {
// If the activity is already in picture-in-picture, update the pinned stack now
+ final PinnedActivityStack stack = r.getStack();
stack.setPictureInPictureAspectRatio(r.pictureInPictureArgs.getAspectRatio());
stack.setPictureInPictureActions(r.pictureInPictureArgs.getActions());
}
@@ -10353,7 +10365,7 @@
synchronized (this) {
if (animate) {
if (stackId == PINNED_STACK_ID) {
- final ActivityStack pinnedStack =
+ final PinnedActivityStack pinnedStack =
mStackSupervisor.getStack(PINNED_STACK_ID);
pinnedStack.animateResizePinnedStack(bounds, animationDuration);
} else {
@@ -10677,7 +10689,7 @@
providers = AppGlobals.getPackageManager()
.queryContentProviders(app.processName, app.uid,
STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS
- | MATCH_DEBUG_TRIAGED_MISSING)
+ | MATCH_DEBUG_TRIAGED_MISSING, /*metadastaKey=*/ null)
.getList();
} catch (RemoteException ex) {
}
@@ -10743,16 +10755,14 @@
try {
cpi = AppGlobals.getPackageManager().resolveContentProvider(authority,
STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS
+ | PackageManager.MATCH_DISABLED_COMPONENTS
| PackageManager.MATCH_DIRECT_BOOT_AWARE
| PackageManager.MATCH_DIRECT_BOOT_UNAWARE,
userId);
} catch (RemoteException ignored) {
}
if (cpi == null) {
- // TODO: make this an outright failure in a future platform release;
- // until then anonymous content notifications are unprotected
- //return "Failed to find provider " + authority + " for user " + userId;
- return null;
+ return "Failed to find provider " + authority + " for user " + userId;
}
ProcessRecord r = null;
@@ -17540,12 +17550,15 @@
public List<ActivityManager.RunningServiceInfo> getServices(int maxNum,
int flags) {
enforceNotIsolatedCaller("getServices");
- synchronized (this) {
- final int callingUid = Binder.getCallingUid();
- final boolean allowed = isGetTasksAllowed("getServices", Binder.getCallingPid(),
- callingUid);
- return mServices.getRunningServiceInfoLocked(maxNum, flags, callingUid, allowed);
+ final int callingUid = Binder.getCallingUid();
+ final boolean canInteractAcrossUsers = (ActivityManager.checkUidPermission(
+ INTERACT_ACROSS_USERS_FULL, callingUid) == PERMISSION_GRANTED);
+ final boolean allowed = isGetTasksAllowed("getServices", Binder.getCallingPid(),
+ callingUid);
+ synchronized (this) {
+ return mServices.getRunningServiceInfoLocked(maxNum, flags, callingUid,
+ allowed, canInteractAcrossUsers);
}
}
@@ -18066,15 +18079,18 @@
} else if (rl.uid != callingUid) {
throw new IllegalArgumentException(
"Receiver requested to register for uid " + callingUid
- + " was previously registered for uid " + rl.uid);
+ + " was previously registered for uid " + rl.uid
+ + " callerPackage is " + callerPackage);
} else if (rl.pid != callingPid) {
throw new IllegalArgumentException(
"Receiver requested to register for pid " + callingPid
- + " was previously registered for pid " + rl.pid);
+ + " was previously registered for pid " + rl.pid
+ + " callerPackage is " + callerPackage);
} else if (rl.userId != userId) {
throw new IllegalArgumentException(
"Receiver requested to register for user " + userId
- + " was previously registered for user " + rl.userId);
+ + " was previously registered for user " + rl.userId
+ + " callerPackage is " + callerPackage);
}
BroadcastFilter bf = new BroadcastFilter(filter, rl, callerPackage,
permission, callingUid, userId);
@@ -19764,7 +19780,7 @@
mStackSupervisor.setDisplayOverrideConfiguration(mTempConfig, displayId);
final boolean isDensityChange = (changes & ActivityInfo.CONFIG_DENSITY) != 0;
- if (isDensityChange) {
+ if (isDensityChange && displayId == DEFAULT_DISPLAY) {
// Reset the unsupported display size dialog.
mUiHandler.sendEmptyMessage(SHOW_UNSUPPORTED_DISPLAY_SIZE_DIALOG_MSG);
@@ -23246,10 +23262,11 @@
}
void updateApplicationInfoLocked(@NonNull List<String> packagesToUpdate, int userId) {
+ final PackageManagerInternal packageManager = getPackageManagerInternalLocked();
final boolean updateFrameworkRes = packagesToUpdate.contains("android");
for (int i = mLruProcesses.size() - 1; i >= 0; i--) {
final ProcessRecord app = mLruProcesses.get(i);
- if (app.thread == null) {
+ if (app.thread == null || app.pid == Process.myPid()) {
continue;
}
@@ -23262,7 +23279,7 @@
final String packageName = app.pkgList.keyAt(j);
if (updateFrameworkRes || packagesToUpdate.contains(packageName)) {
try {
- final ApplicationInfo ai = mPackageManagerInt.getApplicationInfo(
+ final ApplicationInfo ai = packageManager.getApplicationInfo(
packageName, app.userId);
if (ai != null) {
app.thread.scheduleApplicationInfoChanged(ai);
diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java
index 6f89cf2..10055c8 100644
--- a/services/core/java/com/android/server/am/ActivityRecord.java
+++ b/services/core/java/com/android/server/am/ActivityRecord.java
@@ -802,10 +802,7 @@
// Remove the activity from the old task and add it to the new task
prevTask.removeActivity(this);
- // TODO(b/34179495): This should really be set to null in removeActivity() call above,
- // but really bad things that I can't track down right now happen when I do that.
- // So, setting it here now and will change later when there is time for investigation.
- task = null;
+
newTask.addActivityAtIndex(position, this);
}
@@ -880,8 +877,8 @@
/**
* @return Stack value from current task, null if there is no task.
*/
- ActivityStack getStack() {
- return task != null ? task.getStack() : null;
+ <T extends ActivityStack> T getStack() {
+ return task != null ? (T) task.getStack() : null;
}
boolean changeWindowTranslucency(boolean toOpaque) {
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index b948c15..7f7caff 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -84,7 +84,6 @@
import android.app.ActivityOptions;
import android.app.AppGlobals;
import android.app.IActivityController;
-import android.app.RemoteAction;
import android.app.ResultInfo;
import android.content.ComponentName;
import android.content.Intent;
@@ -135,7 +134,8 @@
/**
* State and management of a single stack of activities.
*/
-final class ActivityStack extends ConfigurationContainer implements StackWindowListener {
+class ActivityStack<T extends StackWindowController> extends ConfigurationContainer
+ implements StackWindowListener {
private static final String TAG = TAG_WITH_CLASS_NAME ? "ActivityStack" : TAG_AM;
private static final String TAG_ADD_REMOVE = TAG + POSTFIX_ADD_REMOVE;
@@ -247,7 +247,7 @@
final ActivityManagerService mService;
private final WindowManagerService mWindowManager;
- private StackWindowController mWindowContainerController;
+ T mWindowContainerController;
private final RecentTasks mRecentTasks;
/**
@@ -462,14 +462,18 @@
? new LaunchingTaskPositioner() : null;
final ActivityStackSupervisor.ActivityDisplay display = mActivityContainer.mActivityDisplay;
mTmpRect2.setEmpty();
- mWindowContainerController = new StackWindowController(mStackId, this,
- display.mDisplayId, onTop, mTmpRect2);
+ mWindowContainerController = createStackWindowController(display.mDisplayId, onTop,
+ mTmpRect2);
activityContainer.mStack = this;
mStackSupervisor.mActivityContainers.put(mStackId, activityContainer);
postAddToDisplay(display, mTmpRect2.isEmpty() ? null : mTmpRect2, onTop);
}
- StackWindowController getWindowContainerController() {
+ T createStackWindowController(int displayId, boolean onTop, Rect outBounds) {
+ return (T) new StackWindowController(mStackId, this, displayId, onTop, outBounds);
+ }
+
+ T getWindowContainerController() {
return mWindowContainerController;
}
@@ -540,18 +544,6 @@
mActivityContainer.mActivityDisplay.mDisplay.getSize(out);
}
- void animateResizePinnedStack(Rect bounds, int animationDuration) {
- mWindowContainerController.animateResizePinnedStack(bounds, animationDuration);
- }
-
- void setPictureInPictureAspectRatio(float aspectRatio) {
- mWindowContainerController.setPictureInPictureAspectRatio(aspectRatio);
- }
-
- void setPictureInPictureActions(List<RemoteAction> actions) {
- mWindowContainerController.setPictureInPictureActions(actions);
- }
-
void getStackDockedModeBounds(Rect outBounds, Rect outTempBounds, Rect outTempInsetBounds,
boolean ignoreVisibility) {
mWindowContainerController.getStackDockedModeBounds(outBounds, outTempBounds,
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index 7ceeff8..ab1559d 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -120,7 +120,6 @@
import android.content.pm.ResolveInfo;
import android.content.pm.UserInfo;
import android.content.res.Configuration;
-import android.graphics.Point;
import android.graphics.Rect;
import android.hardware.display.DisplayManager;
import android.hardware.display.DisplayManager.DisplayListener;
@@ -153,7 +152,6 @@
import android.service.voice.IVoiceInteractionSession;
import android.util.ArrayMap;
import android.util.ArraySet;
-import android.util.DisplayMetrics;
import android.util.EventLog;
import android.util.IntArray;
import android.util.Slog;
@@ -179,7 +177,6 @@
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
-import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.Set;
@@ -1198,13 +1195,11 @@
}
ResolveInfo resolveIntent(Intent intent, String resolvedType, int userId, int flags) {
- try {
- return AppGlobals.getPackageManager().resolveIntent(intent, resolvedType,
+ synchronized (mService) {
+ return mService.getPackageManagerInternalLocked().resolveIntent(intent, resolvedType,
PackageManager.MATCH_INSTANT | PackageManager.MATCH_DEFAULT_ONLY | flags
| ActivityManagerService.STOCK_PM_FLAGS, userId);
- } catch (RemoteException e) {
}
- return null;
}
ActivityInfo resolveActivity(Intent intent, String resolvedType, int startFlags,
@@ -2037,19 +2032,20 @@
|| mService.mSupportsFreeformWindowManagement;
}
- ActivityStack getStack(int stackId) {
+ protected <T extends ActivityStack> T getStack(int stackId) {
return getStack(stackId, !CREATE_IF_NEEDED, !ON_TOP);
}
- ActivityStack getStack(int stackId, boolean createStaticStackIfNeeded, boolean createOnTop) {
+ protected <T extends ActivityStack> T getStack(int stackId, boolean createStaticStackIfNeeded,
+ boolean createOnTop) {
final ActivityContainer activityContainer = mActivityContainers.get(stackId);
if (activityContainer != null) {
- return activityContainer.mStack;
+ return (T) activityContainer.mStack;
}
if (!createStaticStackIfNeeded || !StackId.isStaticStack(stackId)) {
return null;
}
- return createStackOnDisplay(stackId, DEFAULT_DISPLAY, createOnTop);
+ return (T) createStackOnDisplay(stackId, DEFAULT_DISPLAY, createOnTop);
}
/**
@@ -2856,7 +2852,7 @@
mWindowManager.deferSurfaceLayout();
// Need to make sure the pinned stack exist so we can resize it below...
- final ActivityStack stack = getStack(PINNED_STACK_ID, CREATE_IF_NEEDED, ON_TOP);
+ final PinnedActivityStack stack = getStack(PINNED_STACK_ID, CREATE_IF_NEEDED, ON_TOP);
try {
final TaskRecord task = r.task;
@@ -2906,7 +2902,7 @@
ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
resumeFocusedStackTopActivityLocked();
- stack.animateResizePinnedStack(bounds, -1);
+ stack.animateResizePinnedStack(bounds, -1 /* animationDuration */);
mService.mTaskChangeNotificationController.notifyActivityPinned();
}
@@ -4367,7 +4363,14 @@
synchronized (mService) {
mStackId = stackId;
mActivityDisplay = activityDisplay;
- new ActivityStack(this, mRecentTasks, onTop);
+ switch (mStackId) {
+ case PINNED_STACK_ID:
+ new PinnedActivityStack(this, mRecentTasks, onTop);
+ break;
+ default:
+ new ActivityStack(this, mRecentTasks, onTop);
+ break;
+ }
mIdString = "ActivtyContainer{" + mStackId + "}";
if (DEBUG_STACK) Slog.d(TAG_STACK, "Creating " + this);
}
@@ -4898,7 +4901,7 @@
setResizingDuringAnimation(task);
}
- mService.mActivityStarter.postStartActivityUncheckedProcessing(task.getTopActivity(),
+ mService.mActivityStarter.postStartActivityProcessing(task.getTopActivity(),
ActivityManager.START_TASK_TO_FRONT,
sourceRecord != null ? sourceRecord.task.getStackId() : INVALID_STACK_ID,
sourceRecord, task.getStack());
diff --git a/services/core/java/com/android/server/am/ActivityStarter.java b/services/core/java/com/android/server/am/ActivityStarter.java
index 7605a1e..d8c5533 100644
--- a/services/core/java/com/android/server/am/ActivityStarter.java
+++ b/services/core/java/com/android/server/am/ActivityStarter.java
@@ -17,6 +17,7 @@
package com.android.server.am;
import static android.app.Activity.RESULT_CANCELED;
+import static android.app.ActivityManager.START_CANCELED;
import static android.app.ActivityManager.START_CLASS_NOT_FOUND;
import static android.app.ActivityManager.START_DELIVERED_TO_TOP;
import static android.app.ActivityManager.START_FLAG_ONLY_IF_NEEDED;
@@ -82,23 +83,24 @@
import static com.android.server.am.ActivityStackSupervisor.TAG_TASKS;
import static com.android.server.am.EventLogTags.AM_NEW_INTENT;
+import android.annotation.NonNull;
import android.app.ActivityManager;
import android.app.ActivityOptions;
import android.app.AppGlobals;
import android.app.IActivityContainer;
import android.app.IApplicationThread;
-import android.app.KeyguardManager;
import android.app.PendingIntent;
import android.app.ProfilerInfo;
import android.app.WaitResult;
import android.content.ComponentName;
-import android.content.Context;
import android.content.IIntentSender;
import android.content.Intent;
import android.content.IntentSender;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
+import android.content.pm.AuxiliaryResolveInfo;
import android.content.pm.PackageManager;
+import android.content.pm.PackageManagerInternal;
import android.content.pm.ResolveInfo;
import android.content.pm.UserInfo;
import android.content.res.Configuration;
@@ -456,22 +458,9 @@
// Instead, launch the ephemeral installer. Once the installer is finished, it
// starts either the intent we resolved here [on install error] or the ephemeral
// app [on install success].
- if (rInfo != null && rInfo.ephemeralResponse != null) {
- final String packageName =
- rInfo.ephemeralResponse.resolveInfo.getPackageName();
- final String splitName = rInfo.ephemeralResponse.splitName;
- final boolean needsPhaseTwo = rInfo.ephemeralResponse.needsPhase2;
- final String token = rInfo.ephemeralResponse.token;
- final int versionCode = rInfo.ephemeralResponse.resolveInfo.getVersionCode();
- if (needsPhaseTwo) {
- // request phase two resolution
- mService.getPackageManagerInternalLocked().requestEphemeralResolutionPhaseTwo(
- rInfo.ephemeralResponse, ephemeralIntent, resolvedType, intent,
- callingPackage, userId);
- }
- intent = EphemeralResolver.buildEphemeralInstallerIntent(intent, ephemeralIntent,
- callingPackage, resolvedType, userId, packageName, splitName, versionCode,
- token, needsPhaseTwo);
+ if (rInfo != null && rInfo.auxiliaryInfo != null) {
+ intent = createLaunchIntent(rInfo.auxiliaryInfo, ephemeralIntent,
+ callingPackage, resolvedType, userId);
resolvedType = null;
callingUid = realCallingUid;
callingPid = realCallingPid;
@@ -519,18 +508,26 @@
doPendingActivityLaunchesLocked(false);
- try {
- mService.mWindowManager.deferSurfaceLayout();
- err = startActivityUnchecked(r, sourceRecord, voiceSession, voiceInteractor, startFlags,
- true, options, inTask);
- } finally {
- mService.mWindowManager.continueSurfaceLayout();
- }
- postStartActivityUncheckedProcessing(r, err, stack.mStackId, mSourceRecord, mTargetStack);
- return err;
+ return startActivity(r, sourceRecord, voiceSession, voiceInteractor, startFlags, true,
+ options, inTask);
}
- void postStartActivityUncheckedProcessing(
+ /** Creates a launch intent for the given auxiliary resolution data. */
+ private @NonNull Intent createLaunchIntent(@NonNull AuxiliaryResolveInfo auxiliaryResponse,
+ Intent originalIntent, String callingPackage,
+ String resolvedType, int userId) {
+ if (auxiliaryResponse.needsPhaseTwo) {
+ // request phase two resolution
+ mService.getPackageManagerInternalLocked().requestInstantAppResolutionPhaseTwo(
+ auxiliaryResponse, originalIntent, resolvedType, callingPackage, userId);
+ }
+ return EphemeralResolver.buildEphemeralInstallerIntent(originalIntent,
+ callingPackage, resolvedType, userId, auxiliaryResponse.packageName,
+ auxiliaryResponse.splitName, auxiliaryResponse.versionCode,
+ auxiliaryResponse.token, auxiliaryResponse.needsPhaseTwo);
+ }
+
+ void postStartActivityProcessing(
ActivityRecord r, int result, int prevFocusedStackId, ActivityRecord sourceRecord,
ActivityStack targetStack) {
@@ -932,6 +929,32 @@
}
}
+ private int startActivity(final ActivityRecord r, ActivityRecord sourceRecord,
+ IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
+ int startFlags, boolean doResume, ActivityOptions options, TaskRecord inTask) {
+ int result = START_CANCELED;
+ try {
+ mService.mWindowManager.deferSurfaceLayout();
+ result = startActivityUnchecked(r, sourceRecord, voiceSession, voiceInteractor,
+ startFlags,
+ doResume, options, inTask);
+ } finally {
+ // If we are not able to proceed, disassociate the activity from the task. Leaving an
+ // activity in an incomplete state can lead to issues, such as performing operations
+ // without a window container.
+ if (result != START_SUCCESS && mStartActivity.task != null) {
+ mStartActivity.task.removeActivity(mStartActivity);
+ }
+ mService.mWindowManager.continueSurfaceLayout();
+ }
+
+ postStartActivityProcessing(r, result, mSupervisor.mFocusedStack.mStackId,
+ mSourceRecord, mTargetStack);
+
+ return result;
+ }
+
+ // Note: This method should only be called from {@link startActivity}.
private int startActivityUnchecked(final ActivityRecord r, ActivityRecord sourceRecord,
IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
int startFlags, boolean doResume, ActivityOptions options, TaskRecord inTask) {
@@ -1838,11 +1861,8 @@
final PendingActivityLaunch pal = mPendingActivityLaunches.remove(0);
final boolean resume = doResume && mPendingActivityLaunches.isEmpty();
try {
- final int result = startActivityUnchecked(
- pal.r, pal.sourceRecord, null, null, pal.startFlags, resume, null, null);
- postStartActivityUncheckedProcessing(
- pal.r, result, mSupervisor.mFocusedStack.mStackId, mSourceRecord,
- mTargetStack);
+ startActivity(pal.r, pal.sourceRecord, null, null, pal.startFlags, resume, null,
+ null);
} catch (Exception e) {
Slog.e(TAG, "Exception during pending activity launch pal=" + pal, e);
pal.sendErrorResult(e.getMessage());
diff --git a/services/core/java/com/android/server/am/PinnedActivityStack.java b/services/core/java/com/android/server/am/PinnedActivityStack.java
new file mode 100644
index 0000000..aa7ab15
--- /dev/null
+++ b/services/core/java/com/android/server/am/PinnedActivityStack.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.am;
+
+import android.app.RemoteAction;
+import android.graphics.Rect;
+
+import com.android.server.am.ActivityStackSupervisor.ActivityContainer;
+import com.android.server.wm.PinnedStackWindowController;
+import com.android.server.wm.StackWindowController;
+
+import java.util.List;
+
+/**
+ * State and management of the pinned stack of activities.
+ */
+class PinnedActivityStack extends ActivityStack<PinnedStackWindowController> {
+
+ PinnedActivityStack(ActivityContainer activityContainer,
+ RecentTasks recentTasks, boolean onTop) {
+ super(activityContainer, recentTasks, onTop);
+ }
+
+ @Override
+ PinnedStackWindowController createStackWindowController(int displayId, boolean onTop,
+ Rect outBounds) {
+ return new PinnedStackWindowController(mStackId, this, displayId, onTop, outBounds);
+ }
+
+ void animateResizePinnedStack(Rect bounds, int animationDuration) {
+ getWindowContainerController().animateResizePinnedStack(bounds, animationDuration);
+ }
+
+ void setPictureInPictureAspectRatio(float aspectRatio) {
+ getWindowContainerController().setPictureInPictureAspectRatio(aspectRatio);
+ }
+
+ void setPictureInPictureActions(List<RemoteAction> actions) {
+ getWindowContainerController().setPictureInPictureActions(actions);
+ }
+}
diff --git a/services/core/java/com/android/server/am/PreBootBroadcaster.java b/services/core/java/com/android/server/am/PreBootBroadcaster.java
index f4f6b66..e0d3abd 100644
--- a/services/core/java/com/android/server/am/PreBootBroadcaster.java
+++ b/services/core/java/com/android/server/am/PreBootBroadcaster.java
@@ -35,6 +35,7 @@
import android.util.Slog;
import com.android.internal.R;
+import com.android.internal.notification.SystemNotificationChannels;
import com.android.internal.util.ProgressReporter;
import com.android.server.UiThread;
@@ -144,13 +145,13 @@
contentIntent = null;
}
- final Notification notif = new Notification.Builder(mService.mContext)
+ final Notification notif =
+ new Notification.Builder(mService.mContext,
+ SystemNotificationChannels.UPDATES)
.setSmallIcon(R.drawable.stat_sys_adb)
.setWhen(0)
.setOngoing(true)
.setTicker(title)
- .setDefaults(0)
- .setPriority(Notification.PRIORITY_MAX)
.setColor(context.getColor(
com.android.internal.R.color.system_notification_accent_color))
.setContentTitle(title)
diff --git a/services/core/java/com/android/server/am/ServiceRecord.java b/services/core/java/com/android/server/am/ServiceRecord.java
index 82b00da..dfbe59f 100644
--- a/services/core/java/com/android/server/am/ServiceRecord.java
+++ b/services/core/java/com/android/server/am/ServiceRecord.java
@@ -115,7 +115,7 @@
long destroyTime; // time at which destory was initiated.
String stringName; // caching of toString
-
+
private int lastStartId; // identifier of most recent start request.
static class StartItem {
@@ -203,7 +203,7 @@
}
}
}
-
+
void dump(PrintWriter pw, String prefix) {
pw.print(prefix); pw.print("intent={");
pw.print(intent.getIntent().toShortString(false, true, false, true));
@@ -413,7 +413,7 @@
restartDelay = 0;
restartTime = 0;
}
-
+
public StartItem findDeliveredStart(int id, boolean remove) {
final int N = deliveredStarts.size();
for (int i=0; i<N; i++) {
@@ -423,10 +423,10 @@
return si;
}
}
-
+
return null;
}
-
+
public int getLastStartId() {
return lastStartId;
}
@@ -478,7 +478,8 @@
ctx = ams.mContext.createPackageContextAsUser(
appInfo.packageName, 0, new UserHandle(userId));
- Notification.Builder notiBuilder = new Notification.Builder(ctx);
+ Notification.Builder notiBuilder = new Notification.Builder(ctx,
+ localForegroundNoti.getChannel());
// it's ugly, but it clearly identifies the app
notiBuilder.setSmallIcon(appInfo.icon);
@@ -486,9 +487,6 @@
// mark as foreground
notiBuilder.setFlag(Notification.FLAG_FOREGROUND_SERVICE, true);
- // we are doing the app a kindness here
- notiBuilder.setPriority(Notification.PRIORITY_MIN);
-
Intent runningIntent = new Intent(
Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
runningIntent.setData(Uri.fromParts("package",
@@ -541,7 +539,7 @@
});
}
}
-
+
public void cancelNotification() {
// Do asynchronous communication with notification manager to
// avoid deadlocks.
@@ -588,7 +586,7 @@
}
});
}
-
+
public void clearDeliveredStartsLocked() {
for (int i=deliveredStarts.size()-1; i>=0; i--) {
deliveredStarts.get(i).removeUriPermissionsLocked();
diff --git a/services/core/java/com/android/server/am/TaskRecord.java b/services/core/java/com/android/server/am/TaskRecord.java
index f8645d6..b051304 100644
--- a/services/core/java/com/android/server/am/TaskRecord.java
+++ b/services/core/java/com/android/server/am/TaskRecord.java
@@ -1083,6 +1083,13 @@
/** @return true if this was the last activity in the task */
boolean removeActivity(ActivityRecord r) {
+ if (r.task != this) {
+ throw new IllegalArgumentException(
+ "Activity=" + r + " does not belong to task=" + this);
+ }
+
+ r.task = null;
+
if (mActivities.remove(r) && r.fullscreen) {
// Was previously in list.
numFullscreen--;
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 5b3495f..79b99a3 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -6518,35 +6518,22 @@
return mRecordMonitor.getActiveRecordingConfigurations();
}
- public void disableRingtoneSync() {
+ public void disableRingtoneSync(final int userId) {
final int callingUserId = UserHandle.getCallingUserId();
+ if (callingUserId != userId) {
+ mContext.enforceCallingOrSelfPermission(Manifest.permission.INTERACT_ACROSS_USERS_FULL,
+ "disable sound settings syncing for another profile");
+ }
final long token = Binder.clearCallingIdentity();
try {
- UserManager userManager = UserManager.get(mContext);
-
- // Disable the sync setting
- Settings.Secure.putIntForUser(mContentResolver,
- Settings.Secure.SYNC_PARENT_SOUNDS, 0 /* false */, callingUserId);
-
- UserInfo parentInfo = userManager.getProfileParent(callingUserId);
- if (parentInfo != null && parentInfo.id != callingUserId) {
- // This is a managed profile, so we clone the ringtones from the parent profile
- cloneRingtoneSetting(callingUserId, parentInfo.id, Settings.System.RINGTONE);
- cloneRingtoneSetting(callingUserId, parentInfo.id,
- Settings.System.NOTIFICATION_SOUND);
- cloneRingtoneSetting(callingUserId, parentInfo.id, Settings.System.ALARM_ALERT);
- }
+ // Disable the sync setting so the profile uses its own sound settings.
+ Settings.Secure.putIntForUser(mContentResolver, Settings.Secure.SYNC_PARENT_SOUNDS,
+ 0 /* false */, userId);
} finally {
Binder.restoreCallingIdentity(token);
}
}
- private void cloneRingtoneSetting(int userId, int parentId, String ringtoneSetting) {
- String parentSetting = Settings.System.getStringForUser(mContentResolver, ringtoneSetting,
- parentId);
- Settings.System.putStringForUser(mContentResolver, ringtoneSetting, parentSetting, userId);
- }
-
//======================
// Audio playback notification
//======================
diff --git a/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java b/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java
index 1f64b65..4404dcf 100644
--- a/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java
+++ b/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java
@@ -47,17 +47,40 @@
implements AudioPlaybackConfiguration.PlayerDeathMonitor, PlayerFocusEnforcer {
public final static String TAG = "AudioService.PlaybackActivityMonitor";
+
private final static boolean DEBUG = false;
private final static int VOLUME_SHAPER_SYSTEM_DUCK_ID = 1;
- private ArrayList<PlayMonitorClient> mClients = new ArrayList<PlayMonitorClient>();
+ private final VolumeShaper.Configuration DUCK_VSHAPE =
+ new VolumeShaper.Configuration.Builder()
+ .setId(VOLUME_SHAPER_SYSTEM_DUCK_ID)
+ .setCurve(new float[] { 0.f, 1.f } /* times */,
+ new float[] { 1.f, 0.2f } /* volumes */)
+ .setOptionFlags(VolumeShaper.Configuration.OPTION_FLAG_CLOCK_TIME)
+ .setDurationMs(MediaFocusControl.getFocusRampTimeMs(
+ AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK,
+ new AudioAttributes.Builder().setUsage(AudioAttributes.USAGE_NOTIFICATION)
+ .build()))
+ .build();
+ private final VolumeShaper.Configuration DUCK_ID =
+ new VolumeShaper.Configuration(VOLUME_SHAPER_SYSTEM_DUCK_ID);
+ private final VolumeShaper.Operation PLAY_CREATE_IF_NEEDED =
+ new VolumeShaper.Operation.Builder(VolumeShaper.Operation.PLAY)
+ .createIfNeeded()
+ .build();
+ private final VolumeShaper.Operation TERMINATE =
+ new VolumeShaper.Operation.Builder()
+ .terminate()
+ .build();
+
+ private final ArrayList<PlayMonitorClient> mClients = new ArrayList<PlayMonitorClient>();
// a public client is one that needs an anonymized version of the playback configurations, we
// keep track of whether there is at least one to know when we need to create the list of
// playback configurations that do not contain uid/pid/package name information.
private boolean mHasPublicClients = false;
private final Object mPlayerLock = new Object();
- private HashMap<Integer, AudioPlaybackConfiguration> mPlayers =
+ private final HashMap<Integer, AudioPlaybackConfiguration> mPlayers =
new HashMap<Integer, AudioPlaybackConfiguration>();
PlaybackActivityMonitor() {
@@ -129,12 +152,12 @@
synchronized(mPlayerLock) {
final AudioPlaybackConfiguration apc = mPlayers.get(new Integer(piid));
if (checkConfigurationCaller(piid, apc, binderUid)) {
+ try {
+ apc.getPlayerProxy().applyVolumeShaper(
+ DUCK_ID,
+ TERMINATE);
+ } catch (Exception e) { /* silent failure, happens happens with binder failure */ }
mPlayers.remove(new Integer(piid));
- final VolumeShaper vs = mDuckVolumeShapers.get(new Integer(piid));
- if (vs != null) {
- vs.release();
- mDuckVolumeShapers.remove(new Integer(piid));
- }
} else {
Log.e(TAG, "Error releasing player " + piid);
}
@@ -251,20 +274,6 @@
private final ArrayList<Integer> mDuckedPlayers = new ArrayList<Integer>();
private final ArrayList<Integer> mMutedPlayers = new ArrayList<Integer>();
- private final VolumeShaper.Configuration DUCK_VSHAPE =
- new VolumeShaper.Configuration.Builder()
- .setId(VOLUME_SHAPER_SYSTEM_DUCK_ID)
- .setCurve(new float[] { 0.f, 1.f } /* times */,
- new float[] { 1.f, 0.2f } /* volumes */)
- .setDurationMs(MediaFocusControl.getFocusRampTimeMs(
- AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK,
- new AudioAttributes.Builder().setUsage(AudioAttributes.USAGE_NOTIFICATION)
- .build()))
- .build();
-
- private final HashMap<Integer, VolumeShaper> mDuckVolumeShapers =
- new HashMap<Integer, VolumeShaper>();
-
@Override
public boolean duckPlayers(FocusRequester winner, FocusRequester loser) {
if (DEBUG) {
@@ -301,17 +310,9 @@
} else {
try {
if (DEBUG) { Log.v(TAG, "ducking player " + piid); }
- final VolumeShaper ducker;
- if (mDuckVolumeShapers.containsKey(new Integer(piid))) {
- ducker = mDuckVolumeShapers.get(new Integer(piid));
- } else {
- ducker = new VolumeShaper(
- DUCK_VSHAPE,
- apc.getPlayerProxy(),
- true /* keepReference */);
- mDuckVolumeShapers.put(new Integer(piid), ducker);
- }
- ducker.apply(VolumeShaper.Operation.PLAY); // duck
+ apc.getPlayerProxy().applyVolumeShaper(
+ DUCK_VSHAPE,
+ PLAY_CREATE_IF_NEEDED);
mDuckedPlayers.add(piid);
} catch (Exception e) {
Log.e(TAG, "Error ducking player " + piid, e);
@@ -340,10 +341,9 @@
try {
if (DEBUG) { Log.v(TAG, "unducking player" + piid); }
mDuckedPlayers.remove(new Integer(piid));
- if (mDuckVolumeShapers.containsKey(new Integer(piid))) {
- final VolumeShaper ducker = mDuckVolumeShapers.get(new Integer(piid));
- ducker.apply(VolumeShaper.Operation.REVERSE); // unduck
- }
+ apc.getPlayerProxy().applyVolumeShaper(
+ DUCK_ID,
+ VolumeShaper.Operation.REVERSE);
} catch (Exception e) {
Log.e(TAG, "Error unducking player " + piid, e);
}
diff --git a/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java b/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java
index 68fe505..83751a9 100644
--- a/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java
+++ b/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java
@@ -32,6 +32,7 @@
import com.android.internal.R;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+import com.android.internal.notification.SystemNotificationChannels;
import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
@@ -187,7 +188,9 @@
return;
}
- Notification.Builder builder = new Notification.Builder(mContext)
+ final String channelId = highPriority ? SystemNotificationChannels.NETWORK_ALERTS :
+ SystemNotificationChannels.NETWORK_STATUS;
+ Notification.Builder builder = new Notification.Builder(mContext, channelId)
.setWhen(System.currentTimeMillis())
.setShowWhen(notifyType == NotificationType.NETWORK_SWITCH)
.setSmallIcon(icon)
@@ -198,10 +201,6 @@
.setContentTitle(title)
.setContentIntent(intent)
.setLocalOnly(true)
- .setPriority(highPriority ?
- Notification.PRIORITY_HIGH :
- Notification.PRIORITY_DEFAULT)
- .setDefaults(highPriority ? Notification.DEFAULT_ALL : 0)
.setOnlyAlertOnce(true);
if (notifyType == NotificationType.NETWORK_SWITCH) {
diff --git a/services/core/java/com/android/server/connectivity/Tethering.java b/services/core/java/com/android/server/connectivity/Tethering.java
index 6c608a2..39e3758 100644
--- a/services/core/java/com/android/server/connectivity/Tethering.java
+++ b/services/core/java/com/android/server/connectivity/Tethering.java
@@ -66,6 +66,7 @@
import android.util.SparseArray;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.notification.SystemNotificationChannels;
import com.android.internal.telephony.IccCardConstants;
import com.android.internal.telephony.TelephonyIntents;
import com.android.internal.util.IndentingPrintWriter;
@@ -668,7 +669,8 @@
tethered_notification_message);
if (mTetheredNotificationBuilder == null) {
- mTetheredNotificationBuilder = new Notification.Builder(mContext);
+ mTetheredNotificationBuilder =
+ new Notification.Builder(mContext, SystemNotificationChannels.NETWORK_STATUS);
mTetheredNotificationBuilder.setWhen(0)
.setOngoing(true)
.setColor(mContext.getColor(
@@ -950,6 +952,8 @@
// Events from NetworkCallbacks that we process on the master state
// machine thread on behalf of the UpstreamNetworkMonitor.
static final int EVENT_UPSTREAM_CALLBACK = BASE_MASTER + 5;
+ // we treated the error and want now to clear it
+ static final int CMD_CLEAR_ERROR = BASE_MASTER + 6;
private State mInitialState;
private State mTetherModeAliveState;
@@ -1491,6 +1495,10 @@
TetherInterfaceStateMachine who = (TetherInterfaceStateMachine)message.obj;
who.sendMessage(mErrorNotification);
break;
+ case CMD_CLEAR_ERROR:
+ mErrorNotification = ConnectivityManager.TETHER_ERROR_NO_ERROR;
+ transitionTo(mInitialState);
+ break;
default:
retValue = false;
}
@@ -1635,6 +1643,12 @@
// Not really very much we can do here.
}
+ // If TetherMasterSM is in ErrorState, TetherMasterSM stays there.
+ // Thus we give a chance for TetherMasterSM to recover to InitialState
+ // by sending CMD_CLEAR_ERROR
+ if (error == ConnectivityManager.TETHER_ERROR_MASTER_ERROR) {
+ mTetherMasterSM.sendMessage(TetherMasterSM.CMD_CLEAR_ERROR, who);
+ }
switch (state) {
case IControlsTethering.STATE_UNAVAILABLE:
case IControlsTethering.STATE_AVAILABLE:
diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java
index b963555..9fc2fc7 100644
--- a/services/core/java/com/android/server/connectivity/Vpn.java
+++ b/services/core/java/com/android/server/connectivity/Vpn.java
@@ -85,6 +85,7 @@
import com.android.internal.net.VpnConfig;
import com.android.internal.net.VpnInfo;
import com.android.internal.net.VpnProfile;
+import com.android.internal.notification.SystemNotificationChannels;
import com.android.server.DeviceIdleController;
import com.android.server.LocalServices;
import com.android.server.net.BaseNetworkObserver;
@@ -1293,17 +1294,16 @@
mContext, /* request */ 0, intent,
PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_UPDATE_CURRENT,
null, user);
- final Notification.Builder builder = new Notification.Builder(mContext)
- .setDefaults(0)
- .setSmallIcon(R.drawable.vpn_connected)
- .setContentTitle(mContext.getString(R.string.vpn_lockdown_disconnected))
- .setContentText(mContext.getString(R.string.vpn_lockdown_config))
- .setContentIntent(configIntent)
- .setCategory(Notification.CATEGORY_SYSTEM)
- .setPriority(Notification.PRIORITY_LOW)
- .setVisibility(Notification.VISIBILITY_PUBLIC)
- .setOngoing(true)
- .setColor(mContext.getColor(R.color.system_notification_accent_color));
+ final Notification.Builder builder =
+ new Notification.Builder(mContext, SystemNotificationChannels.VPN)
+ .setSmallIcon(R.drawable.vpn_connected)
+ .setContentTitle(mContext.getString(R.string.vpn_lockdown_disconnected))
+ .setContentText(mContext.getString(R.string.vpn_lockdown_config))
+ .setContentIntent(configIntent)
+ .setCategory(Notification.CATEGORY_SYSTEM)
+ .setVisibility(Notification.VISIBILITY_PUBLIC)
+ .setOngoing(true)
+ .setColor(mContext.getColor(R.color.system_notification_accent_color));
notificationManager.notifyAsUser(TAG, 0, builder.build(), user);
} finally {
Binder.restoreCallingIdentity(token);
diff --git a/services/core/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachine.java b/services/core/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachine.java
index 5e51579..710ab33 100644
--- a/services/core/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachine.java
+++ b/services/core/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachine.java
@@ -167,7 +167,8 @@
private void maybeLogMessage(State state, int what) {
if (DBG) {
Log.d(TAG, state.getName() + " got " +
- sMagicDecoderRing.get(what, Integer.toString(what)));
+ sMagicDecoderRing.get(what, Integer.toString(what)) + ", Iface = " +
+ mIfaceName);
}
}
diff --git a/services/core/java/com/android/server/connectivity/tethering/UpstreamNetworkMonitor.java b/services/core/java/com/android/server/connectivity/tethering/UpstreamNetworkMonitor.java
index 63024db..6106093 100644
--- a/services/core/java/com/android/server/connectivity/tethering/UpstreamNetworkMonitor.java
+++ b/services/core/java/com/android/server/connectivity/tethering/UpstreamNetworkMonitor.java
@@ -20,6 +20,8 @@
import static android.net.ConnectivityManager.TYPE_MOBILE_HIPRI;
import android.content.Context;
+import android.os.Handler;
+import android.os.Looper;
import android.net.ConnectivityManager;
import android.net.ConnectivityManager.NetworkCallback;
import android.net.LinkProperties;
@@ -72,6 +74,7 @@
private final Context mContext;
private final StateMachine mTarget;
+ private final Handler mHandler;
private final int mWhat;
private final HashMap<Network, NetworkState> mNetworkMap = new HashMap<>();
private ConnectivityManager mCM;
@@ -84,6 +87,7 @@
public UpstreamNetworkMonitor(Context ctx, StateMachine tgt, int what) {
mContext = ctx;
mTarget = tgt;
+ mHandler = mTarget.getHandler();
mWhat = what;
}
@@ -99,10 +103,10 @@
final NetworkRequest listenAllRequest = new NetworkRequest.Builder()
.clearCapabilities().build();
mListenAllCallback = new UpstreamNetworkCallback(CALLBACK_LISTEN_ALL);
- cm().registerNetworkCallback(listenAllRequest, mListenAllCallback);
+ cm().registerNetworkCallback(listenAllRequest, mListenAllCallback, mHandler);
mDefaultNetworkCallback = new UpstreamNetworkCallback(CALLBACK_TRACK_DEFAULT);
- cm().registerDefaultNetworkCallback(mDefaultNetworkCallback);
+ cm().registerDefaultNetworkCallback(mDefaultNetworkCallback, mHandler);
}
public void stop() {
@@ -154,7 +158,7 @@
// Additionally, we log a message to aid in any subsequent debugging.
Log.d(TAG, "requesting mobile upstream network: " + mobileUpstreamRequest);
- cm().requestNetwork(mobileUpstreamRequest, mMobileNetworkCallback, 0, legacyType);
+ cm().requestNetwork(mobileUpstreamRequest, mMobileNetworkCallback, 0, legacyType, mHandler);
}
public void releaseMobileNetworkRequest() {
@@ -185,11 +189,13 @@
case CALLBACK_TRACK_DEFAULT:
if (mDefaultNetworkCallback == null) {
// The callback was unregistered in the interval between
- // ConnectivityService calling onAvailable() and our
- // handling of it here on the mTarget.getHandler() thread.
+ // ConnectivityService enqueueing onAvailable() and our
+ // handling of it here on the mHandler thread.
+ //
// Clean-up of this network entry is deferred to the
// handling of onLost() by other callbacks.
- // TODO: change to Log.wtf() after oag/331764 is merged.
+ //
+ // These request*() calls can be deleted post oag/339444.
return;
}
@@ -200,11 +206,13 @@
case CALLBACK_MOBILE_REQUEST:
if (mMobileNetworkCallback == null) {
// The callback was unregistered in the interval between
- // ConnectivityService calling onAvailable() and our
- // handling of it here on the mTarget.getHandler() thread.
+ // ConnectivityService enqueueing onAvailable() and our
+ // handling of it here on the mHandler thread.
+ //
// Clean-up of this network entry is deferred to the
// handling of onLost() by other callbacks.
- // TODO: change to Log.wtf() after oag/331764 is merged.
+ //
+ // These request*() calls can be deleted post oag/339444.
return;
}
@@ -312,8 +320,9 @@
}
/**
- * A NetworkCallback class that relays information of interest to the
- * tethering master state machine thread for subsequent processing.
+ * A NetworkCallback class that handles information of interest directly
+ * in the thread on which it is invoked. To avoid locking, this MUST be
+ * run on the same thread as the target state machine's handler.
*/
private class UpstreamNetworkCallback extends NetworkCallback {
private final int mCallbackType;
@@ -324,22 +333,35 @@
@Override
public void onAvailable(Network network) {
- mTarget.getHandler().post(() -> handleAvailable(mCallbackType, network));
+ checkExpectedThread();
+ handleAvailable(mCallbackType, network);
}
@Override
public void onCapabilitiesChanged(Network network, NetworkCapabilities newNc) {
- mTarget.getHandler().post(() -> handleNetCap(network, newNc));
+ checkExpectedThread();
+ handleNetCap(network, newNc);
}
@Override
public void onLinkPropertiesChanged(Network network, LinkProperties newLp) {
- mTarget.getHandler().post(() -> handleLinkProp(network, newLp));
+ checkExpectedThread();
+ handleLinkProp(network, newLp);
}
+ // TODO: Handle onNetworkSuspended();
+ // TODO: Handle onNetworkResumed();
+
@Override
public void onLost(Network network) {
- mTarget.getHandler().post(() -> handleLost(mCallbackType, network));
+ checkExpectedThread();
+ handleLost(mCallbackType, network);
+ }
+
+ private void checkExpectedThread() {
+ if (Looper.myLooper() != mHandler.getLooper()) {
+ Log.wtf(TAG, "Handling callback in unexpected thread.");
+ }
}
}
diff --git a/services/core/java/com/android/server/content/ContentService.java b/services/core/java/com/android/server/content/ContentService.java
index 886c97f..4b34eba56 100644
--- a/services/core/java/com/android/server/content/ContentService.java
+++ b/services/core/java/com/android/server/content/ContentService.java
@@ -43,6 +43,7 @@
import android.database.sqlite.SQLiteException;
import android.net.Uri;
import android.os.Binder;
+import android.os.Build;
import android.os.Bundle;
import android.os.FactoryTest;
import android.os.IBinder;
@@ -287,7 +288,7 @@
*/
@Override
public void registerContentObserver(Uri uri, boolean notifyForDescendants,
- IContentObserver observer, int userHandle) {
+ IContentObserver observer, int userHandle, int targetSdkVersion) {
if (observer == null || uri == null) {
throw new IllegalArgumentException("You must pass a valid uri and observer");
}
@@ -301,8 +302,17 @@
final String msg = LocalServices.getService(ActivityManagerInternal.class)
.checkContentProviderAccess(uri.getAuthority(), userHandle);
if (msg != null) {
- Log.w(TAG, "Ignoring content changes for " + uri + " from " + uid + ": " + msg);
- return;
+ if (targetSdkVersion >= Build.VERSION_CODES.O) {
+ throw new SecurityException(msg);
+ } else {
+ if (msg.startsWith("Failed to find provider")) {
+ // Sigh, we need to quietly let apps targeting older API
+ // levels notify on non-existent providers.
+ } else {
+ Log.w(TAG, "Ignoring content changes for " + uri + " from " + uid + ": " + msg);
+ return;
+ }
+ }
}
synchronized (mRootNode) {
@@ -316,7 +326,7 @@
public void registerContentObserver(Uri uri, boolean notifyForDescendants,
IContentObserver observer) {
registerContentObserver(uri, notifyForDescendants, observer,
- UserHandle.getCallingUserId());
+ UserHandle.getCallingUserId(), Build.VERSION_CODES.CUR_DEVELOPMENT);
}
@Override
@@ -340,8 +350,8 @@
*/
@Override
public void notifyChange(Uri uri, IContentObserver observer,
- boolean observerWantsSelfNotifications, int flags,
- int userHandle) {
+ boolean observerWantsSelfNotifications, int flags, int userHandle,
+ int targetSdkVersion) {
if (DEBUG) Slog.d(TAG, "Notifying update of " + uri + " for user " + userHandle
+ " from observer " + observer + ", flags " + Integer.toHexString(flags));
@@ -359,8 +369,17 @@
final String msg = LocalServices.getService(ActivityManagerInternal.class)
.checkContentProviderAccess(uri.getAuthority(), userHandle);
if (msg != null) {
- Log.w(TAG, "Ignoring notify for " + uri + " from " + uid + ": " + msg);
- return;
+ if (targetSdkVersion >= Build.VERSION_CODES.O) {
+ throw new SecurityException(msg);
+ } else {
+ if (msg.startsWith("Failed to find provider")) {
+ // Sigh, we need to quietly let apps targeting older API
+ // levels notify on non-existent providers.
+ } else {
+ Log.w(TAG, "Ignoring notify for " + uri + " from " + uid + ": " + msg);
+ return;
+ }
+ }
}
// This makes it so that future permission checks will be in the context of this
@@ -427,7 +446,7 @@
boolean observerWantsSelfNotifications, boolean syncToNetwork) {
notifyChange(uri, observer, observerWantsSelfNotifications,
syncToNetwork ? ContentResolver.NOTIFY_SYNC_TO_NETWORK : 0,
- UserHandle.getCallingUserId());
+ UserHandle.getCallingUserId(), Build.VERSION_CODES.CUR_DEVELOPMENT);
}
/**
diff --git a/services/core/java/com/android/server/content/SyncManager.java b/services/core/java/com/android/server/content/SyncManager.java
index 5b539ff..bbad493 100644
--- a/services/core/java/com/android/server/content/SyncManager.java
+++ b/services/core/java/com/android/server/content/SyncManager.java
@@ -81,6 +81,7 @@
import android.util.Pair;
import android.util.Slog;
+import com.android.internal.notification.SystemNotificationChannels;
import com.android.internal.util.ArrayUtils;
import com.android.server.LocalServices;
import com.android.server.job.JobSchedulerInternal;
@@ -3250,7 +3251,8 @@
R.string.contentServiceTooManyDeletesNotificationDesc);
Context contextForUser = getContextForUser(user);
- Notification notification = new Notification.Builder(contextForUser)
+ Notification notification =
+ new Notification.Builder(contextForUser, SystemNotificationChannels.ACCOUNT)
.setSmallIcon(R.drawable.stat_notify_sync_error)
.setTicker(mContext.getString(R.string.contentServiceSync))
.setWhen(System.currentTimeMillis())
@@ -3460,4 +3462,4 @@
return mContext;
}
}
-}
\ No newline at end of file
+}
diff --git a/services/core/java/com/android/server/display/VirtualDisplayAdapter.java b/services/core/java/com/android/server/display/VirtualDisplayAdapter.java
index 74e025d..5149933 100644
--- a/services/core/java/com/android/server/display/VirtualDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/VirtualDisplayAdapter.java
@@ -149,13 +149,7 @@
}
private void handleBinderDiedLocked(IBinder appToken) {
- VirtualDisplayDevice device = mVirtualDisplayDevices.remove(appToken);
- if (device != null) {
- Slog.i(TAG, "Virtual display device released because application token died: "
- + device.mOwnerPackageName);
- device.destroyLocked(false);
- sendDisplayDeviceEventLocked(device, DISPLAY_DEVICE_EVENT_REMOVED);
- }
+ mVirtualDisplayDevices.remove(appToken);
}
private void handleMediaProjectionStoppedLocked(IBinder appToken) {
@@ -216,6 +210,10 @@
public void binderDied() {
synchronized (getSyncRoot()) {
handleBinderDiedLocked(mAppToken);
+ Slog.i(TAG, "Virtual display device released because application token died: "
+ + mOwnerPackageName);
+ destroyLocked(false);
+ sendDisplayDeviceEventLocked(this, DISPLAY_DEVICE_EVENT_REMOVED);
}
}
diff --git a/services/core/java/com/android/server/fingerprint/ClientMonitor.java b/services/core/java/com/android/server/fingerprint/ClientMonitor.java
index 5a1e445..43bb21d 100644
--- a/services/core/java/com/android/server/fingerprint/ClientMonitor.java
+++ b/services/core/java/com/android/server/fingerprint/ClientMonitor.java
@@ -68,7 +68,9 @@
mIsRestricted = restricted;
mOwner = owner;
try {
- token.linkToDeath(this, 0);
+ if (token != null) {
+ token.linkToDeath(this, 0);
+ }
} catch (RemoteException e) {
Slog.w(TAG, "caught remote exception in linkToDeath: ", e);
}
diff --git a/services/core/java/com/android/server/fingerprint/FingerprintService.java b/services/core/java/com/android/server/fingerprint/FingerprintService.java
index e83b228..0f29942 100644
--- a/services/core/java/com/android/server/fingerprint/FingerprintService.java
+++ b/services/core/java/com/android/server/fingerprint/FingerprintService.java
@@ -1180,7 +1180,7 @@
// Statistics about secure fingerprint transactions (e.g. to unlock password
// storage, make secure purchases, etc.)
- final PerformanceStats crypto = mPerformanceMap.get(userId);
+ final PerformanceStats crypto = mCryptoPerformanceMap.get(userId);
if (crypto != null) {
final long countsToken = proto.start(FingerprintUserStatsProto.CRYPTO);
proto.write(FingerprintActionStatsProto.ACCEPT, crypto.accept);
diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java
index 3793b91..297d5bd 100644
--- a/services/core/java/com/android/server/input/InputManagerService.java
+++ b/services/core/java/com/android/server/input/InputManagerService.java
@@ -23,6 +23,7 @@
import android.util.Log;
import android.view.Display;
import com.android.internal.inputmethod.InputMethodSubtypeHandle;
+import com.android.internal.notification.SystemNotificationChannels;
import com.android.internal.os.SomeArgs;
import com.android.internal.R;
import com.android.internal.util.Preconditions;
@@ -973,17 +974,17 @@
intent, 0, null, UserHandle.CURRENT);
Resources r = mContext.getResources();
- Notification notification = new Notification.Builder(mContext)
- .setContentTitle(r.getString(
- R.string.select_keyboard_layout_notification_title))
- .setContentText(r.getString(
- R.string.select_keyboard_layout_notification_message))
- .setContentIntent(keyboardLayoutIntent)
- .setSmallIcon(R.drawable.ic_settings_language)
- .setPriority(Notification.PRIORITY_LOW)
- .setColor(mContext.getColor(
- com.android.internal.R.color.system_notification_accent_color))
- .build();
+ Notification notification =
+ new Notification.Builder(mContext, SystemNotificationChannels.PHYSICAL_KEYBOARD)
+ .setContentTitle(r.getString(
+ R.string.select_keyboard_layout_notification_title))
+ .setContentText(r.getString(
+ R.string.select_keyboard_layout_notification_message))
+ .setContentIntent(keyboardLayoutIntent)
+ .setSmallIcon(R.drawable.ic_settings_language)
+ .setColor(mContext.getColor(
+ com.android.internal.R.color.system_notification_accent_color))
+ .build();
mNotificationManager.notifyAsUser(null,
R.string.select_keyboard_layout_notification_title,
notification, UserHandle.ALL);
diff --git a/services/core/java/com/android/server/job/JobPackageTracker.java b/services/core/java/com/android/server/job/JobPackageTracker.java
index 82e2eb4..0a6d8a4 100644
--- a/services/core/java/com/android/server/job/JobPackageTracker.java
+++ b/services/core/java/com/android/server/job/JobPackageTracker.java
@@ -437,7 +437,7 @@
for (int i=0; i<size; i++) {
final int index = mEventIndices.indexOf(i);
final int uid = mEventUids[index];
- if (filterUid != -1 && filterUid != UserHandle.getAppId(filterUid)) {
+ if (filterUid != -1 && filterUid != UserHandle.getAppId(uid)) {
continue;
}
final int cmd = mEventCmds[index];
diff --git a/services/core/java/com/android/server/job/JobSchedulerService.java b/services/core/java/com/android/server/job/JobSchedulerService.java
index a748013..c973911 100644
--- a/services/core/java/com/android/server/job/JobSchedulerService.java
+++ b/services/core/java/com/android/server/job/JobSchedulerService.java
@@ -131,6 +131,8 @@
final List<JobServiceContext> mActiveServices = new ArrayList<>();
/** List of controllers that will notify this service of updates to jobs. */
List<StateController> mControllers;
+ /** Need direct access to this for testing. */
+ BatteryController mBatteryController;
/**
* Queue of pending jobs. The JobServiceContext class will receive jobs from this list
* when ready to execute them.
@@ -194,6 +196,7 @@
// Key names stored in the settings value.
private static final String KEY_MIN_IDLE_COUNT = "min_idle_count";
private static final String KEY_MIN_CHARGING_COUNT = "min_charging_count";
+ private static final String KEY_MIN_BATTERY_NOT_LOW_COUNT = "min_battery_not_low_count";
private static final String KEY_MIN_CONNECTIVITY_COUNT = "min_connectivity_count";
private static final String KEY_MIN_CONTENT_COUNT = "min_content_count";
private static final String KEY_MIN_READY_JOBS_COUNT = "min_ready_jobs_count";
@@ -207,6 +210,7 @@
private static final int DEFAULT_MIN_IDLE_COUNT = 1;
private static final int DEFAULT_MIN_CHARGING_COUNT = 1;
+ private static final int DEFAULT_MIN_BATTERY_NOT_LOW_COUNT = 1;
private static final int DEFAULT_MIN_CONNECTIVITY_COUNT = 1;
private static final int DEFAULT_MIN_CONTENT_COUNT = 1;
private static final int DEFAULT_MIN_READY_JOBS_COUNT = 1;
@@ -229,6 +233,11 @@
*/
int MIN_CHARGING_COUNT = DEFAULT_MIN_CHARGING_COUNT;
/**
+ * Minimum # of "battery not low" jobs that must be ready in order to force the JMS to
+ * schedule things early.
+ */
+ int MIN_BATTERY_NOT_LOW_COUNT = DEFAULT_MIN_BATTERY_NOT_LOW_COUNT;
+ /**
* Minimum # of connectivity jobs that must be ready in order to force the JMS to schedule
* things early. 1 == Run connectivity jobs as soon as ready.
*/
@@ -312,6 +321,8 @@
DEFAULT_MIN_IDLE_COUNT);
MIN_CHARGING_COUNT = mParser.getInt(KEY_MIN_CHARGING_COUNT,
DEFAULT_MIN_CHARGING_COUNT);
+ MIN_BATTERY_NOT_LOW_COUNT = mParser.getInt(KEY_MIN_BATTERY_NOT_LOW_COUNT,
+ DEFAULT_MIN_BATTERY_NOT_LOW_COUNT);
MIN_CONNECTIVITY_COUNT = mParser.getInt(KEY_MIN_CONNECTIVITY_COUNT,
DEFAULT_MIN_CONNECTIVITY_COUNT);
MIN_CONTENT_COUNT = mParser.getInt(KEY_MIN_CONTENT_COUNT,
@@ -356,6 +367,9 @@
pw.print(" "); pw.print(KEY_MIN_CHARGING_COUNT); pw.print("=");
pw.print(MIN_CHARGING_COUNT); pw.println();
+ pw.print(" "); pw.print(KEY_MIN_BATTERY_NOT_LOW_COUNT); pw.print("=");
+ pw.print(MIN_BATTERY_NOT_LOW_COUNT); pw.println();
+
pw.print(" "); pw.print(KEY_MIN_CONNECTIVITY_COUNT); pw.print("=");
pw.print(MIN_CONNECTIVITY_COUNT); pw.println();
@@ -785,7 +799,8 @@
mControllers.add(ConnectivityController.get(this));
mControllers.add(TimeController.get(this));
mControllers.add(IdleController.get(this));
- mControllers.add(BatteryController.get(this));
+ mBatteryController = BatteryController.get(this);
+ mControllers.add(mBatteryController);
mControllers.add(AppIdleController.get(this));
mControllers.add(ContentObserverController.get(this));
mControllers.add(DeviceIdleJobsController.get(this));
@@ -1186,6 +1201,7 @@
*/
class MaybeReadyJobQueueFunctor implements JobStatusFunctor {
int chargingCount;
+ int batteryNotLowCount;
int idleCount;
int backoffCount;
int connectivityCount;
@@ -1223,6 +1239,9 @@
if (job.hasChargingConstraint()) {
chargingCount++;
}
+ if (job.hasBatteryNotLowConstraint()) {
+ batteryNotLowCount++;
+ }
if (job.hasContentTriggerConstraint()) {
contentCount++;
}
@@ -1241,6 +1260,7 @@
idleCount >= mConstants.MIN_IDLE_COUNT ||
connectivityCount >= mConstants.MIN_CONNECTIVITY_COUNT ||
chargingCount >= mConstants.MIN_CHARGING_COUNT ||
+ batteryNotLowCount >= mConstants.MIN_BATTERY_NOT_LOW_COUNT ||
contentCount >= mConstants.MIN_CONTENT_COUNT ||
(runnableJobs != null
&& runnableJobs.size() >= mConstants.MIN_READY_JOBS_COUNT)) {
@@ -1264,6 +1284,7 @@
idleCount = 0;
backoffCount = 0;
connectivityCount = 0;
+ batteryNotLowCount = 0;
contentCount = 0;
runnableJobs = null;
}
@@ -1764,6 +1785,34 @@
return 0;
}
+ void setMonitorBattery(boolean enabled) {
+ synchronized (mLock) {
+ if (mBatteryController != null) {
+ mBatteryController.getTracker().setMonitorBatteryLocked(enabled);
+ }
+ }
+ }
+
+ int getBatterySeq() {
+ synchronized (mLock) {
+ return mBatteryController != null ? mBatteryController.getTracker().getSeq() : -1;
+ }
+ }
+
+ boolean getBatteryCharging() {
+ synchronized (mLock) {
+ return mBatteryController != null
+ ? mBatteryController.getTracker().isOnStablePower() : false;
+ }
+ }
+
+ boolean getBatteryNotLow() {
+ synchronized (mLock) {
+ return mBatteryController != null
+ ? mBatteryController.getTracker().isBatteryNotLow() : false;
+ }
+ }
+
private String printContextIdToJobMap(JobStatus[] map, String initial) {
StringBuilder s = new StringBuilder(initial + ": ");
for (int i=0; i<map.length; i++) {
diff --git a/services/core/java/com/android/server/job/JobSchedulerShellCommand.java b/services/core/java/com/android/server/job/JobSchedulerShellCommand.java
index 2d62c1c..ec23407 100644
--- a/services/core/java/com/android/server/job/JobSchedulerShellCommand.java
+++ b/services/core/java/com/android/server/job/JobSchedulerShellCommand.java
@@ -43,10 +43,19 @@
public int onCommand(String cmd) {
final PrintWriter pw = getOutPrintWriter();
try {
- if ("run".equals(cmd)) {
- return runJob();
- } else {
- return handleDefaultCommands(cmd);
+ switch (cmd != null ? cmd : "") {
+ case "run":
+ return runJob(pw);
+ case "monitor-battery":
+ return runMonitorBattery(pw);
+ case "get-battery-seq":
+ return runGetBatterySeq(pw);
+ case "get-battery-charging":
+ return runGetBatteryCharging(pw);
+ case "get-battery-not-low":
+ return runGetBatteryNotLow(pw);
+ default:
+ return handleDefaultCommands(cmd);
}
} catch (Exception e) {
pw.println("Exception: " + e);
@@ -54,20 +63,23 @@
return -1;
}
- private int runJob() {
- try {
- final int uid = Binder.getCallingUid();
- final int perm = mPM.checkUidPermission(
- "android.permission.CHANGE_APP_IDLE_STATE", uid);
- if (perm != PackageManager.PERMISSION_GRANTED) {
- throw new SecurityException("Uid " + uid
- + " not permitted to force scheduled jobs");
- }
- } catch (RemoteException e) {
- // Can't happen
+ private void checkPermission(String operation) throws Exception {
+ final int uid = Binder.getCallingUid();
+ if (uid == 0) {
+ // Root can do anything.
+ return;
}
+ final int perm = mPM.checkUidPermission(
+ "android.permission.CHANGE_APP_IDLE_STATE", uid);
+ if (perm != PackageManager.PERMISSION_GRANTED) {
+ throw new SecurityException("Uid " + uid
+ + " not permitted to " + operation);
+ }
+ }
- final PrintWriter pw = getOutPrintWriter();
+ private int runJob(PrintWriter pw) throws Exception {
+ checkPermission("force scheduled jobs");
+
boolean force = false;
int userId = UserHandle.USER_SYSTEM;
@@ -133,6 +145,42 @@
return ret;
}
+ private int runMonitorBattery(PrintWriter pw) throws Exception {
+ checkPermission("change battery monitoring");
+ String opt = getNextArgRequired();
+ boolean enabled;
+ if ("on".equals(opt)) {
+ enabled = true;
+ } else if ("off".equals(opt)) {
+ enabled = false;
+ } else {
+ getErrPrintWriter().println("Error: unknown option " + opt);
+ return 1;
+ }
+ mInternal.setMonitorBattery(enabled);
+ if (enabled) pw.println("Battery monitoring enabled");
+ else pw.println("Battery monitoring disabled");
+ return 0;
+ }
+
+ private int runGetBatterySeq(PrintWriter pw) {
+ int seq = mInternal.getBatterySeq();
+ pw.println(seq);
+ return 0;
+ }
+
+ private int runGetBatteryCharging(PrintWriter pw) {
+ boolean val = mInternal.getBatteryCharging();
+ pw.println(val);
+ return 0;
+ }
+
+ private int runGetBatteryNotLow(PrintWriter pw) {
+ boolean val = mInternal.getBatteryNotLow();
+ pw.println(val);
+ return 0;
+ }
+
@Override
public void onHelp() {
final PrintWriter pw = getOutPrintWriter();
@@ -140,7 +188,6 @@
pw.println("Job scheduler (jobscheduler) commands:");
pw.println(" help");
pw.println(" Print this help text.");
- pw.println();
pw.println(" run [-f | --force] [-u | --user USER_ID] PACKAGE JOB_ID");
pw.println(" Trigger immediate execution of a specific scheduled job.");
pw.println(" Options:");
@@ -148,6 +195,15 @@
pw.println(" connectivity are not currently met");
pw.println(" -u or --user: specify which user's job is to be run; the default is");
pw.println(" the primary or system user");
+ pw.println(" monitor-battery [on|off]");
+ pw.println(" Control monitoring of all battery changes. Off by default. Turning");
+ pw.println(" on makes get-battery-seq useful.");
+ pw.println(" get-battery-seq");
+ pw.println(" Return the last battery update sequence number that was received.");
+ pw.println(" get-battery-charging");
+ pw.println(" Return whether the battery is currently considered to be charging.");
+ pw.println(" get-battery-not-low");
+ pw.println(" Return whether the battery is currently considered to not be low.");
pw.println();
}
diff --git a/services/core/java/com/android/server/job/JobStore.java b/services/core/java/com/android/server/job/JobStore.java
index dd3f85f..ccfc287 100644
--- a/services/core/java/com/android/server/job/JobStore.java
+++ b/services/core/java/com/android/server/job/JobStore.java
@@ -381,6 +381,9 @@
if (jobStatus.hasChargingConstraint()) {
out.attribute(null, "charging", Boolean.toString(true));
}
+ if (jobStatus.hasBatteryNotLowConstraint()) {
+ out.attribute(null, "battery-not-low", Boolean.toString(true));
+ }
out.endTag(null, XML_TAG_PARAMS_CONSTRAINTS);
}
diff --git a/services/core/java/com/android/server/job/controllers/BatteryController.java b/services/core/java/com/android/server/job/controllers/BatteryController.java
index f6b8ef4..05527be 100644
--- a/services/core/java/com/android/server/job/controllers/BatteryController.java
+++ b/services/core/java/com/android/server/job/controllers/BatteryController.java
@@ -80,32 +80,38 @@
@Override
public void maybeStartTrackingJobLocked(JobStatus taskStatus, JobStatus lastJob) {
- final boolean isOnStablePower = mChargeTracker.isOnStablePower();
- if (taskStatus.hasChargingConstraint()) {
+ if (taskStatus.hasPowerConstraint()) {
mTrackedTasks.add(taskStatus);
- taskStatus.setChargingConstraintSatisfied(isOnStablePower);
+ taskStatus.setChargingConstraintSatisfied(mChargeTracker.isOnStablePower());
+ taskStatus.setBatteryNotLowConstraintSatisfied(mChargeTracker.isBatteryNotLow());
}
}
@Override
public void maybeStopTrackingJobLocked(JobStatus taskStatus, JobStatus incomingJob, boolean forUpdate) {
- if (taskStatus.hasChargingConstraint()) {
+ if (taskStatus.hasPowerConstraint()) {
mTrackedTasks.remove(taskStatus);
}
}
private void maybeReportNewChargingState() {
final boolean stablePower = mChargeTracker.isOnStablePower();
+ final boolean batteryNotLow = mChargeTracker.isBatteryNotLow();
if (DEBUG) {
Slog.d(TAG, "maybeReportNewChargingState: " + stablePower);
}
boolean reportChange = false;
synchronized (mLock) {
- for (JobStatus ts : mTrackedTasks) {
+ for (int i = mTrackedTasks.size() - 1; i >= 0; i--) {
+ final JobStatus ts = mTrackedTasks.get(i);
boolean previous = ts.setChargingConstraintSatisfied(stablePower);
if (previous != stablePower) {
reportChange = true;
}
+ previous = ts.setBatteryNotLowConstraintSatisfied(batteryNotLow);
+ if (previous != batteryNotLow) {
+ reportChange = true;
+ }
}
}
// Let the scheduler know that state has changed. This may or may not result in an
@@ -127,6 +133,10 @@
private boolean mCharging;
/** Keep track of whether the battery is charged enough that we want to do work. */
private boolean mBatteryHealthy;
+ /** Sequence number of last broadcast. */
+ private int mLastBatterySeq = -1;
+
+ private BroadcastReceiver mMonitor;
public ChargingTracker() {
}
@@ -149,10 +159,42 @@
mCharging = batteryManagerInternal.isPowered(BatteryManager.BATTERY_PLUGGED_ANY);
}
- boolean isOnStablePower() {
+ public void setMonitorBatteryLocked(boolean enabled) {
+ if (enabled) {
+ if (mMonitor == null) {
+ mMonitor = new BroadcastReceiver() {
+ @Override public void onReceive(Context context, Intent intent) {
+ ChargingTracker.this.onReceive(context, intent);
+ }
+ };
+ IntentFilter filter = new IntentFilter();
+ filter.addAction(Intent.ACTION_BATTERY_CHANGED);
+ mContext.registerReceiver(mMonitor, filter);
+ }
+ } else {
+ if (mMonitor != null) {
+ mContext.unregisterReceiver(mMonitor);
+ mMonitor = null;
+ }
+ }
+ }
+
+ public boolean isOnStablePower() {
return mCharging && mBatteryHealthy;
}
+ public boolean isBatteryNotLow() {
+ return mBatteryHealthy;
+ }
+
+ public boolean isMonitoring() {
+ return mMonitor != null;
+ }
+
+ public int getSeq() {
+ return mLastBatterySeq;
+ }
+
@Override
public void onReceive(Context context, Intent intent) {
onReceiveInternal(intent);
@@ -191,13 +233,20 @@
mCharging = false;
maybeReportNewChargingState();
}
+ mLastBatterySeq = intent.getIntExtra(BatteryManager.EXTRA_SEQUENCE, mLastBatterySeq);
}
}
@Override
public void dumpControllerStateLocked(PrintWriter pw, int filterUid) {
pw.print("Battery: stable power = ");
- pw.println(mChargeTracker.isOnStablePower());
+ pw.print(mChargeTracker.isOnStablePower());
+ pw.print(", not low = ");
+ pw.println(mChargeTracker.isBatteryNotLow());
+ if (mChargeTracker.isMonitoring()) {
+ pw.print("MONITORING: seq=");
+ pw.println(mChargeTracker.getSeq());
+ }
pw.print("Tracking ");
pw.print(mTrackedTasks.size());
pw.println(":");
diff --git a/services/core/java/com/android/server/job/controllers/JobStatus.java b/services/core/java/com/android/server/job/controllers/JobStatus.java
index 4b39bf9..9a55fed 100644
--- a/services/core/java/com/android/server/job/controllers/JobStatus.java
+++ b/services/core/java/com/android/server/job/controllers/JobStatus.java
@@ -46,16 +46,17 @@
public static final long NO_LATEST_RUNTIME = Long.MAX_VALUE;
public static final long NO_EARLIEST_RUNTIME = 0L;
- static final int CONSTRAINT_CHARGING = 1<<0;
- static final int CONSTRAINT_TIMING_DELAY = 1<<1;
- static final int CONSTRAINT_DEADLINE = 1<<2;
- static final int CONSTRAINT_IDLE = 1<<3;
- static final int CONSTRAINT_UNMETERED = 1<<4;
- static final int CONSTRAINT_CONNECTIVITY = 1<<5;
- static final int CONSTRAINT_APP_NOT_IDLE = 1<<6;
- static final int CONSTRAINT_CONTENT_TRIGGER = 1<<7;
- static final int CONSTRAINT_DEVICE_NOT_DOZING = 1<<8;
- static final int CONSTRAINT_NOT_ROAMING = 1<<9;
+ static final int CONSTRAINT_CHARGING = JobInfo.CONSTRAINT_FLAG_CHARGING;
+ static final int CONSTRAINT_IDLE = JobInfo.CONSTRAINT_FLAG_DEVICE_IDLE;
+ static final int CONSTRAINT_BATTERY_NOT_LOW = JobInfo.CONSTRAINT_FLAG_BATTERY_NOT_LOW;
+ static final int CONSTRAINT_TIMING_DELAY = 1<<31;
+ static final int CONSTRAINT_DEADLINE = 1<<30;
+ static final int CONSTRAINT_UNMETERED = 1<<29;
+ static final int CONSTRAINT_CONNECTIVITY = 1<<28;
+ static final int CONSTRAINT_APP_NOT_IDLE = 1<<27;
+ static final int CONSTRAINT_CONTENT_TRIGGER = 1<<26;
+ static final int CONSTRAINT_DEVICE_NOT_DOZING = 1<<25;
+ static final int CONSTRAINT_NOT_ROAMING = 1<<24;
// Soft override: ignore constraints like time that don't affect API availability
public static final int OVERRIDE_SOFT = 1;
@@ -163,7 +164,7 @@
this.latestRunTimeElapsedMillis = latestRunTimeElapsedMillis;
this.numFailures = numFailures;
- int requiredConstraints = 0;
+ int requiredConstraints = job.getConstraintFlags();
if (job.getNetworkType() == JobInfo.NETWORK_TYPE_ANY) {
requiredConstraints |= CONSTRAINT_CONNECTIVITY;
}
@@ -173,18 +174,12 @@
if (job.getNetworkType() == JobInfo.NETWORK_TYPE_NOT_ROAMING) {
requiredConstraints |= CONSTRAINT_NOT_ROAMING;
}
- if (job.isRequireCharging()) {
- requiredConstraints |= CONSTRAINT_CHARGING;
- }
if (earliestRunTimeElapsedMillis != NO_EARLIEST_RUNTIME) {
requiredConstraints |= CONSTRAINT_TIMING_DELAY;
}
if (latestRunTimeElapsedMillis != NO_LATEST_RUNTIME) {
requiredConstraints |= CONSTRAINT_DEADLINE;
}
- if (job.isRequireDeviceIdle()) {
- requiredConstraints |= CONSTRAINT_IDLE;
- }
if (job.getTriggerContentUris() != null) {
requiredConstraints |= CONSTRAINT_CONTENT_TRIGGER;
}
@@ -331,6 +326,14 @@
return (requiredConstraints&CONSTRAINT_CHARGING) != 0;
}
+ public boolean hasBatteryNotLowConstraint() {
+ return (requiredConstraints&CONSTRAINT_BATTERY_NOT_LOW) != 0;
+ }
+
+ public boolean hasPowerConstraint() {
+ return (requiredConstraints&(CONSTRAINT_CHARGING|CONSTRAINT_BATTERY_NOT_LOW)) != 0;
+ }
+
public boolean hasTimingDelayConstraint() {
return (requiredConstraints&CONSTRAINT_TIMING_DELAY) != 0;
}
@@ -379,6 +382,10 @@
return setConstraintSatisfied(CONSTRAINT_CHARGING, state);
}
+ boolean setBatteryNotLowConstraintSatisfied(boolean state) {
+ return setConstraintSatisfied(CONSTRAINT_BATTERY_NOT_LOW, state);
+ }
+
boolean setTimingDelayConstraintSatisfied(boolean state) {
return setConstraintSatisfied(CONSTRAINT_TIMING_DELAY, state);
}
@@ -453,13 +460,14 @@
}
static final int CONSTRAINTS_OF_INTEREST =
- CONSTRAINT_CHARGING | CONSTRAINT_TIMING_DELAY |
+ CONSTRAINT_CHARGING | CONSTRAINT_BATTERY_NOT_LOW | CONSTRAINT_TIMING_DELAY |
CONSTRAINT_CONNECTIVITY | CONSTRAINT_UNMETERED | CONSTRAINT_NOT_ROAMING |
CONSTRAINT_IDLE | CONSTRAINT_CONTENT_TRIGGER;
// Soft override covers all non-"functional" constraints
static final int SOFT_OVERRIDE_CONSTRAINTS =
- CONSTRAINT_CHARGING | CONSTRAINT_TIMING_DELAY | CONSTRAINT_IDLE;
+ CONSTRAINT_CHARGING | CONSTRAINT_BATTERY_NOT_LOW
+ | CONSTRAINT_TIMING_DELAY | CONSTRAINT_IDLE;
/**
* @return Whether the constraints set on this job are satisfied.
@@ -495,6 +503,7 @@
+ ",R=(" + formatRunTime(earliestRunTimeElapsedMillis, NO_EARLIEST_RUNTIME)
+ "," + formatRunTime(latestRunTimeElapsedMillis, NO_LATEST_RUNTIME) + ")"
+ ",N=" + job.getNetworkType() + ",C=" + job.isRequireCharging()
+ + ",BL=" + job.isRequireBatteryNotLow()
+ ",I=" + job.isRequireDeviceIdle()
+ ",U=" + (job.getTriggerContentUris() != null)
+ ",F=" + numFailures + ",P=" + job.isPersisted()
@@ -550,6 +559,9 @@
if ((constraints&CONSTRAINT_CHARGING) != 0) {
pw.print(" CHARGING");
}
+ if ((constraints& CONSTRAINT_BATTERY_NOT_LOW) != 0) {
+ pw.print(" BATTERY_NOT_LOW");
+ }
if ((constraints&CONSTRAINT_TIMING_DELAY) != 0) {
pw.print(" TIMING_DELAY");
}
@@ -607,7 +619,8 @@
pw.println(Integer.toHexString(job.getFlags()));
}
pw.print(prefix); pw.print(" Requires: charging=");
- pw.print(job.isRequireCharging()); pw.print(" deviceIdle=");
+ pw.print(job.isRequireCharging()); pw.print(" batteryNotLow=");
+ pw.print(job.isRequireBatteryNotLow()); pw.print(" deviceIdle=");
pw.println(job.isRequireDeviceIdle());
if (job.getTriggerContentUris() != null) {
pw.print(prefix); pw.println(" Trigger content URIs:");
diff --git a/services/core/java/com/android/server/media/MediaSessionService.java b/services/core/java/com/android/server/media/MediaSessionService.java
index 36f3287..6349f21 100644
--- a/services/core/java/com/android/server/media/MediaSessionService.java
+++ b/services/core/java/com/android/server/media/MediaSessionService.java
@@ -37,6 +37,7 @@
import android.media.IAudioService;
import android.media.IRemoteVolumeController;
import android.media.session.IActiveSessionsListener;
+import android.media.session.ICallback;
import android.media.session.IOnMediaKeyListener;
import android.media.session.IOnVolumeKeyLongPressListener;
import android.media.session.ISession;
@@ -107,6 +108,7 @@
private AudioManagerInternal mAudioManagerInternal;
private ContentResolver mContentResolver;
private SettingsObserver mSettingsObserver;
+ private ICallback mCallback;
// List of user IDs running in the foreground.
// Multiple users can be in the foreground if the work profile is on.
@@ -486,6 +488,7 @@
if (size > 0 && records.get(0).isPlaybackActive(false)) {
rememberMediaButtonReceiverLocked(records.get(0));
}
+ pushAddressedPlayerChangedLocked();
ArrayList<MediaSession.Token> tokens = new ArrayList<MediaSession.Token>();
for (int i = 0; i < size; i++) {
tokens.add(new MediaSession.Token(records.get(i).getControllerBinder()));
@@ -517,6 +520,52 @@
}
}
+ private MediaSessionRecord getMediaButtonSessionLocked() {
+ // If we don't have a media button receiver to fall back on
+ // include non-playing sessions for dispatching.
+ boolean useNotPlayingSessions = true;
+ for (int userId : mCurrentUserIdList) {
+ UserRecord ur = mUserRecords.get(userId);
+ if (ur.mLastMediaButtonReceiver != null
+ || ur.mRestoredMediaButtonReceiver != null) {
+ useNotPlayingSessions = false;
+ break;
+ }
+ }
+ return mPriorityStack.getDefaultMediaButtonSession(
+ mCurrentUserIdList, useNotPlayingSessions);
+ }
+
+ private void pushAddressedPlayerChangedLocked() {
+ if (mCallback == null) {
+ return;
+ }
+ try {
+ MediaSessionRecord mediaButtonSession = getMediaButtonSessionLocked();
+ if (mediaButtonSession != null) {
+ mCallback.onAddressedPlayerChangedToMediaSession(
+ new MediaSession.Token(mediaButtonSession.getControllerBinder()));
+ } else {
+ for (int userId : mCurrentUserIdList) {
+ UserRecord user = mUserRecords.get(userId);
+ if (user.mLastMediaButtonReceiver == null
+ && user.mRestoredMediaButtonReceiver == null) {
+ continue;
+ }
+ ComponentName componentName = user.mLastMediaButtonReceiver != null
+ ? user.mLastMediaButtonReceiver.getIntent().getComponent()
+ : user.mRestoredMediaButtonReceiver;
+ mCallback.onAddressedPlayerChangedToMediaButtonReceiver(componentName);
+ return;
+ }
+ }
+ } catch (RemoteException e) {
+ Log.w(TAG, "Failed to pushAddressedPlayerChangedLocked", e);
+ }
+ }
+
+ // Remember media button receiver and keep it in the persistent storage.
+ // This should be called whenever there's no media session to receive media button event.
private void rememberMediaButtonReceiverLocked(MediaSessionRecord record) {
PendingIntent receiver = record.getMediaButtonReceiver();
UserRecord user = mUserRecords.get(record.getUserId());
@@ -801,19 +850,74 @@
+ "setup is in progress.");
return;
}
- if (isGlobalPriorityActive() && uid != Process.SYSTEM_UID) {
- // Prevent dispatching key event through reflection while the global priority
- // session is active.
- Slog.i(TAG, "Only the system can dispatch media key event "
- + "to the global priority session.");
- return;
- }
synchronized (mLock) {
- if (!isGlobalPriorityActive() && isVoiceKey(keyEvent.getKeyCode())) {
+ boolean isGlobalPriorityActive = mPriorityStack.isGlobalPriorityActive();
+ if (isGlobalPriorityActive && uid != Process.SYSTEM_UID) {
+ // Prevent dispatching key event through reflection while the global
+ // priority session is active.
+ Slog.i(TAG, "Only the system can dispatch media key event "
+ + "to the global priority session.");
+ return;
+ }
+ if (!isGlobalPriorityActive) {
+ // Only consider full user.
+ UserRecord user = mUserRecords.get(mCurrentUserIdList.get(0));
+ if (user.mOnMediaKeyListener != null) {
+ if (DEBUG_KEY_EVENT) {
+ Log.d(TAG, "Send " + keyEvent + " to media key listener");
+ }
+ try {
+ user.mOnMediaKeyListener.onMediaKey(keyEvent,
+ new MediaKeyListenerResultReceiver(keyEvent, needWakeLock));
+ return;
+ } catch (RemoteException e) {
+ Log.w(TAG, "Failed to send " + keyEvent + " to media key listener");
+ }
+ }
+ }
+ if (!isGlobalPriorityActive && isVoiceKey(keyEvent.getKeyCode())) {
handleVoiceKeyEventLocked(keyEvent, needWakeLock);
} else {
- dispatchMediaKeyEventLocked(keyEvent, needWakeLock, true);
+ dispatchMediaKeyEventLocked(keyEvent, needWakeLock);
+ }
+ }
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
+ @Override
+ public void setCallback(ICallback callback) {
+ final int pid = Binder.getCallingPid();
+ final int uid = Binder.getCallingUid();
+ final long token = Binder.clearCallingIdentity();
+ try {
+ if (uid != Process.BLUETOOTH_UID) {
+ throw new SecurityException("Only Bluetooth service processes can set"
+ + " Callback");
+ }
+ synchronized (mLock) {
+ Log.d(TAG, "Callback + " + mCallback
+ + " is set by " + getCallingPackageName(uid));
+ mCallback = callback;
+ if (mCallback == null) {
+ return;
+ }
+ try {
+ mCallback.asBinder().linkToDeath(
+ new IBinder.DeathRecipient() {
+ @Override
+ public void binderDied() {
+ synchronized (mLock) {
+ mCallback = null;
+ }
+ }
+ }, 0);
+ pushAddressedPlayerChangedLocked();
+ } catch (RemoteException e) {
+ Log.w(TAG, "Failed to set callback", e);
+ mCallback = null;
}
}
} finally {
@@ -1080,7 +1184,9 @@
@Override
public boolean isGlobalPriorityActive() {
- return mPriorityStack.isGlobalPriorityActive();
+ synchronized (mLock) {
+ return mPriorityStack.isGlobalPriorityActive();
+ }
}
@Override
@@ -1190,52 +1296,15 @@
if (!mVoiceButtonHandled && !keyEvent.isCanceled()) {
// Resend the down then send this event through
KeyEvent downEvent = KeyEvent.changeAction(keyEvent, KeyEvent.ACTION_DOWN);
- dispatchMediaKeyEventLocked(downEvent, needWakeLock, true);
- dispatchMediaKeyEventLocked(keyEvent, needWakeLock, true);
+ dispatchMediaKeyEventLocked(downEvent, needWakeLock);
+ dispatchMediaKeyEventLocked(keyEvent, needWakeLock);
}
}
}
}
- private void dispatchMediaKeyEventLocked(KeyEvent keyEvent, boolean needWakeLock,
- boolean checkMediaKeyListener) {
- // If we don't have a media button receiver to fall back on
- // include non-playing sessions for dispatching.
- boolean useNotPlayingSessions = true;
- for (int userId : mCurrentUserIdList) {
- UserRecord ur = mUserRecords.get(userId);
- if (ur.mLastMediaButtonReceiver != null
- || ur.mRestoredMediaButtonReceiver != null) {
- useNotPlayingSessions = false;
- break;
- }
- }
- if (DEBUG) {
- Log.d(TAG, "dispatchMediaKeyEvent, useNotPlayingSessions="
- + useNotPlayingSessions);
- }
-
- MediaSessionRecord session = mPriorityStack.getDefaultMediaButtonSession(
- mCurrentUserIdList, useNotPlayingSessions);
-
- if ((session == null
- || !session.hasFlag(MediaSession.FLAG_EXCLUSIVE_GLOBAL_PRIORITY))
- && checkMediaKeyListener) {
- // Only consider full user.
- UserRecord user = mUserRecords.get(mCurrentUserIdList.get(0));
- if (user.mOnMediaKeyListener != null) {
- if (DEBUG_KEY_EVENT) {
- Log.d(TAG, "Send " + keyEvent + " to media key listener");
- }
- try {
- user.mOnMediaKeyListener.onMediaKey(keyEvent,
- new MediaKeyListenerResultReceiver(keyEvent, needWakeLock));
- return;
- } catch (RemoteException e) {
- Log.w(TAG, "Failed to send " + keyEvent + " to media key listener");
- }
- }
- }
+ private void dispatchMediaKeyEventLocked(KeyEvent keyEvent, boolean needWakeLock) {
+ MediaSessionRecord session = getMediaButtonSessionLocked();
if (session != null) {
if (DEBUG_KEY_EVENT) {
Log.d(TAG, "Sending " + keyEvent + " to " + session);
@@ -1248,6 +1317,14 @@
needWakeLock ? mKeyEventReceiver.mLastTimeoutId : -1,
mKeyEventReceiver, Process.SYSTEM_UID,
getContext().getPackageName());
+ if (mCallback != null) {
+ try {
+ mCallback.onMediaKeyEventDispatchedToMediaSession(keyEvent,
+ new MediaSession.Token(session.getControllerBinder()));
+ } catch (RemoteException e) {
+ Log.w(TAG, "Failed to send callback", e);
+ }
+ }
} else {
// Launch the last PendingIntent we had with priority
for (int userId : mCurrentUserIdList) {
@@ -1264,26 +1341,41 @@
mediaButtonIntent.putExtra(Intent.EXTRA_KEY_EVENT, keyEvent);
try {
if (user.mLastMediaButtonReceiver != null) {
+ PendingIntent receiver = user.mLastMediaButtonReceiver;
if (DEBUG_KEY_EVENT) {
Log.d(TAG, "Sending " + keyEvent
- + " to the last known pendingIntent "
- + user.mLastMediaButtonReceiver);
+ + " to the last known pendingIntent " + receiver);
}
- user.mLastMediaButtonReceiver.send(getContext(),
+ receiver.send(getContext(),
needWakeLock ? mKeyEventReceiver.mLastTimeoutId : -1,
mediaButtonIntent, mKeyEventReceiver, mHandler);
+ if (mCallback != null) {
+ ComponentName componentName =
+ user.mLastMediaButtonReceiver.getIntent().getComponent();
+ if (componentName != null) {
+ mCallback.onMediaKeyEventDispatchedToMediaButtonReceiver(
+ keyEvent, componentName);
+ }
+ }
} else {
+ ComponentName receiver = user.mRestoredMediaButtonReceiver;
if (DEBUG_KEY_EVENT) {
Log.d(TAG, "Sending " + keyEvent + " to the restored intent "
- + user.mRestoredMediaButtonReceiver);
+ + receiver);
}
- mediaButtonIntent.setComponent(user.mRestoredMediaButtonReceiver);
+ mediaButtonIntent.setComponent(receiver);
getContext().sendBroadcastAsUser(mediaButtonIntent,
UserHandle.of(userId));
+ if (mCallback != null) {
+ mCallback.onMediaKeyEventDispatchedToMediaButtonReceiver(
+ keyEvent, receiver);
+ }
}
} catch (CanceledException e) {
Log.i(TAG, "Error sending key event to media button receiver "
+ user.mLastMediaButtonReceiver, e);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Failed to send callback", e);
}
return;
}
@@ -1394,7 +1486,12 @@
mHandled = true;
mHandler.removeCallbacks(this);
synchronized (mLock) {
- dispatchMediaKeyEventLocked(mKeyEvent, mNeedWakeLock, false);
+ if (!mPriorityStack.isGlobalPriorityActive()
+ && isVoiceKey(mKeyEvent.getKeyCode())) {
+ handleVoiceKeyEventLocked(mKeyEvent, mNeedWakeLock);
+ } else {
+ dispatchMediaKeyEventLocked(mKeyEvent, mNeedWakeLock);
+ }
}
}
}
diff --git a/services/core/java/com/android/server/net/LockdownVpnTracker.java b/services/core/java/com/android/server/net/LockdownVpnTracker.java
index 4a8539a..a5e7d7c 100644
--- a/services/core/java/com/android/server/net/LockdownVpnTracker.java
+++ b/services/core/java/com/android/server/net/LockdownVpnTracker.java
@@ -47,6 +47,7 @@
import com.android.internal.R;
import com.android.internal.net.VpnConfig;
import com.android.internal.net.VpnProfile;
+import com.android.internal.notification.SystemNotificationChannels;
import com.android.internal.util.Preconditions;
import com.android.server.ConnectivityService;
import com.android.server.EventLogTags;
@@ -330,18 +331,18 @@
}
private void showNotification(int titleRes, int iconRes) {
- final Notification.Builder builder = new Notification.Builder(mContext)
- .setWhen(0)
- .setSmallIcon(iconRes)
- .setContentTitle(mContext.getString(titleRes))
- .setContentText(mContext.getString(R.string.vpn_lockdown_config))
- .setContentIntent(mConfigIntent)
- .setPriority(Notification.PRIORITY_LOW)
- .setOngoing(true)
- .addAction(R.drawable.ic_menu_refresh, mContext.getString(R.string.reset),
- mResetIntent)
- .setColor(mContext.getColor(
- com.android.internal.R.color.system_notification_accent_color));
+ final Notification.Builder builder =
+ new Notification.Builder(mContext, SystemNotificationChannels.VPN)
+ .setWhen(0)
+ .setSmallIcon(iconRes)
+ .setContentTitle(mContext.getString(titleRes))
+ .setContentText(mContext.getString(R.string.vpn_lockdown_config))
+ .setContentIntent(mConfigIntent)
+ .setOngoing(true)
+ .addAction(R.drawable.ic_menu_refresh, mContext.getString(R.string.reset),
+ mResetIntent)
+ .setColor(mContext.getColor(
+ com.android.internal.R.color.system_notification_accent_color));
NotificationManager.from(mContext).notify(TAG, 0, builder.build());
}
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index 7d3d902..5078998 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -171,6 +171,7 @@
import com.android.internal.R;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.notification.SystemNotificationChannels;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.FastXmlSerializer;
import com.android.internal.util.IndentingPrintWriter;
@@ -1069,7 +1070,8 @@
*/
private void enqueueNotification(NetworkPolicy policy, int type, long totalBytes) {
final String tag = buildNotificationTag(policy, type);
- final Notification.Builder builder = new Notification.Builder(mContext);
+ final Notification.Builder builder =
+ new Notification.Builder(mContext, SystemNotificationChannels.NETWORK_STATUS);
builder.setOnlyAlertOnce(true);
builder.setWhen(0L);
builder.setColor(mContext.getColor(
@@ -1087,7 +1089,7 @@
builder.setContentTitle(title);
builder.setContentText(body);
builder.setDefaults(Notification.DEFAULT_ALL);
- builder.setPriority(Notification.PRIORITY_HIGH);
+ builder.setChannel(SystemNotificationChannels.NETWORK_ALERTS);
final Intent snoozeIntent = buildSnoozeWarningIntent(policy.template);
builder.setDeleteIntent(PendingIntent.getBroadcast(
@@ -2602,8 +2604,7 @@
// (mPowerSaveTempWhitelistAppIds) for whitelisting, we can reuse their logic in this method.
private void updateRulesForWhitelistedPowerSaveUL(int uid, boolean enabled, int chain) {
if (enabled) {
- if (isWhitelistedBatterySaverUL(uid)
- || isProcStateAllowedWhileIdleOrPowerSaveMode(mUidState.get(uid))) {
+ if (isWhitelistedBatterySaverUL(uid) || isUidForegroundOnRestrictPowerUL(uid)) {
setUidFirewallRule(chain, uid, FIREWALL_RULE_ALLOW);
} else {
setUidFirewallRule(chain, uid, FIREWALL_RULE_DEFAULT);
diff --git a/services/core/java/com/android/server/notification/BadgeExtractor.java b/services/core/java/com/android/server/notification/BadgeExtractor.java
index 4795fbf..e6edaf1 100644
--- a/services/core/java/com/android/server/notification/BadgeExtractor.java
+++ b/services/core/java/com/android/server/notification/BadgeExtractor.java
@@ -46,7 +46,9 @@
if (!appCanShowBadge) {
record.setShowBadge(false);
} else {
- record.setShowBadge(record.getChannel().canShowBadge() && appCanShowBadge);
+ record.setShowBadge(mConfig.getNotificationChannel(record.sbn.getPackageName(),
+ record.sbn.getUid(), record.getChannel().getId(), false).canShowBadge()
+ && appCanShowBadge);
}
return null;
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 8f4ad00..dae5da3 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -2029,11 +2029,11 @@
*/
@Override
public void snoozeNotificationUntilFromListener(INotificationListener token, String key,
- long snoozeUntil) {
+ long duration) {
long identity = Binder.clearCallingIdentity();
try {
final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
- snoozeNotificationInt(key, snoozeUntil, null, info);
+ snoozeNotificationInt(key, duration, null, info);
} finally {
Binder.restoreCallingIdentity(identity);
}
@@ -2736,9 +2736,10 @@
Notification.EXTRA_BUILDER_APPLICATION_INFO);
final Bundle extras = new Bundle();
extras.putParcelable(Notification.EXTRA_BUILDER_APPLICATION_INFO, appInfo);
+ final String channelId = notificationRecord.getChannel().getId();
final Notification summaryNotification =
- new Notification.Builder(getContext()).setSmallIcon(
- adjustedSbn.getNotification().getSmallIcon())
+ new Notification.Builder(getContext(), channelId)
+ .setSmallIcon(adjustedSbn.getNotification().getSmallIcon())
.setGroupSummary(true)
.setGroup(GroupHelper.AUTOGROUP_KEY)
.setFlag(Notification.FLAG_AUTOGROUP_SUMMARY, true)
@@ -3409,7 +3410,7 @@
@VisibleForTesting
void scheduleTimeoutLocked(NotificationRecord record) {
- if (record.getNotification().getTimeout() > System.currentTimeMillis()) {
+ if (record.getNotification().getTimeout() > 0) {
final PendingIntent pi = PendingIntent.getBroadcast(getContext(),
REQUEST_CODE_TIMEOUT,
new Intent(ACTION_NOTIFICATION_TIMEOUT)
@@ -3418,8 +3419,8 @@
.addFlags(Intent.FLAG_RECEIVER_FOREGROUND)
.putExtra(EXTRA_KEY, record.getKey()),
PendingIntent.FLAG_UPDATE_CURRENT);
- mAlarmManager.setExactAndAllowWhileIdle(
- AlarmManager.RTC_WAKEUP, record.getNotification().getTimeout(), pi);
+ mAlarmManager.setExactAndAllowWhileIdle(AlarmManager.ELAPSED_REALTIME_WAKEUP,
+ SystemClock.elapsedRealtime() + record.getNotification().getTimeout(), pi);
}
}
@@ -4185,16 +4186,16 @@
}
}
- void snoozeNotificationInt(String key, long until, String snoozeCriterionId,
+ void snoozeNotificationInt(String key, long duration, String snoozeCriterionId,
ManagedServiceInfo listener) {
String listenerName = listener == null ? null : listener.component.toShortString();
- if (until < System.currentTimeMillis() && snoozeCriterionId == null) {
+ if (duration <= 0 && snoozeCriterionId == null) {
return;
}
if (DBG) {
- Slog.d(TAG, String.format("snooze event(%s, %d, %s, %s)", key, until, snoozeCriterionId,
- listenerName));
+ Slog.d(TAG, String.format("snooze event(%s, %d, %s, %s)", key, duration,
+ snoozeCriterionId, listenerName));
}
// Needs to post so that it can cancel notifications not yet enqueued.
mHandler.post(new Runnable() {
@@ -4215,7 +4216,7 @@
snoozeCriterionId);
mSnoozeHelper.snooze(r);
} else {
- mSnoozeHelper.snooze(r, until);
+ mSnoozeHelper.snooze(r, duration);
}
savePolicyFile();
}
diff --git a/services/core/java/com/android/server/notification/RankingHelper.java b/services/core/java/com/android/server/notification/RankingHelper.java
index 76890b1..867af9a 100644
--- a/services/core/java/com/android/server/notification/RankingHelper.java
+++ b/services/core/java/com/android/server/notification/RankingHelper.java
@@ -32,6 +32,7 @@
import android.content.pm.ParceledListSlice;
import android.os.Build;
import android.os.UserHandle;
+import android.provider.Settings;
import android.service.notification.NotificationListenerService.Ranking;
import android.text.TextUtils;
import android.util.ArrayMap;
@@ -516,6 +517,10 @@
if (!r.showBadge) {
channel.setShowBadge(false);
}
+ if (channel.getSound() == null) {
+ channel.setSound(Settings.System.DEFAULT_NOTIFICATION_URI,
+ Notification.AUDIO_ATTRIBUTES_DEFAULT);
+ }
r.channels.put(channel.getId(), channel);
updateConfig();
}
diff --git a/services/core/java/com/android/server/notification/SnoozeHelper.java b/services/core/java/com/android/server/notification/SnoozeHelper.java
index 0cd8cea..913f636 100644
--- a/services/core/java/com/android/server/notification/SnoozeHelper.java
+++ b/services/core/java/com/android/server/notification/SnoozeHelper.java
@@ -32,6 +32,7 @@
import android.content.IntentFilter;
import android.net.Uri;
import android.os.Binder;
+import android.os.SystemClock;
import android.os.UserHandle;
import android.service.notification.StatusBarNotification;
import android.util.ArrayMap;
@@ -125,9 +126,9 @@
/**
* Snoozes a notification and schedules an alarm to repost at that time.
*/
- protected void snooze(NotificationRecord record, long until) {
+ protected void snooze(NotificationRecord record, long duration) {
snooze(record);
- scheduleRepost(record.sbn.getPackageName(), record.getKey(), record.getUserId(), until);
+ scheduleRepost(record.sbn.getPackageName(), record.getKey(), record.getUserId(), duration);
}
/**
@@ -291,13 +292,14 @@
PendingIntent.FLAG_UPDATE_CURRENT);
}
- private void scheduleRepost(String pkg, String key, int userId, long time) {
+ private void scheduleRepost(String pkg, String key, int userId, long duration) {
long identity = Binder.clearCallingIdentity();
try {
final PendingIntent pi = createPendingIntent(pkg, key, userId);
mAm.cancel(pi);
+ long time = SystemClock.elapsedRealtime() + duration;
if (DEBUG) Slog.d(TAG, "Scheduling evaluate for " + new Date(time));
- mAm.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, time, pi);
+ mAm.setExactAndAllowWhileIdle(AlarmManager.ELAPSED_REALTIME_WAKEUP, time, pi);
} finally {
Binder.restoreCallingIdentity(identity);
}
diff --git a/services/core/java/com/android/server/om/OverlayManagerService.java b/services/core/java/com/android/server/om/OverlayManagerService.java
index cc709ce..ba4d46a 100644
--- a/services/core/java/com/android/server/om/OverlayManagerService.java
+++ b/services/core/java/com/android/server/om/OverlayManagerService.java
@@ -26,7 +26,6 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.ActivityManager;
-import android.app.ActivityManagerNative;
import android.app.IActivityManager;
import android.content.BroadcastReceiver;
import android.content.Context;
@@ -42,7 +41,6 @@
import android.os.Binder;
import android.os.Environment;
import android.os.IBinder;
-import android.os.Process;
import android.os.RemoteException;
import android.os.ResultReceiver;
import android.os.ShellCallback;
@@ -646,7 +644,7 @@
Slog.d(TAG, String.format("send broadcast %s", intent));
}
try {
- ActivityManagerNative.getDefault().broadcastIntent(null, intent, null, null, 0,
+ ActivityManager.getService().broadcastIntent(null, intent, null, null, 0,
null, null, null, android.app.AppOpsManager.OP_NONE, null, false, false,
userId);
} catch (RemoteException e) {
@@ -664,7 +662,38 @@
}
private void updateAssets(final int userId, List<String> targetPackageNames) {
- // TODO: implement when we integrate OMS properly
+ final PackageManagerInternal pm = LocalServices.getService(PackageManagerInternal.class);
+ final boolean updateFrameworkRes = targetPackageNames.contains("android");
+ if (updateFrameworkRes) {
+ targetPackageNames = pm.getTargetPackageNames(userId);
+ }
+
+ final Map<String, List<String>> pendingChanges = new ArrayMap<>(targetPackageNames.size());
+ synchronized (mLock) {
+ final int N = targetPackageNames.size();
+ for (int i = 0; i < N; i++) {
+ final String targetPackageName = targetPackageNames.get(i);
+ pendingChanges.put(targetPackageName,
+ mImpl.getEnabledOverlayPackageNames(targetPackageName, userId));
+ }
+ }
+
+ final int N = targetPackageNames.size();
+ for (int i = 0; i < N; i++) {
+ final String targetPackageName = targetPackageNames.get(i);
+ if (!pm.setEnabledOverlayPackages(
+ userId, targetPackageName, pendingChanges.get(targetPackageName))) {
+ Slog.e(TAG, String.format("Failed to change enabled overlays for %s user %d",
+ targetPackageName, userId));
+ }
+ }
+
+ final IActivityManager am = ActivityManager.getService();
+ try {
+ am.scheduleApplicationInfoChanged(targetPackageNames, userId);
+ } catch (RemoteException e) {
+ // Intentionally left empty.
+ }
}
private void schedulePersistSettings() {
diff --git a/services/core/java/com/android/server/pm/EphemeralResolver.java b/services/core/java/com/android/server/pm/EphemeralResolver.java
index d99a1b6..7bc65f9 100644
--- a/services/core/java/com/android/server/pm/EphemeralResolver.java
+++ b/services/core/java/com/android/server/pm/EphemeralResolver.java
@@ -16,8 +16,9 @@
package com.android.server.pm;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.app.ActivityManager;
-import android.app.ActivityManagerNative;
import android.app.PendingIntent;
import android.content.ComponentName;
import android.content.Context;
@@ -29,7 +30,7 @@
import android.content.pm.EphemeralIntentFilter;
import android.content.pm.EphemeralRequest;
import android.content.pm.EphemeralResolveInfo;
-import android.content.pm.EphemeralResponse;
+import android.content.pm.AuxiliaryResolveInfo;
import android.content.pm.EphemeralResolveInfo.EphemeralDigest;
import android.os.Binder;
import android.os.Handler;
@@ -46,7 +47,7 @@
/** @hide */
public abstract class EphemeralResolver {
- public static EphemeralResponse doEphemeralResolutionPhaseOne(Context context,
+ public static AuxiliaryResolveInfo doEphemeralResolutionPhaseOne(Context context,
EphemeralResolverConnection connection, EphemeralRequest requestObj) {
final Intent intent = requestObj.origIntent;
final EphemeralDigest digest =
@@ -83,7 +84,7 @@
final ArrayList<EphemeralResolveInfo> ephemeralResolveInfoList =
new ArrayList<EphemeralResolveInfo>(1);
ephemeralResolveInfoList.add(ephemeralResolveInfo);
- final EphemeralResponse ephemeralIntentInfo =
+ final AuxiliaryResolveInfo ephemeralIntentInfo =
EphemeralResolver.filterEphemeralIntent(
ephemeralResolveInfoList, intent, null /*resolvedType*/,
0 /*userId*/, intent.getPackage(), digest,
@@ -104,7 +105,6 @@
versionCode = -1;
}
final Intent installerIntent = buildEphemeralInstallerIntent(
- requestObj.launchIntent,
requestObj.origIntent,
requestObj.callingPackage,
requestObj.resolvedType,
@@ -126,35 +126,41 @@
/**
* Builds and returns an intent to launch the ephemeral installer.
*/
- public static Intent buildEphemeralInstallerIntent(Intent launchIntent, Intent origIntent,
- String callingPackage, String resolvedType, int userId, String ephemeralPackageName,
- String ephemeralSplitName, int versionCode, String token, boolean needsPhaseTwo) {
+ public static Intent buildEphemeralInstallerIntent(@NonNull Intent origIntent,
+ @NonNull String callingPackage,
+ @NonNull String resolvedType,
+ int userId,
+ @NonNull String ephemeralPackageName,
+ @Nullable String ephemeralSplitName,
+ int versionCode,
+ @Nullable String token,
+ boolean needsPhaseTwo) {
// Construct the intent that launches the ephemeral installer
- int flags = launchIntent.getFlags();
+ int flags = origIntent.getFlags();
final Intent intent = new Intent();
intent.setFlags(flags
| Intent.FLAG_ACTIVITY_NEW_TASK
| Intent.FLAG_ACTIVITY_CLEAR_TASK
| Intent.FLAG_ACTIVITY_NO_HISTORY
| Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
- // TODO: Remove when the platform has fully implemented ephemeral apps
- intent.setData(origIntent.getData().buildUpon().clearQuery().build());
- intent.putExtra(Intent.EXTRA_EPHEMERAL_TOKEN, token);
- intent.putExtra(Intent.EXTRA_EPHEMERAL_HOSTNAME, origIntent.getData().getHost());
+ if (token != null) {
+ intent.putExtra(Intent.EXTRA_EPHEMERAL_TOKEN, token);
+ }
+ if (origIntent.getData() != null) {
+ intent.putExtra(Intent.EXTRA_EPHEMERAL_HOSTNAME, origIntent.getData().getHost());
+ }
+ // We have all of the data we need; just start the installer without a second phase
if (!needsPhaseTwo) {
- // We have all of the data we need; just start the installer without a second phase
- final Intent nonEphemeralIntent = new Intent(origIntent);
- nonEphemeralIntent.setFlags(
- nonEphemeralIntent.getFlags() | Intent.FLAG_IGNORE_EPHEMERAL);
- // Intent that is launched if the ephemeral package couldn't be installed
- // for any reason.
+ // Intent that is launched if the package couldn't be installed for any reason.
+ final Intent failureIntent = new Intent(origIntent);
+ failureIntent.setFlags(failureIntent.getFlags() | Intent.FLAG_IGNORE_EPHEMERAL);
try {
- final IIntentSender failureIntentTarget = ActivityManagerNative.getDefault()
+ final IIntentSender failureIntentTarget = ActivityManager.getService()
.getIntentSender(
ActivityManager.INTENT_SENDER_ACTIVITY, callingPackage,
null /*token*/, null /*resultWho*/, 1 /*requestCode*/,
- new Intent[] { nonEphemeralIntent },
+ new Intent[] { failureIntent },
new String[] { resolvedType },
PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_ONE_SHOT
| PendingIntent.FLAG_IMMUTABLE,
@@ -163,19 +169,14 @@
new IntentSender(failureIntentTarget));
} catch (RemoteException ignore) { /* ignore; same process */ }
- // Success intent goes back to the installer
- final Intent ephemeralIntent = new Intent(launchIntent)
- .setComponent(null)
- .setPackage(ephemeralPackageName);
- // Intent that is eventually launched if the ephemeral package was
- // installed successfully. This will actually be launched by a platform
- // broadcast receiver.
+ // Intent that is launched if the package was installed successfully.
+ final Intent successIntent = new Intent(origIntent);
try {
- final IIntentSender successIntentTarget = ActivityManagerNative.getDefault()
+ final IIntentSender successIntentTarget = ActivityManager.getService()
.getIntentSender(
ActivityManager.INTENT_SENDER_ACTIVITY, callingPackage,
null /*token*/, null /*resultWho*/, 0 /*requestCode*/,
- new Intent[] { ephemeralIntent },
+ new Intent[] { successIntent },
new String[] { resolvedType },
PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_ONE_SHOT
| PendingIntent.FLAG_IMMUTABLE,
@@ -192,7 +193,7 @@
return intent;
}
- private static EphemeralResponse filterEphemeralIntent(
+ private static AuxiliaryResolveInfo filterEphemeralIntent(
List<EphemeralResolveInfo> ephemeralResolveInfoList,
Intent intent, String resolvedType, int userId, String packageName,
EphemeralDigest digest, String token) {
@@ -212,7 +213,7 @@
ephemeralInfo.getIntentFilters();
// No filters; we need to start phase two
if (ephemeralFilters == null || ephemeralFilters.isEmpty()) {
- return new EphemeralResponse(ephemeralInfo,
+ return new AuxiliaryResolveInfo(ephemeralInfo,
new IntentFilter(Intent.ACTION_VIEW) /*intentFilter*/,
null /*splitName*/, token, true /*needsPhase2*/);
}
@@ -226,14 +227,14 @@
continue;
}
for (int k = splitFilters.size() - 1; k >= 0; --k) {
- final EphemeralResponse intentInfo =
- new EphemeralResponse(ephemeralInfo,
+ final AuxiliaryResolveInfo intentInfo =
+ new AuxiliaryResolveInfo(ephemeralInfo,
splitFilters.get(k), ephemeralFilter.getSplitName(),
token, false /*needsPhase2*/);
ephemeralResolver.addFilter(intentInfo);
}
}
- List<EphemeralResponse> matchedResolveInfoList = ephemeralResolver.queryIntent(
+ List<AuxiliaryResolveInfo> matchedResolveInfoList = ephemeralResolver.queryIntent(
intent, resolvedType, false /*defaultOnly*/, userId);
if (!matchedResolveInfoList.isEmpty()) {
return matchedResolveInfoList.get(0);
diff --git a/services/core/java/com/android/server/pm/EphemeralResolverConnection.java b/services/core/java/com/android/server/pm/EphemeralResolverConnection.java
index 2b6ce10..7f5973e 100644
--- a/services/core/java/com/android/server/pm/EphemeralResolverConnection.java
+++ b/services/core/java/com/android/server/pm/EphemeralResolverConnection.java
@@ -23,7 +23,6 @@
import android.content.Intent;
import android.content.ServiceConnection;
import android.content.pm.EphemeralResolveInfo;
-import android.content.pm.EphemeralResponse;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
diff --git a/services/core/java/com/android/server/pm/InstantAppRegistry.java b/services/core/java/com/android/server/pm/InstantAppRegistry.java
index 55a5f72..0ae5f31 100644
--- a/services/core/java/com/android/server/pm/InstantAppRegistry.java
+++ b/services/core/java/com/android/server/pm/InstantAppRegistry.java
@@ -438,6 +438,7 @@
bitmap = Bitmap.createBitmap(icon.getIntrinsicWidth(),
icon.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
+ icon.setBounds(0, 0, icon.getIntrinsicWidth(), icon.getIntrinsicHeight());
icon.draw(canvas);
}
diff --git a/services/core/java/com/android/server/pm/LauncherAppsService.java b/services/core/java/com/android/server/pm/LauncherAppsService.java
index 96a2577..71bfa64 100644
--- a/services/core/java/com/android/server/pm/LauncherAppsService.java
+++ b/services/core/java/com/android/server/pm/LauncherAppsService.java
@@ -242,6 +242,12 @@
try {
UserInfo callingUserInfo = mUm.getUserInfo(callingUserId);
if (callingUserInfo.isManagedProfile()) {
+
+ // STOPSHIP Remove the whitelist.
+ if ("com.google.android.talk".equals(callingPackage)
+ || "com.google.android.quicksearchbox".equals(callingPackage)) {
+ return false;
+ }
Slog.wtfStack(TAG, message + " by " + callingPackage + " for another profile "
+ targetUserId + " from " + callingUserId);
@@ -436,8 +442,8 @@
@Override
public ParceledListSlice getShortcuts(String callingPackage, long changedSince,
- String packageName, List shortcutIds, ComponentName componentName, int flags,
- UserHandle targetUser) {
+ String packageName, List shortcutIds, ComponentName componentName, Intent intent,
+ int flags, UserHandle targetUser) {
ensureShortcutPermission(callingPackage);
if (!canAccessProfile(callingPackage, targetUser, "Cannot get shortcuts")
|| !isUserEnabled(targetUser)) {
@@ -448,11 +454,17 @@
"To query by shortcut ID, package name must also be set");
}
+ if ((flags & ShortcutQuery.FLAG_MATCH_CHOOSER) == 0
+ && intent != null) {
+ throw new IllegalArgumentException("Supplied an intent in the query, but did "
+ + "not request chooser targets");
+ }
+
// TODO(b/29399275): Eclipse compiler requires explicit List<ShortcutInfo> cast below.
return new ParceledListSlice<>((List<ShortcutInfo>)
mShortcutServiceInternal.getShortcuts(getCallingUserId(),
callingPackage, changedSince, packageName, shortcutIds,
- componentName, flags, targetUser.getIdentifier()));
+ componentName, intent, flags, targetUser.getIdentifier()));
}
@Override
@@ -900,6 +912,7 @@
cookie.packageName,
/* changedSince= */ 0, packageName, /* shortcutIds=*/ null,
/* component= */ null,
+ /* intent= */ null,
ShortcutQuery.FLAG_GET_KEY_FIELDS_ONLY
| ShortcutQuery.FLAG_GET_ALL_KINDS
, userId);
diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java
index 53765f2..37f78b4 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerService.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerService.java
@@ -88,6 +88,7 @@
import com.android.internal.R;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.content.PackageHelper;
+import com.android.internal.notification.SystemNotificationChannels;
import com.android.internal.util.FastXmlSerializer;
import com.android.internal.util.ImageUtils;
import com.android.internal.util.IndentingPrintWriter;
@@ -607,6 +608,12 @@
+ "to use the PackageManager.INSTALL_GRANT_RUNTIME_PERMISSIONS flag");
}
+ if ((params.installFlags & PackageManager.INSTALL_FORWARD_LOCK) != 0
+ || (params.installFlags & PackageManager.INSTALL_EXTERNAL) != 0) {
+ throw new IllegalArgumentException(
+ "New installs into ASEC containers no longer supported");
+ }
+
// Defensively resize giant app icons
if (params.appIcon != null) {
final ActivityManager am = (ActivityManager) mContext.getSystemService(
@@ -1097,7 +1104,7 @@
context.getResources().getDimensionPixelSize(
android.R.dimen.notification_large_icon_height));
CharSequence packageLabel = packageInfo.applicationInfo.loadLabel(pm);
- return new Notification.Builder(context)
+ return new Notification.Builder(context, SystemNotificationChannels.DEVICE_ADMIN)
.setSmallIcon(R.drawable.ic_check_circle_24px)
.setColor(context.getResources().getColor(
R.color.system_notification_accent_color))
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index 1c5675a..fd731c3 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -29,6 +29,7 @@
import static com.android.server.pm.PackageInstallerService.prepareStageDir;
import android.app.admin.DevicePolicyManager;
+import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentSender;
@@ -45,6 +46,7 @@
import android.content.pm.PackageParser.PackageLite;
import android.content.pm.PackageParser.PackageParserException;
import android.content.pm.Signature;
+import android.content.pm.UserInfo;
import android.os.Binder;
import android.os.Bundle;
import android.os.FileBridge;
@@ -295,6 +297,7 @@
info.active = mActiveCount.get() > 0;
info.mode = params.mode;
+ info.installReason = params.installReason;
info.sizeBytes = params.sizeBytes;
info.appPackageName = params.appPackageName;
info.appIcon = params.appIcon;
@@ -1139,6 +1142,25 @@
}
final boolean success = (returnCode == PackageManager.INSTALL_SUCCEEDED);
+
+ // Send broadcast to default launcher only if it's a new install
+ final boolean isNewInstall = extras == null || !extras.getBoolean(Intent.EXTRA_REPLACING);
+ if (success && isNewInstall) {
+ UserManagerService ums = UserManagerService.getInstance();
+ if (ums != null) {
+ final UserInfo parent = ums.getProfileParent(userId);
+ final int launcherUid = (parent != null) ? parent.id : userId;
+ final ComponentName launcherComponent = mPm.getDefaultHomeActivity(launcherUid);
+ if (launcherComponent != null) {
+ Intent launcherIntent = new Intent(PackageInstaller.ACTION_SESSION_COMMITTED)
+ .putExtra(PackageInstaller.EXTRA_SESSION, generateInfo())
+ .putExtra(Intent.EXTRA_USER, UserHandle.of(userId))
+ .setPackage(launcherComponent.getPackageName());
+ mContext.sendBroadcastAsUser(launcherIntent, UserHandle.of(launcherUid));
+ }
+ }
+ }
+
mCallback.onSessionFinished(this, success);
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index e447072..8380983 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -128,10 +128,9 @@
import android.content.pm.AppsQueryHelper;
import android.content.pm.ChangedPackages;
import android.content.pm.ComponentInfo;
-import android.content.pm.InstantAppInfo;
import android.content.pm.EphemeralRequest;
import android.content.pm.EphemeralResolveInfo;
-import android.content.pm.EphemeralResponse;
+import android.content.pm.AuxiliaryResolveInfo;
import android.content.pm.FallbackCategoryProvider;
import android.content.pm.FeatureInfo;
import android.content.pm.IOnPermissionsChangeListener;
@@ -143,6 +142,7 @@
import android.content.pm.IPackageManager;
import android.content.pm.IPackageMoveObserver;
import android.content.pm.IPackageStatsObserver;
+import android.content.pm.InstantAppInfo;
import android.content.pm.InstrumentationInfo;
import android.content.pm.IntentFilterVerificationInfo;
import android.content.pm.KeySet;
@@ -204,15 +204,16 @@
import android.os.UserManager;
import android.os.UserManagerInternal;
import android.os.storage.IStorageManager;
-import android.os.storage.StorageManagerInternal;
import android.os.storage.StorageEventListener;
import android.os.storage.StorageManager;
+import android.os.storage.StorageManagerInternal;
import android.os.storage.VolumeInfo;
import android.os.storage.VolumeRecord;
import android.provider.Settings.Global;
import android.provider.Settings.Secure;
import android.security.KeyStore;
import android.security.SystemKeyStore;
+import android.service.pm.PackageServiceDumpProto;
import android.system.ErrnoException;
import android.system.Os;
import android.text.TextUtils;
@@ -235,6 +236,7 @@
import android.util.SparseIntArray;
import android.util.Xml;
import android.util.jar.StrictJarFile;
+import android.util.proto.ProtoOutputStream;
import android.view.Display;
import com.android.internal.R;
@@ -251,6 +253,7 @@
import com.android.internal.os.Zygote;
import com.android.internal.telephony.CarrierAppUtils;
import com.android.internal.util.ArrayUtils;
+import com.android.internal.util.ConcurrentUtils;
import com.android.internal.util.FastPrintWriter;
import com.android.internal.util.FastXmlSerializer;
import com.android.internal.util.IndentingPrintWriter;
@@ -265,6 +268,7 @@
import com.android.server.LocalServices;
import com.android.server.ServiceThread;
import com.android.server.SystemConfig;
+import com.android.server.SystemServerInitThreadPool;
import com.android.server.Watchdog;
import com.android.server.net.NetworkPolicyManagerInternal;
import com.android.server.pm.Installer.InstallerException;
@@ -314,14 +318,15 @@
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
-import java.util.HashSet;
import java.util.HashMap;
+import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
@@ -577,7 +582,8 @@
Manifest.permission.RECEIVE_MMS,
Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.WRITE_EXTERNAL_STORAGE,
- Manifest.permission.READ_PHONE_NUMBER);
+ Manifest.permission.READ_PHONE_NUMBER,
+ Manifest.permission.ANSWER_PHONE_CALLS);
/**
@@ -658,9 +664,12 @@
final ArrayMap<String, Set<String>> mKnownCodebase =
new ArrayMap<String, Set<String>>();
- // Tracks available target package names -> overlay package paths.
- final ArrayMap<String, ArrayMap<String, PackageParser.Package>> mOverlays =
- new ArrayMap<String, ArrayMap<String, PackageParser.Package>>();
+ // List of APK paths to load for each user and package. This data is never
+ // persisted by the package manager. Instead, the overlay manager will
+ // ensure the data is up-to-date in runtime.
+ @GuardedBy("mPackages")
+ final SparseArray<ArrayMap<String, ArrayList<String>>> mEnabledOverlayPaths =
+ new SparseArray<ArrayMap<String, ArrayList<String>>>();
/**
* Tracks new system packages [received in an OTA] that we expect to
@@ -834,12 +843,12 @@
private int mIntentFilterVerificationToken = 0;
/** The service connection to the ephemeral resolver */
- final EphemeralResolverConnection mEphemeralResolverConnection;
+ final EphemeralResolverConnection mInstantAppResolverConnection;
/** Component used to install ephemeral applications */
- ComponentName mEphemeralInstallerComponent;
- final ActivityInfo mEphemeralInstallerActivity = new ActivityInfo();
- final ResolveInfo mEphemeralInstallerInfo = new ResolveInfo();
+ ComponentName mInstantAppInstallerComponent;
+ final ActivityInfo mInstantAppInstallerActivity = new ActivityInfo();
+ final ResolveInfo mInstantAppInstallerInfo = new ResolveInfo();
final SparseArray<IntentFilterVerificationState> mIntentFilterVerificationStates
= new SparseArray<IntentFilterVerificationState>();
@@ -857,6 +866,8 @@
private ArraySet<String> mPrivappPermissionsViolations;
+ private Future<?> mPrepareAppDataFuture;
+
private static class IFVerificationParams {
PackageParser.Package pkg;
boolean replacing;
@@ -1159,7 +1170,7 @@
static final int START_INTENT_FILTER_VERIFICATIONS = 17;
static final int INTENT_FILTER_VERIFIED = 18;
static final int WRITE_PACKAGE_LIST = 19;
- static final int EPHEMERAL_RESOLUTION_PHASE_TWO = 20;
+ static final int INSTANT_APP_RESOLUTION_PHASE_TWO = 20;
static final int WRITE_SETTINGS_DELAY = 10*1000; // 10 seconds
@@ -1730,11 +1741,11 @@
break;
}
- case EPHEMERAL_RESOLUTION_PHASE_TWO: {
+ case INSTANT_APP_RESOLUTION_PHASE_TWO: {
EphemeralResolver.doEphemeralResolutionPhaseTwo(mContext,
- mEphemeralResolverConnection,
+ mInstantAppResolverConnection,
(EphemeralRequest) msg.obj,
- mEphemeralInstallerActivity,
+ mInstantAppInstallerActivity,
mHandler);
}
}
@@ -2757,8 +2768,32 @@
} else {
storageFlags = StorageManager.FLAG_STORAGE_DE | StorageManager.FLAG_STORAGE_CE;
}
- reconcileAppsDataLI(StorageManager.UUID_PRIVATE_INTERNAL, UserHandle.USER_SYSTEM,
- storageFlags, true /* migrateAppData */);
+ List<String> deferPackages = reconcileAppsDataLI(StorageManager.UUID_PRIVATE_INTERNAL,
+ UserHandle.USER_SYSTEM, storageFlags, true /* migrateAppData */,
+ true /* onlyCoreApps */);
+ mPrepareAppDataFuture = SystemServerInitThreadPool.get().submit(() -> {
+ if (deferPackages == null || deferPackages.isEmpty()) {
+ return;
+ }
+ int count = 0;
+ for (String pkgName : deferPackages) {
+ PackageParser.Package pkg = null;
+ synchronized (mPackages) {
+ PackageSetting ps = mSettings.getPackageLPr(pkgName);
+ if (ps != null && ps.getInstalled(UserHandle.USER_SYSTEM)) {
+ pkg = ps.pkg;
+ }
+ }
+ if (pkg != null) {
+ synchronized (mInstallLock) {
+ prepareAppDataAndMigrateLIF(pkg, UserHandle.USER_SYSTEM, storageFlags,
+ true /* maybeMigrateAppData */);
+ }
+ count++;
+ }
+ }
+ Slog.i(TAG, "Deferred reconcileAppsData finished " + count + " packages");
+ }, "prepareAppData");
// If this is first boot after an OTA, and a normal boot, then
// we need to clear code cache directories.
@@ -2861,17 +2896,17 @@
if (DEBUG_EPHEMERAL) {
Slog.i(TAG, "Ephemeral resolver: " + ephemeralResolverComponent);
}
- mEphemeralResolverConnection =
+ mInstantAppResolverConnection =
new EphemeralResolverConnection(mContext, ephemeralResolverComponent);
} else {
- mEphemeralResolverConnection = null;
+ mInstantAppResolverConnection = null;
}
- mEphemeralInstallerComponent = getEphemeralInstallerLPr();
- if (mEphemeralInstallerComponent != null) {
+ mInstantAppInstallerComponent = getEphemeralInstallerLPr();
+ if (mInstantAppInstallerComponent != null) {
if (DEBUG_EPHEMERAL) {
- Slog.i(TAG, "Ephemeral installer: " + mEphemeralInstallerComponent);
+ Slog.i(TAG, "Ephemeral installer: " + mInstantAppInstallerComponent);
}
- setUpEphemeralInstallerActivityLP(mEphemeralInstallerComponent);
+ setUpInstantAppInstallerActivityLP(mInstantAppInstallerComponent);
}
// Read and update the usage of dex files.
@@ -3705,6 +3740,7 @@
ApplicationInfo ai = PackageParser.generateApplicationInfo(ps.pkg, flags,
ps.readUserState(userId), userId);
if (ai != null) {
+ rebaseEnabledOverlays(ai, userId);
ai.packageName = resolveExternalPackageNameLPr(ps.pkg);
}
return ai;
@@ -3739,6 +3775,7 @@
ApplicationInfo ai = PackageParser.generateApplicationInfo(
p, flags, ps.readUserState(userId), userId);
if (ai != null) {
+ rebaseEnabledOverlays(ai, userId);
ai.packageName = resolveExternalPackageNameLPr(p);
}
return ai;
@@ -3755,6 +3792,26 @@
return null;
}
+ private void rebaseEnabledOverlays(@NonNull ApplicationInfo ai, int userId) {
+ List<String> paths = new ArrayList<>();
+ ArrayMap<String, ArrayList<String>> userSpecificOverlays =
+ mEnabledOverlayPaths.get(userId);
+ if (userSpecificOverlays != null) {
+ if (!"android".equals(ai.packageName)) {
+ ArrayList<String> frameworkOverlays = userSpecificOverlays.get("android");
+ if (frameworkOverlays != null) {
+ paths.addAll(frameworkOverlays);
+ }
+ }
+
+ ArrayList<String> appOverlays = userSpecificOverlays.get(ai.packageName);
+ if (appOverlays != null) {
+ paths.addAll(appOverlays);
+ }
+ }
+ ai.resourceDirs = paths.size() > 0 ? paths.toArray(new String[paths.size()]) : null;
+ }
+
private String normalizePackageNameLPr(String packageName) {
String normalizedPackageName = mSettings.getRenamedPackageLPr(packageName);
return normalizedPackageName != null ? normalizedPackageName : packageName;
@@ -3983,8 +4040,17 @@
/**
* Update given flags when being used to request {@link ResolveInfo}.
+ * <p>Instant apps are resolved specially, depending upon context. Minimally,
+ * {@code}flags{@code} must have the {@link PackageManager#MATCH_INSTANT}
+ * flag set. However, this flag is only honoured in three circumstances:
+ * <ul>
+ * <li>when called from a system process</li>
+ * <li>when the caller holds the permission {@code android.permission.ACCESS_INSTANT_APPS}</li>
+ * <li>when resolution occurs to start an activity with a {@code android.intent.action.VIEW}
+ * action and a {@code android.intent.category.BROWSABLE} category</li>
+ * </ul>
*/
- int updateFlagsForResolve(int flags, int userId, Object cookie) {
+ int updateFlagsForResolve(int flags, int userId, Intent intent, boolean includeInstantApp) {
// Safe mode means we shouldn't match any third-party components
if (mSafeMode) {
flags |= PackageManager.MATCH_SYSTEM_ONLY;
@@ -3996,13 +4062,24 @@
flags |= PackageManager.MATCH_INSTANT;
} else {
// Otherwise, prevent leaking ephemeral components
+ final boolean isSpecialProcess =
+ callingUid == Process.SYSTEM_UID
+ || callingUid == Process.SHELL_UID
+ || callingUid == 0;
+ final boolean allowMatchInstant =
+ (includeInstantApp
+ && Intent.ACTION_VIEW.equals(intent.getAction())
+ && intent.hasCategory(Intent.CATEGORY_BROWSABLE)
+ && hasWebURI(intent))
+ || isSpecialProcess
+ || mContext.checkCallingOrSelfPermission(
+ android.Manifest.permission.ACCESS_INSTANT_APPS) == PERMISSION_GRANTED;
flags &= ~PackageManager.MATCH_VISIBLE_TO_INSTANT_APP_ONLY;
- if (callingUid != Process.SYSTEM_UID && callingUid != 0) {
- // Unless called from the system process
+ if (!allowMatchInstant) {
flags &= ~PackageManager.MATCH_INSTANT;
}
}
- return updateFlagsForComponent(flags, userId, cookie);
+ return updateFlagsForComponent(flags, userId, intent /*cookie*/);
}
@Override
@@ -5527,17 +5604,23 @@
@Override
public ResolveInfo resolveIntent(Intent intent, String resolvedType,
int flags, int userId) {
+ return resolveIntentInternal(
+ intent, resolvedType, flags, userId, false /*includeInstantApp*/);
+ }
+
+ private ResolveInfo resolveIntentInternal(Intent intent, String resolvedType,
+ int flags, int userId, boolean includeInstantApp) {
try {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "resolveIntent");
if (!sUserManager.exists(userId)) return null;
- flags = updateFlagsForResolve(flags, userId, intent);
+ flags = updateFlagsForResolve(flags, userId, intent, includeInstantApp);
enforceCrossUserPermission(Binder.getCallingUid(), userId,
false /*requireFullPermission*/, false /*checkShell*/, "resolve intent");
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "queryIntentActivities");
final List<ResolveInfo> query = queryIntentActivitiesInternal(intent, resolvedType,
- flags, userId);
+ flags, userId, includeInstantApp);
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
final ResolveInfo bestChoice =
@@ -5559,7 +5642,7 @@
}
intent = updateIntentForResolve(intent);
final String resolvedType = intent.resolveTypeIfNeeded(mContext.getContentResolver());
- final int flags = updateFlagsForResolve(0, userId, intent);
+ final int flags = updateFlagsForResolve(0, userId, intent, false);
final List<ResolveInfo> query = queryIntentActivitiesInternal(intent, resolvedType, flags,
userId);
synchronized (mPackages) {
@@ -5602,6 +5685,11 @@
false, false, false, userId);
}
+ /**
+ * Returns whether or not instant apps have been disabled remotely.
+ * <p><em>IMPORTANT</em> This should not be called with the package manager lock
+ * held. Otherwise we run the risk of deadlock.
+ */
private boolean isEphemeralDisabled() {
// ephemeral apps have been disabled across the board
if (DISABLE_EPHEMERAL_APPS) {
@@ -5622,18 +5710,14 @@
private boolean isEphemeralAllowed(
Intent intent, List<ResolveInfo> resolvedActivities, int userId,
boolean skipPackageCheck) {
- // Short circuit and return early if possible.
- if (isEphemeralDisabled()) {
- return false;
- }
final int callingUser = UserHandle.getCallingUserId();
if (callingUser != UserHandle.USER_SYSTEM) {
return false;
}
- if (mEphemeralResolverConnection == null) {
+ if (mInstantAppResolverConnection == null) {
return false;
}
- if (mEphemeralInstallerComponent == null) {
+ if (mInstantAppInstallerComponent == null) {
return false;
}
if (intent.getComponent() != null) {
@@ -5650,6 +5734,7 @@
return false;
}
// Deny ephemeral apps if the user chose _ALWAYS or _ALWAYS_ASK for intent resolution.
+ // Or if there's already an ephemeral app installed that handles the action
synchronized (mPackages) {
final int count = (resolvedActivities == null ? 0 : resolvedActivities.size());
for (int n = 0; n < count; n++) {
@@ -5668,6 +5753,9 @@
}
return false;
}
+ if (ps.getInstantApp(userId)) {
+ return false;
+ }
}
}
}
@@ -5675,11 +5763,11 @@
return true;
}
- private void requestEphemeralResolutionPhaseTwo(EphemeralResponse responseObj,
- Intent origIntent, String resolvedType, Intent launchIntent, String callingPackage,
+ private void requestInstantAppResolutionPhaseTwo(AuxiliaryResolveInfo responseObj,
+ Intent origIntent, String resolvedType, String callingPackage,
int userId) {
- final Message msg = mHandler.obtainMessage(EPHEMERAL_RESOLUTION_PHASE_TWO,
- new EphemeralRequest(responseObj, origIntent, resolvedType, launchIntent,
+ final Message msg = mHandler.obtainMessage(INSTANT_APP_RESOLUTION_PHASE_TWO,
+ new EphemeralRequest(responseObj, origIntent, resolvedType,
callingPackage, userId));
mHandler.sendMessage(msg);
}
@@ -5714,6 +5802,13 @@
if (ri != null) {
return ri;
}
+ // If we have an ephemeral app, use it
+ for (int i = 0; i < N; i++) {
+ ri = query.get(i);
+ if (ri.activityInfo.applicationInfo.isInstantApp()) {
+ return ri;
+ }
+ }
ri = new ResolveInfo(mResolveInfo);
ri.activityInfo = new ActivityInfo(ri.activityInfo);
ri.activityInfo.labelRes = ResolverActivity.getLabelRes(intent.getAction());
@@ -5832,7 +5927,7 @@
List<ResolveInfo> query, int priority, boolean always,
boolean removeMatches, boolean debug, int userId) {
if (!sUserManager.exists(userId)) return null;
- flags = updateFlagsForResolve(flags, userId, intent);
+ flags = updateFlagsForResolve(flags, userId, intent, false);
intent = updateIntentForResolve(intent);
// writer
synchronized (mPackages) {
@@ -6000,7 +6095,7 @@
// cross-profile app linking works only towards the parent.
final UserInfo parent = getProfileParent(sourceUserId);
synchronized(mPackages) {
- int flags = updateFlagsForResolve(0, parent.id, intent);
+ int flags = updateFlagsForResolve(0, parent.id, intent, false);
CrossProfileDomainInfo xpDomainInfo = getCrossProfileDomainPreferredLpr(
intent, resolvedType, flags, sourceUserId, parent.id);
return xpDomainInfo != null;
@@ -6059,9 +6154,14 @@
private @NonNull List<ResolveInfo> queryIntentActivitiesInternal(Intent intent,
String resolvedType, int flags, int userId) {
+ return queryIntentActivitiesInternal(intent, resolvedType, flags, userId, false);
+ }
+
+ private @NonNull List<ResolveInfo> queryIntentActivitiesInternal(Intent intent,
+ String resolvedType, int flags, int userId, boolean includeInstantApp) {
if (!sUserManager.exists(userId)) return Collections.emptyList();
final String instantAppPkgName = getInstantAppPackageName(Binder.getCallingUid());
- flags = updateFlagsForResolve(flags, userId, intent);
+ flags = updateFlagsForResolve(flags, userId, intent, includeInstantApp);
enforceCrossUserPermission(Binder.getCallingUid(), userId,
false /* requireFullPermission */, false /* checkShell */,
"query intent activities");
@@ -6105,7 +6205,7 @@
list.add(ri);
}
}
- return list;
+ return applyPostResolutionFilter(list, instantAppPkgName);
}
// reader
@@ -6113,6 +6213,7 @@
boolean addEphemeral = false;
List<ResolveInfo> result;
final String pkgName = intent.getPackage();
+ final boolean ephemeralDisabled = isEphemeralDisabled();
synchronized (mPackages) {
if (pkgName == null) {
List<CrossProfileIntentFilter> matchingFilters =
@@ -6123,15 +6224,15 @@
if (xpResolveInfo != null) {
List<ResolveInfo> xpResult = new ArrayList<ResolveInfo>(1);
xpResult.add(xpResolveInfo);
- return filterForEphemeral(
+ return applyPostResolutionFilter(
filterIfNotSystemUser(xpResult, userId), instantAppPkgName);
}
// Check for results in the current profile.
result = filterIfNotSystemUser(mActivities.queryIntent(
intent, resolvedType, flags, userId), userId);
- addEphemeral =
- isEphemeralAllowed(intent, result, userId, false /*skipPackageCheck*/);
+ addEphemeral = !ephemeralDisabled
+ && isEphemeralAllowed(intent, result, userId, false /*skipPackageCheck*/);
// Check for cross profile results.
boolean hasNonNegativePriorityResult = hasNonNegativePriority(result);
@@ -6164,13 +6265,13 @@
// And we are not going to add emphemeral app, so we can return the
// result straight away.
result.add(xpDomainInfo.resolveInfo);
- return filterForEphemeral(result, instantAppPkgName);
+ return applyPostResolutionFilter(result, instantAppPkgName);
}
} else if (result.size() <= 1 && !addEphemeral) {
// No result in parent user and <= 1 result in current profile, and we
// are not going to add emphemeral app, so we can return the result without
// further processing.
- return filterForEphemeral(result, instantAppPkgName);
+ return applyPostResolutionFilter(result, instantAppPkgName);
}
// We have more than one candidate (combining results from current and parent
// profile), so we need filtering and sorting.
@@ -6181,15 +6282,16 @@
} else {
final PackageParser.Package pkg = mPackages.get(pkgName);
if (pkg != null) {
- result = filterForEphemeral(filterIfNotSystemUser(
+ result = applyPostResolutionFilter(filterIfNotSystemUser(
mActivities.queryIntentForPackage(
intent, resolvedType, flags, pkg.activities, userId),
userId), instantAppPkgName);
} else {
// the caller wants to resolve for a particular package; however, there
// were no installed results, so, try to find an ephemeral result
- addEphemeral = isEphemeralAllowed(
- intent, null /*result*/, userId, true /*skipPackageCheck*/);
+ addEphemeral = !ephemeralDisabled
+ && isEphemeralAllowed(
+ intent, null /*result*/, userId, true /*skipPackageCheck*/);
result = new ArrayList<ResolveInfo>();
}
}
@@ -6198,15 +6300,16 @@
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "resolveEphemeral");
final EphemeralRequest requestObject = new EphemeralRequest(
null /*responseObj*/, intent /*origIntent*/, resolvedType,
- null /*launchIntent*/, null /*callingPackage*/, userId);
- final EphemeralResponse intentInfo = EphemeralResolver.doEphemeralResolutionPhaseOne(
- mContext, mEphemeralResolverConnection, requestObject);
- if (intentInfo != null) {
+ null /*callingPackage*/, userId);
+ final AuxiliaryResolveInfo auxiliaryResponse =
+ EphemeralResolver.doEphemeralResolutionPhaseOne(
+ mContext, mInstantAppResolverConnection, requestObject);
+ if (auxiliaryResponse != null) {
if (DEBUG_EPHEMERAL) {
Slog.v(TAG, "Adding ephemeral installer to the ResolveInfo list");
}
- final ResolveInfo ephemeralInstaller = new ResolveInfo(mEphemeralInstallerInfo);
- ephemeralInstaller.ephemeralResponse = intentInfo;
+ final ResolveInfo ephemeralInstaller = new ResolveInfo(mInstantAppInstallerInfo);
+ ephemeralInstaller.auxiliaryInfo = auxiliaryResponse;
// make sure this resolver is the default
ephemeralInstaller.isDefault = true;
ephemeralInstaller.match = IntentFilter.MATCH_CATEGORY_SCHEME_SPECIFIC_PART
@@ -6215,6 +6318,7 @@
ephemeralInstaller.filter = new IntentFilter(intent.getAction());
ephemeralInstaller.filter.addDataPath(
intent.getData().getPath(), PatternMatcher.PATTERN_LITERAL);
+ ephemeralInstaller.instantAppAvailable = true;
result.add(ephemeralInstaller);
}
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
@@ -6222,7 +6326,7 @@
if (sortResult) {
Collections.sort(result, mResolvePrioritySorter);
}
- return filterForEphemeral(result, instantAppPkgName);
+ return applyPostResolutionFilter(result, instantAppPkgName);
}
private static class CrossProfileDomainInfo {
@@ -6330,16 +6434,40 @@
* is performed.
* @return A filtered list of resolved activities.
*/
- private List<ResolveInfo> filterForEphemeral(List<ResolveInfo> resolveInfos,
+ private List<ResolveInfo> applyPostResolutionFilter(List<ResolveInfo> resolveInfos,
String ephemeralPkgName) {
+ // TODO: When adding on-demand split support for non-instant apps, remove this check
+ // and always apply post filtering
if (ephemeralPkgName == null) {
return resolveInfos;
}
for (int i = resolveInfos.size() - 1; i >= 0; i--) {
- ResolveInfo info = resolveInfos.get(i);
+ final ResolveInfo info = resolveInfos.get(i);
final boolean isEphemeralApp = info.activityInfo.applicationInfo.isInstantApp();
// allow activities that are defined in the provided package
if (isEphemeralApp && ephemeralPkgName.equals(info.activityInfo.packageName)) {
+ if (info.activityInfo.splitName != null
+ && !ArrayUtils.contains(info.activityInfo.applicationInfo.splitNames,
+ info.activityInfo.splitName)) {
+ // requested activity is defined in a split that hasn't been installed yet.
+ // add the installer to the resolve list
+ if (DEBUG_EPHEMERAL) {
+ Slog.v(TAG, "Adding ephemeral installer to the ResolveInfo list");
+ }
+ final ResolveInfo installerInfo = new ResolveInfo(mInstantAppInstallerInfo);
+ installerInfo.auxiliaryInfo = new AuxiliaryResolveInfo(
+ info.activityInfo.packageName, info.activityInfo.splitName,
+ info.activityInfo.applicationInfo.versionCode);
+ // make sure this resolver is the default
+ installerInfo.isDefault = true;
+ installerInfo.match = IntentFilter.MATCH_CATEGORY_SCHEME_SPECIFIC_PART
+ | IntentFilter.MATCH_ADJUSTMENT_NORMAL;
+ // add a non-generic filter
+ installerInfo.filter = new IntentFilter();
+ // load resources from the correct package
+ installerInfo.resolvePackageName = info.getComponentInfo().packageName;
+ resolveInfos.set(i, installerInfo);
+ }
continue;
}
// allow activities that have been explicitly exposed to ephemeral apps
@@ -6663,7 +6791,7 @@
Intent[] specifics, String[] specificTypes, Intent intent,
String resolvedType, int flags, int userId) {
if (!sUserManager.exists(userId)) return Collections.emptyList();
- flags = updateFlagsForResolve(flags, userId, intent);
+ flags = updateFlagsForResolve(flags, userId, intent, false);
enforceCrossUserPermission(Binder.getCallingUid(), userId,
false /* requireFullPermission */, false /* checkShell */,
"query intent activity options");
@@ -6843,7 +6971,7 @@
private @NonNull List<ResolveInfo> queryIntentReceiversInternal(Intent intent,
String resolvedType, int flags, int userId) {
if (!sUserManager.exists(userId)) return Collections.emptyList();
- flags = updateFlagsForResolve(flags, userId, intent);
+ flags = updateFlagsForResolve(flags, userId, intent, false);
ComponentName comp = intent.getComponent();
if (comp == null) {
if (intent.getSelector() != null) {
@@ -6880,7 +7008,7 @@
@Override
public ResolveInfo resolveService(Intent intent, String resolvedType, int flags, int userId) {
if (!sUserManager.exists(userId)) return null;
- flags = updateFlagsForResolve(flags, userId, intent);
+ flags = updateFlagsForResolve(flags, userId, intent, false);
List<ResolveInfo> query = queryIntentServicesInternal(intent, resolvedType, flags, userId);
if (query != null) {
if (query.size() >= 1) {
@@ -6902,7 +7030,7 @@
private @NonNull List<ResolveInfo> queryIntentServicesInternal(Intent intent,
String resolvedType, int flags, int userId) {
if (!sUserManager.exists(userId)) return Collections.emptyList();
- flags = updateFlagsForResolve(flags, userId, intent);
+ flags = updateFlagsForResolve(flags, userId, intent, false);
ComponentName comp = intent.getComponent();
if (comp == null) {
if (intent.getSelector() != null) {
@@ -6946,7 +7074,7 @@
private @NonNull List<ResolveInfo> queryIntentContentProvidersInternal(
Intent intent, String resolvedType, int flags, int userId) {
if (!sUserManager.exists(userId)) return Collections.emptyList();
- flags = updateFlagsForResolve(flags, userId, intent);
+ flags = updateFlagsForResolve(flags, userId, intent, false);
ComponentName comp = intent.getComponent();
if (comp == null) {
if (intent.getSelector() != null) {
@@ -7118,6 +7246,7 @@
ai = PackageParser.generateApplicationInfo(ps.pkg, effectiveFlags,
ps.readUserState(userId), userId);
if (ai != null) {
+ rebaseEnabledOverlays(ai, userId);
ai.packageName = resolveExternalPackageNameLPr(ps.pkg);
}
} else {
@@ -7141,6 +7270,7 @@
ApplicationInfo ai = PackageParser.generateApplicationInfo(p, flags,
ps.readUserState(userId), userId);
if (ai != null) {
+ rebaseEnabledOverlays(ai, userId);
ai.packageName = resolveExternalPackageNameLPr(p);
list.add(ai);
}
@@ -7182,12 +7312,17 @@
return false;
}
- if (!isCallerSameApp(packageName)) {
- return false;
- }
synchronized (mPackages) {
final PackageSetting ps = mSettings.mPackages.get(packageName);
- if (ps != null) {
+ final boolean returnAllowed =
+ ps != null
+ && (isCallerSameApp(packageName)
+ || mContext.checkCallingOrSelfPermission(
+ android.Manifest.permission.ACCESS_INSTANT_APPS)
+ == PERMISSION_GRANTED
+ || mInstantAppRegistry.isInstantAccessGranted(
+ userId, UserHandle.getAppId(Binder.getCallingUid()), ps.appId));
+ if (returnAllowed) {
return ps.getInstantApp(userId);
}
}
@@ -7284,6 +7419,7 @@
ApplicationInfo ai = PackageParser.generateApplicationInfo(p, flags,
ps.readUserState(userId), userId);
if (ai != null) {
+ rebaseEnabledOverlays(ai, userId);
finalList.add(ai);
}
}
@@ -7343,7 +7479,7 @@
@Override
public @NonNull ParceledListSlice<ProviderInfo> queryContentProviders(String processName,
- int uid, int flags) {
+ int uid, int flags, String metaDataKey) {
final int userId = processName != null ? UserHandle.getUserId(uid)
: UserHandle.getCallingUserId();
if (!sUserManager.exists(userId)) return ParceledListSlice.emptyList();
@@ -7361,6 +7497,14 @@
|| (p.info.processName.equals(processName)
&& UserHandle.isSameApp(p.info.applicationInfo.uid, uid)))
&& mSettings.isEnabledAndMatchLPr(p.info, flags, userId)) {
+
+ // See PM.queryContentProviders()'s javadoc for why we have the metaData
+ // parameter.
+ if (metaDataKey != null
+ && (p.metaData == null || !p.metaData.containsKey(metaDataKey))) {
+ continue;
+ }
+
if (finalList == null) {
finalList = new ArrayList<ProviderInfo>(3);
}
@@ -7419,60 +7563,6 @@
return finalList;
}
- private void createIdmapsForPackageLI(PackageParser.Package pkg) {
- ArrayMap<String, PackageParser.Package> overlays = mOverlays.get(pkg.packageName);
- if (overlays == null) {
- Slog.w(TAG, "Unable to create idmap for " + pkg.packageName + ": no overlay packages");
- return;
- }
- for (PackageParser.Package opkg : overlays.values()) {
- // Not much to do if idmap fails: we already logged the error
- // and we certainly don't want to abort installation of pkg simply
- // because an overlay didn't fit properly. For these reasons,
- // ignore the return value of createIdmapForPackagePairLI.
- createIdmapForPackagePairLI(pkg, opkg);
- }
- }
-
- private boolean createIdmapForPackagePairLI(PackageParser.Package pkg,
- PackageParser.Package opkg) {
- if (!opkg.mTrustedOverlay) {
- Slog.w(TAG, "Skipping target and overlay pair " + pkg.baseCodePath + " and " +
- opkg.baseCodePath + ": overlay not trusted");
- return false;
- }
- ArrayMap<String, PackageParser.Package> overlaySet = mOverlays.get(pkg.packageName);
- if (overlaySet == null) {
- Slog.e(TAG, "was about to create idmap for " + pkg.baseCodePath + " and " +
- opkg.baseCodePath + " but target package has no known overlays");
- return false;
- }
- final int sharedGid = UserHandle.getSharedAppGid(pkg.applicationInfo.uid);
- // TODO: generate idmap for split APKs
- try {
- mInstaller.idmap(pkg.baseCodePath, opkg.baseCodePath, sharedGid);
- } catch (InstallerException e) {
- Slog.e(TAG, "Failed to generate idmap for " + pkg.baseCodePath + " and "
- + opkg.baseCodePath);
- return false;
- }
- PackageParser.Package[] overlayArray =
- overlaySet.values().toArray(new PackageParser.Package[0]);
- Comparator<PackageParser.Package> cmp = new Comparator<PackageParser.Package>() {
- public int compare(PackageParser.Package p1, PackageParser.Package p2) {
- return p1.mOverlayPriority - p2.mOverlayPriority;
- }
- };
- Arrays.sort(overlayArray, cmp);
-
- pkg.applicationInfo.resourceDirs = new String[overlayArray.length];
- int i = 0;
- for (PackageParser.Package p : overlayArray) {
- pkg.applicationInfo.resourceDirs[i++] = p.baseCodePath;
- }
- return true;
- }
-
private void scanDirTracedLI(File dir, final int parseFlags, int scanFlags, long currentTime) {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "scanDir [" + dir.getAbsolutePath() + "]");
try {
@@ -9961,7 +10051,6 @@
// writer
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "updateSettings");
- boolean createIdmapFailed = false;
synchronized (mPackages) {
// We don't expect installation to fail beyond this point
@@ -10302,36 +10391,9 @@
mProtectedBroadcasts.add(pkg.protectedBroadcasts.get(i));
}
}
-
- // Create idmap files for pairs of (packages, overlay packages).
- // Note: "android", ie framework-res.apk, is handled by native layers.
- if (pkg.mOverlayTarget != null) {
- // This is an overlay package.
- if (pkg.mOverlayTarget != null && !pkg.mOverlayTarget.equals("android")) {
- if (!mOverlays.containsKey(pkg.mOverlayTarget)) {
- mOverlays.put(pkg.mOverlayTarget,
- new ArrayMap<String, PackageParser.Package>());
- }
- ArrayMap<String, PackageParser.Package> map = mOverlays.get(pkg.mOverlayTarget);
- map.put(pkg.packageName, pkg);
- PackageParser.Package orig = mPackages.get(pkg.mOverlayTarget);
- if (orig != null && !createIdmapForPackagePairLI(orig, pkg)) {
- createIdmapFailed = true;
- }
- }
- } else if (mOverlays.containsKey(pkg.packageName) &&
- !pkg.packageName.equals("android")) {
- // This is a regular package, with one or more known overlay packages.
- createIdmapsForPackageLI(pkg);
- }
}
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
-
- if (createIdmapFailed) {
- throw new PackageManagerException(INSTALL_FAILED_UPDATE_INCOMPATIBLE,
- "scanPackageLI failed to createIdmap");
- }
}
private static void maybeRenameForeignDexMarkers(PackageParser.Package existing,
@@ -10670,12 +10732,12 @@
}
}
- private void setUpEphemeralInstallerActivityLP(ComponentName installerComponent) {
+ private void setUpInstantAppInstallerActivityLP(ComponentName installerComponent) {
if (installerComponent == null) {
if (DEBUG_EPHEMERAL) {
Slog.d(TAG, "Clear ephemeral installer activity");
}
- mEphemeralInstallerActivity.applicationInfo = null;
+ mInstantAppInstallerActivity.applicationInfo = null;
return;
}
@@ -10684,21 +10746,21 @@
}
final PackageParser.Package pkg = mPackages.get(installerComponent.getPackageName());
// Set up information for ephemeral installer activity
- mEphemeralInstallerActivity.applicationInfo = pkg.applicationInfo;
- mEphemeralInstallerActivity.name = installerComponent.getClassName();
- mEphemeralInstallerActivity.packageName = pkg.applicationInfo.packageName;
- mEphemeralInstallerActivity.processName = pkg.applicationInfo.packageName;
- mEphemeralInstallerActivity.launchMode = ActivityInfo.LAUNCH_MULTIPLE;
- mEphemeralInstallerActivity.flags = ActivityInfo.FLAG_EXCLUDE_FROM_RECENTS
+ mInstantAppInstallerActivity.applicationInfo = pkg.applicationInfo;
+ mInstantAppInstallerActivity.name = installerComponent.getClassName();
+ mInstantAppInstallerActivity.packageName = pkg.applicationInfo.packageName;
+ mInstantAppInstallerActivity.processName = pkg.applicationInfo.packageName;
+ mInstantAppInstallerActivity.launchMode = ActivityInfo.LAUNCH_MULTIPLE;
+ mInstantAppInstallerActivity.flags = ActivityInfo.FLAG_EXCLUDE_FROM_RECENTS
| ActivityInfo.FLAG_FINISH_ON_CLOSE_SYSTEM_DIALOGS;
- mEphemeralInstallerActivity.theme = 0;
- mEphemeralInstallerActivity.exported = true;
- mEphemeralInstallerActivity.enabled = true;
- mEphemeralInstallerInfo.activityInfo = mEphemeralInstallerActivity;
- mEphemeralInstallerInfo.priority = 0;
- mEphemeralInstallerInfo.preferredOrder = 1;
- mEphemeralInstallerInfo.isDefault = true;
- mEphemeralInstallerInfo.match = IntentFilter.MATCH_CATEGORY_SCHEME_SPECIFIC_PART
+ mInstantAppInstallerActivity.theme = 0;
+ mInstantAppInstallerActivity.exported = true;
+ mInstantAppInstallerActivity.enabled = true;
+ mInstantAppInstallerInfo.activityInfo = mInstantAppInstallerActivity;
+ mInstantAppInstallerInfo.priority = 0;
+ mInstantAppInstallerInfo.preferredOrder = 1;
+ mInstantAppInstallerInfo.isDefault = true;
+ mInstantAppInstallerInfo.match = IntentFilter.MATCH_CATEGORY_SCHEME_SPECIFIC_PART
| IntentFilter.MATCH_ADJUSTMENT_NORMAL;
}
@@ -11656,7 +11718,8 @@
if (!whitelisted) {
Slog.w(TAG, "Privileged permission " + perm + " for package "
+ pkg.packageName + " - not in privapp-permissions whitelist");
- if (!mSystemReady) {
+ // Only report violations for apps on system image
+ if (!mSystemReady && !pkg.isUpdatedSystemApp()) {
if (mPrivappPermissionsViolations == null) {
mPrivappPermissionsViolations = new ArraySet<>();
}
@@ -12278,6 +12341,7 @@
}
res.iconResourceId = info.icon;
res.system = res.activityInfo.applicationInfo.isSystemApp();
+ res.instantAppAvailable = userState.instantApp;
return res;
}
@@ -12740,7 +12804,7 @@
}
static final class EphemeralIntentResolver
- extends IntentResolver<EphemeralResponse, EphemeralResponse> {
+ extends IntentResolver<AuxiliaryResolveInfo, AuxiliaryResolveInfo> {
/**
* The result that has the highest defined order. Ordering applies on a
* per-package basis. Mapping is from package name to Pair of order and
@@ -12755,17 +12819,17 @@
final ArrayMap<String, Pair<Integer, EphemeralResolveInfo>> mOrderResult = new ArrayMap<>();
@Override
- protected EphemeralResponse[] newArray(int size) {
- return new EphemeralResponse[size];
+ protected AuxiliaryResolveInfo[] newArray(int size) {
+ return new AuxiliaryResolveInfo[size];
}
@Override
- protected boolean isPackageForFilter(String packageName, EphemeralResponse responseObj) {
+ protected boolean isPackageForFilter(String packageName, AuxiliaryResolveInfo responseObj) {
return true;
}
@Override
- protected EphemeralResponse newResult(EphemeralResponse responseObj, int match,
+ protected AuxiliaryResolveInfo newResult(AuxiliaryResolveInfo responseObj, int match,
int userId) {
if (!sUserManager.exists(userId)) {
return null;
@@ -12787,7 +12851,7 @@
}
@Override
- protected void filterResults(List<EphemeralResponse> results) {
+ protected void filterResults(List<AuxiliaryResolveInfo> results) {
// only do work if ordering is enabled [most of the time it won't be]
if (mOrderResult.size() == 0) {
return;
@@ -13026,6 +13090,12 @@
+ "to use the PackageManager.INSTALL_GRANT_RUNTIME_PERMISSIONS flag");
}
+ if ((installFlags & PackageManager.INSTALL_FORWARD_LOCK) != 0
+ || (installFlags & PackageManager.INSTALL_EXTERNAL) != 0) {
+ throw new IllegalArgumentException(
+ "New installs into ASEC containers no longer supported");
+ }
+
final File originFile = new File(originPath);
final OriginInfo origin = OriginInfo.fromUntrustedFile(originFile);
@@ -14202,88 +14272,6 @@
abstract void handleReturnCode();
}
- class MeasureParams extends HandlerParams {
- private final PackageStats mStats;
- private boolean mSuccess;
-
- private final IPackageStatsObserver mObserver;
-
- public MeasureParams(PackageStats stats, IPackageStatsObserver observer) {
- super(new UserHandle(stats.userHandle));
- mObserver = observer;
- mStats = stats;
- }
-
- @Override
- public String toString() {
- return "MeasureParams{"
- + Integer.toHexString(System.identityHashCode(this))
- + " " + mStats.packageName + "}";
- }
-
- @Override
- void handleStartCopy() throws RemoteException {
- synchronized (mInstallLock) {
- mSuccess = getPackageSizeInfoLI(mStats.packageName, mStats.userHandle, mStats);
- }
-
- if (mSuccess) {
- boolean mounted = false;
- try {
- final String status = Environment.getExternalStorageState();
- mounted = (Environment.MEDIA_MOUNTED.equals(status)
- || Environment.MEDIA_MOUNTED_READ_ONLY.equals(status));
- } catch (Exception e) {
- }
-
- if (mounted) {
- final UserEnvironment userEnv = new UserEnvironment(mStats.userHandle);
-
- mStats.externalCacheSize = calculateDirectorySize(mContainerService,
- userEnv.buildExternalStorageAppCacheDirs(mStats.packageName));
-
- mStats.externalDataSize = calculateDirectorySize(mContainerService,
- userEnv.buildExternalStorageAppDataDirs(mStats.packageName));
-
- // Always subtract cache size, since it's a subdirectory
- mStats.externalDataSize -= mStats.externalCacheSize;
-
- mStats.externalMediaSize = calculateDirectorySize(mContainerService,
- userEnv.buildExternalStorageAppMediaDirs(mStats.packageName));
-
- mStats.externalObbSize = calculateDirectorySize(mContainerService,
- userEnv.buildExternalStorageAppObbDirs(mStats.packageName));
- }
- }
- }
-
- @Override
- void handleReturnCode() {
- if (mObserver != null) {
- try {
- mObserver.onGetStatsCompleted(mStats, mSuccess);
- } catch (RemoteException e) {
- Slog.i(TAG, "Observer no longer exists.");
- }
- }
- }
-
- @Override
- void handleServiceError() {
- Slog.e(TAG, "Could not measure application " + mStats.packageName
- + " external storage");
- }
- }
-
- private static long calculateDirectorySize(IMediaContainerService mcs, File[] paths)
- throws RemoteException {
- long result = 0;
- for (File path : paths) {
- result += mcs.calculateDirectorySize(path.getAbsolutePath());
- }
- return result;
- }
-
private static void clearDirectory(IMediaContainerService mcs, File[] paths) {
for (File path : paths) {
try {
@@ -16844,11 +16832,20 @@
res.origUsers = ps.queryInstalledUsers(sUserManager.getUserIds(), true);
}
- // Check whether the newly-scanned package wants to define an already-defined perm
int N = pkg.permissions.size();
for (int i = N-1; i >= 0; i--) {
PackageParser.Permission perm = pkg.permissions.get(i);
BasePermission bp = mSettings.mPermissions.get(perm.info.name);
+
+ // Don't allow anyone but the platform to define ephemeral permissions.
+ if ((perm.info.protectionLevel & PermissionInfo.PROTECTION_FLAG_EPHEMERAL) != 0
+ && !PLATFORM_PACKAGE_NAME.equals(pkg.packageName)) {
+ Slog.w(TAG, "Package " + pkg.packageName
+ + " attempting to delcare ephemeral permission "
+ + perm.info.name + "; Removing ephemeral.");
+ perm.info.protectionLevel &= ~PermissionInfo.PROTECTION_FLAG_EPHEMERAL;
+ }
+ // Check whether the newly-scanned package wants to define an already-defined perm
if (bp != null) {
// If the defining package is signed with our cert, it's okay. This
// also includes the "updating the same package" case, of course.
@@ -18739,21 +18736,11 @@
@Override
public void getPackageSizeInfo(final String packageName, int userHandle,
final IPackageStatsObserver observer) {
- mContext.enforceCallingOrSelfPermission(
- android.Manifest.permission.GET_PACKAGE_SIZE, null);
- if (packageName == null) {
- throw new IllegalArgumentException("Attempt to get size of null packageName");
+ Slog.w(TAG, "Shame on you for calling a hidden API. Shame!");
+ try {
+ observer.onGetStatsCompleted(null, false);
+ } catch (Throwable ignored) {
}
-
- PackageStats stats = new PackageStats(packageName, userHandle);
-
- /*
- * Queue up an async operation since the package measurement may take a
- * little while.
- */
- Message msg = mHandler.obtainMessage(INIT_COPY);
- msg.obj = new MeasureParams(stats, observer);
- mHandler.sendMessage(msg);
}
private boolean getPackageSizeInfoLI(String packageName, int userId, PackageStats stats) {
@@ -19666,6 +19653,35 @@
return getHomeActivitiesAsUser(allHomeCandidates, UserHandle.getCallingUserId());
}
+ /**
+ * Report the 'Home' activity which is currently set as "always use this one". If non is set
+ * then reports the most likely home activity or null if there are more than one.
+ */
+ public ComponentName getDefaultHomeActivity(int userId) {
+ List<ResolveInfo> allHomeCandidates = new ArrayList<>();
+ ComponentName cn = getHomeActivitiesAsUser(allHomeCandidates, userId);
+ if (cn != null) {
+ return cn;
+ }
+
+ // Find the launcher with the highest priority and return that component if there are no
+ // other home activity with the same priority.
+ int lastPriority = Integer.MIN_VALUE;
+ ComponentName lastComponent = null;
+ final int size = allHomeCandidates.size();
+ for (int i = 0; i < size; i++) {
+ final ResolveInfo ri = allHomeCandidates.get(i);
+ if (ri.priority > lastPriority) {
+ lastComponent = ri.activityInfo.getComponentName();
+ lastPriority = ri.priority;
+ } else if (ri.priority == lastPriority) {
+ // Two components found with same priority.
+ lastComponent = null;
+ }
+ }
+ return lastComponent;
+ }
+
private Intent getHomeIntent() {
Intent intent = new Intent(Intent.ACTION_MAIN);
intent.addCategory(Intent.CATEGORY_HOME);
@@ -20168,6 +20184,14 @@
}
}
+ public void waitForAppDataPrepared() {
+ if (mPrepareAppDataFuture == null) {
+ return;
+ }
+ ConcurrentUtils.waitForFutureNoInterrupt(mPrepareAppDataFuture, "wait for prepareAppData");
+ mPrepareAppDataFuture = null;
+ }
+
@Override
public boolean isSafeMode() {
return mSafeMode;
@@ -20214,6 +20238,7 @@
public static final int DUMP_FROZEN = 1 << 19;
public static final int DUMP_DEXOPT = 1 << 20;
public static final int DUMP_COMPILER_STATS = 1 << 21;
+ public static final int DUMP_ENABLED_OVERLAYS = 1 << 22;
public static final int OPTION_SHOW_FILTERS = 1 << 0;
@@ -20333,12 +20358,16 @@
pw.println(" check-permission <permission> <package> [<user>]: does pkg hold perm?");
pw.println(" dexopt: dump dexopt state");
pw.println(" compiler-stats: dump compiler statistics");
+ pw.println(" enabled-overlays: dump list of enabled overlay packages");
pw.println(" <package.name>: info about given package");
return;
} else if ("--checkin".equals(opt)) {
checkin = true;
} else if ("-f".equals(opt)) {
dumpState.setOptionEnabled(DumpState.OPTION_SHOW_FILTERS);
+ } else if ("--proto".equals(opt)) {
+ dumpProto(fd);
+ return;
} else {
pw.println("Unknown argument: " + opt + "; use -h for help");
}
@@ -20461,6 +20490,8 @@
dumpState.setDump(DumpState.DUMP_DEXOPT);
} else if ("compiler-stats".equals(cmd)) {
dumpState.setDump(DumpState.DUMP_COMPILER_STATS);
+ } else if ("enabled-overlays".equals(cmd)) {
+ dumpState.setDump(DumpState.DUMP_ENABLED_OVERLAYS);
} else if ("write".equals(cmd)) {
synchronized (mPackages) {
mSettings.writeLPr();
@@ -20831,6 +20862,11 @@
dumpCompilerStatsLPr(pw, packageName);
}
+ if (!checkin && dumpState.isDumping(DumpState.DUMP_ENABLED_OVERLAYS)) {
+ if (dumpState.onTitlePrinted()) pw.println();
+ dumpEnabledOverlaysLPr(pw);
+ }
+
if (!checkin && dumpState.isDumping(DumpState.DUMP_MESSAGES) && packageName == null) {
if (dumpState.onTitlePrinted()) pw.println();
mSettings.dumpReadMessagesLPr(pw, dumpState);
@@ -20869,6 +20905,98 @@
}
}
+ private void dumpProto(FileDescriptor fd) {
+ final ProtoOutputStream proto = new ProtoOutputStream(fd);
+
+ synchronized (mPackages) {
+ final long requiredVerifierPackageToken =
+ proto.start(PackageServiceDumpProto.REQUIRED_VERIFIER_PACKAGE);
+ proto.write(PackageServiceDumpProto.PackageShortProto.NAME, mRequiredVerifierPackage);
+ proto.write(
+ PackageServiceDumpProto.PackageShortProto.UID,
+ getPackageUid(
+ mRequiredVerifierPackage,
+ MATCH_DEBUG_TRIAGED_MISSING,
+ UserHandle.USER_SYSTEM));
+ proto.end(requiredVerifierPackageToken);
+
+ if (mIntentFilterVerifierComponent != null) {
+ String verifierPackageName = mIntentFilterVerifierComponent.getPackageName();
+ final long verifierPackageToken =
+ proto.start(PackageServiceDumpProto.VERIFIER_PACKAGE);
+ proto.write(PackageServiceDumpProto.PackageShortProto.NAME, verifierPackageName);
+ proto.write(
+ PackageServiceDumpProto.PackageShortProto.UID,
+ getPackageUid(
+ verifierPackageName,
+ MATCH_DEBUG_TRIAGED_MISSING,
+ UserHandle.USER_SYSTEM));
+ proto.end(verifierPackageToken);
+ }
+
+ dumpSharedLibrariesProto(proto);
+ dumpFeaturesProto(proto);
+ mSettings.dumpPackagesProto(proto);
+ mSettings.dumpSharedUsersProto(proto);
+ dumpMessagesProto(proto);
+ }
+ proto.flush();
+ }
+
+ private void dumpMessagesProto(ProtoOutputStream proto) {
+ BufferedReader in = null;
+ String line = null;
+ try {
+ in = new BufferedReader(new FileReader(getSettingsProblemFile()));
+ while ((line = in.readLine()) != null) {
+ if (line.contains("ignored: updated version")) continue;
+ proto.write(PackageServiceDumpProto.MESSAGES, line);
+ }
+ } catch (IOException ignored) {
+ } finally {
+ IoUtils.closeQuietly(in);
+ }
+ }
+
+ private void dumpFeaturesProto(ProtoOutputStream proto) {
+ synchronized (mAvailableFeatures) {
+ final int count = mAvailableFeatures.size();
+ for (int i = 0; i < count; i++) {
+ final FeatureInfo feat = mAvailableFeatures.valueAt(i);
+ final long featureToken = proto.start(PackageServiceDumpProto.FEATURES);
+ proto.write(PackageServiceDumpProto.FeatureProto.NAME, feat.name);
+ proto.write(PackageServiceDumpProto.FeatureProto.VERSION, feat.version);
+ proto.end(featureToken);
+ }
+ }
+ }
+
+ private void dumpSharedLibrariesProto(ProtoOutputStream proto) {
+ final int count = mSharedLibraries.size();
+ for (int i = 0; i < count; i++) {
+ final String libName = mSharedLibraries.keyAt(i);
+ SparseArray<SharedLibraryEntry> versionedLib = mSharedLibraries.get(libName);
+ if (versionedLib == null) {
+ continue;
+ }
+ final int versionCount = versionedLib.size();
+ for (int j = 0; j < versionCount; j++) {
+ final SharedLibraryEntry libEntry = versionedLib.valueAt(j);
+ final long sharedLibraryToken =
+ proto.start(PackageServiceDumpProto.SHARED_LIBRARIES);
+ proto.write(PackageServiceDumpProto.SharedLibraryProto.NAME, libEntry.info.getName());
+ final boolean isJar = (libEntry.path != null);
+ proto.write(PackageServiceDumpProto.SharedLibraryProto.IS_JAR, isJar);
+ if (isJar) {
+ proto.write(PackageServiceDumpProto.SharedLibraryProto.PATH, libEntry.path);
+ } else {
+ proto.write(PackageServiceDumpProto.SharedLibraryProto.APK, libEntry.apk);
+ }
+ proto.end(sharedLibraryToken);
+ }
+ }
+ }
+
private void dumpDexoptStateLPr(PrintWriter pw, String packageName) {
final IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " ", 120);
ipw.println();
@@ -20927,6 +21055,23 @@
}
}
+ private void dumpEnabledOverlaysLPr(PrintWriter pw) {
+ pw.println("Enabled overlay paths:");
+ final int N = mEnabledOverlayPaths.size();
+ for (int i = 0; i < N; i++) {
+ final int userId = mEnabledOverlayPaths.keyAt(i);
+ pw.println(String.format(" User %d:", userId));
+ final ArrayMap<String, ArrayList<String>> userSpecificOverlays =
+ mEnabledOverlayPaths.valueAt(i);
+ final int M = userSpecificOverlays.size();
+ for (int j = 0; j < M; j++) {
+ final String targetPackageName = userSpecificOverlays.keyAt(j);
+ final ArrayList<String> overlayPackagePaths = userSpecificOverlays.valueAt(j);
+ pw.println(String.format(" %s: %s", targetPackageName, overlayPackagePaths));
+ }
+ }
+ }
+
private String dumpDomainString(String packageName) {
List<IntentFilterVerificationInfo> iviList = getIntentFilterVerifications(packageName)
.getList();
@@ -21618,6 +21763,11 @@
}
}
+ private void reconcileAppsDataLI(String volumeUuid, int userId, int flags,
+ boolean migrateAppData) {
+ reconcileAppsDataLI(volumeUuid, userId, flags, migrateAppData, false /* onlyCoreApps */);
+ }
+
/**
* Reconcile all app data on given mounted volume.
* <p>
@@ -21626,11 +21776,13 @@
* <p>
* Verifies that directories exist and that ownership and labeling is
* correct for all installed apps.
+ * @returns list of skipped non-core packages (if {@code onlyCoreApps} is true)
*/
- private void reconcileAppsDataLI(String volumeUuid, int userId, int flags,
- boolean migrateAppData) {
+ private List<String> reconcileAppsDataLI(String volumeUuid, int userId, int flags,
+ boolean migrateAppData, boolean onlyCoreApps) {
Slog.v(TAG, "reconcileAppsData for " + volumeUuid + " u" + userId + " 0x"
+ Integer.toHexString(flags) + " migrateAppData=" + migrateAppData);
+ List<String> result = onlyCoreApps ? new ArrayList<>() : null;
final File ceDir = Environment.getDataUserCeDirectory(volumeUuid, userId);
final File deDir = Environment.getDataUserDeDirectory(volumeUuid, userId);
@@ -21694,21 +21846,20 @@
// and reconcile again once they're scanned
continue;
}
+ // Skip non-core apps if requested
+ if (onlyCoreApps && !ps.pkg.coreApp) {
+ result.add(packageName);
+ continue;
+ }
if (ps.getInstalled(userId)) {
- prepareAppDataLIF(ps.pkg, userId, flags);
-
- if (migrateAppData && maybeMigrateAppDataLIF(ps.pkg, userId)) {
- // We may have just shuffled around app data directories, so
- // prepare them one more time
- prepareAppDataLIF(ps.pkg, userId, flags);
- }
-
+ prepareAppDataAndMigrateLIF(ps.pkg, userId, flags, migrateAppData);
preparedCount++;
}
}
Slog.v(TAG, "reconcileAppsData finished " + preparedCount + " packages");
+ return result;
}
/**
@@ -21769,6 +21920,17 @@
}
}
+ private void prepareAppDataAndMigrateLIF(PackageParser.Package pkg, int userId, int flags,
+ boolean maybeMigrateAppData) {
+ prepareAppDataLIF(pkg, userId, flags);
+
+ if (maybeMigrateAppData && maybeMigrateAppDataLIF(pkg, userId)) {
+ // We may have just shuffled around app data directories, so
+ // prepare them one more time
+ prepareAppDataLIF(pkg, userId, flags);
+ }
+ }
+
private void prepareAppDataLeafLIF(PackageParser.Package pkg, int userId, int flags) {
if (DEBUG_APP_DATA) {
Slog.v(TAG, "prepareAppData for " + pkg.packageName + " u" + userId + " 0x"
@@ -22936,11 +23098,10 @@
}
@Override
- public void requestEphemeralResolutionPhaseTwo(EphemeralResponse responseObj,
- Intent origIntent, String resolvedType, Intent launchIntent,
- String callingPackage, int userId) {
- PackageManagerService.this.requestEphemeralResolutionPhaseTwo(
- responseObj, origIntent, resolvedType, launchIntent, callingPackage, userId);
+ public void requestInstantAppResolutionPhaseTwo(AuxiliaryResolveInfo responseObj,
+ Intent origIntent, String resolvedType, String callingPackage, int userId) {
+ PackageManagerService.this.requestInstantAppResolutionPhaseTwo(
+ responseObj, origIntent, resolvedType, callingPackage, userId);
}
@Override
@@ -23011,12 +23172,50 @@
return targetPackages;
}
-
@Override
- public boolean setEnabledOverlayPackages(int userId, String targetPackageName,
- List<String> overlayPackageNames) {
- // TODO: implement when we integrate OMS properly
- return false;
+ public boolean setEnabledOverlayPackages(int userId, @NonNull String targetPackageName,
+ @Nullable List<String> overlayPackageNames) {
+ synchronized (mPackages) {
+ if (targetPackageName == null || mPackages.get(targetPackageName) == null) {
+ Slog.e(TAG, "failed to find package " + targetPackageName);
+ return false;
+ }
+
+ ArrayList<String> paths = null;
+ if (overlayPackageNames != null) {
+ final int N = overlayPackageNames.size();
+ paths = new ArrayList<String>(N);
+ for (int i = 0; i < N; i++) {
+ final String packageName = overlayPackageNames.get(i);
+ final PackageParser.Package pkg = mPackages.get(packageName);
+ if (pkg == null) {
+ Slog.e(TAG, "failed to find package " + packageName);
+ return false;
+ }
+ paths.add(pkg.baseCodePath);
+ }
+ }
+
+ ArrayMap<String, ArrayList<String>> userSpecificOverlays =
+ mEnabledOverlayPaths.get(userId);
+ if (userSpecificOverlays == null) {
+ userSpecificOverlays = new ArrayMap<String, ArrayList<String>>();
+ mEnabledOverlayPaths.put(userId, userSpecificOverlays);
+ }
+
+ if (paths != null && paths.size() > 0) {
+ userSpecificOverlays.put(targetPackageName, paths);
+ } else {
+ userSpecificOverlays.remove(targetPackageName);
+ }
+ return true;
+ }
+ }
+
+ public ResolveInfo resolveIntent(Intent intent, String resolvedType,
+ int flags, int userId) {
+ return resolveIntentInternal(
+ intent, resolvedType, flags, userId, true /*includeInstantApp*/);
}
}
diff --git a/services/core/java/com/android/server/pm/PackageSetting.java b/services/core/java/com/android/server/pm/PackageSetting.java
index 5f348ab..b4bba88 100644
--- a/services/core/java/com/android/server/pm/PackageSetting.java
+++ b/services/core/java/com/android/server/pm/PackageSetting.java
@@ -19,6 +19,9 @@
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageParser;
+import android.content.pm.UserInfo;
+import android.service.pm.PackageProto;
+import android.util.proto.ProtoOutputStream;
import java.io.File;
import java.util.List;
@@ -128,4 +131,32 @@
}
return true;
}
+
+ public void writeToProto(ProtoOutputStream proto, long fieldId, List<UserInfo> users) {
+ final long packageToken = proto.start(fieldId);
+ proto.write(PackageProto.NAME, (realName != null ? realName : name));
+ proto.write(PackageProto.UID, appId);
+ proto.write(PackageProto.VERSION_CODE, versionCode);
+ proto.write(PackageProto.VERSION_STRING, pkg.mVersionName);
+ proto.write(PackageProto.INSTALL_TIME_MS, firstInstallTime);
+ proto.write(PackageProto.UPDATE_TIME_MS, lastUpdateTime);
+ proto.write(PackageProto.INSTALLER_NAME, installerPackageName);
+
+ if (pkg != null) {
+ long splitToken = proto.start(PackageProto.SPLITS);
+ proto.write(PackageProto.SplitProto.NAME, "base");
+ proto.write(PackageProto.SplitProto.REVISION_CODE, pkg.baseRevisionCode);
+ proto.end(splitToken);
+ if (pkg.splitNames != null) {
+ for (int i = 0; i < pkg.splitNames.length; i++) {
+ splitToken = proto.start(PackageProto.SPLITS);
+ proto.write(PackageProto.SplitProto.NAME, pkg.splitNames[i]);
+ proto.write(PackageProto.SplitProto.REVISION_CODE, pkg.splitRevisionCodes[i]);
+ proto.end(splitToken);
+ }
+ }
+ }
+ writeUsersInfoToProto(proto, PackageProto.USERS);
+ proto.end(packageToken);
+ }
}
diff --git a/services/core/java/com/android/server/pm/PackageSettingBase.java b/services/core/java/com/android/server/pm/PackageSettingBase.java
index 601377d6..b9c43da 100644
--- a/services/core/java/com/android/server/pm/PackageSettingBase.java
+++ b/services/core/java/com/android/server/pm/PackageSettingBase.java
@@ -25,8 +25,10 @@
import android.content.pm.PackageManager;
import android.content.pm.PackageUserState;
import android.os.storage.VolumeInfo;
+import android.service.pm.PackageProto;
import android.util.ArraySet;
import android.util.SparseArray;
+import android.util.proto.ProtoOutputStream;
import com.android.internal.annotations.VisibleForTesting;
@@ -564,4 +566,32 @@
modifyUserState(userId).domainVerificationStatus =
PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED;
}
+
+ protected void writeUsersInfoToProto(ProtoOutputStream proto, long fieldId) {
+ int count = userState.size();
+ for (int i = 0; i < count; i++) {
+ final long userToken = proto.start(fieldId);
+ final int userId = userState.keyAt(i);
+ final PackageUserState state = userState.valueAt(i);
+ proto.write(PackageProto.UserInfoProto.ID, userId);
+ final int installType;
+ if (state.instantApp) {
+ installType = PackageProto.UserInfoProto.INSTANT_APP_INSTALL;
+ } else if (state.installed) {
+ installType = PackageProto.UserInfoProto.FULL_APP_INSTALL;
+ } else {
+ installType = PackageProto.UserInfoProto.NOT_INSTALLED_FOR_USER;
+ }
+ proto.write(PackageProto.UserInfoProto.INSTALL_TYPE, installType);
+ proto.write(PackageProto.UserInfoProto.IS_HIDDEN, state.hidden);
+ proto.write(PackageProto.UserInfoProto.IS_SUSPENDED, state.suspended);
+ proto.write(PackageProto.UserInfoProto.IS_STOPPED, state.stopped);
+ proto.write(PackageProto.UserInfoProto.IS_LAUNCHED, !state.notLaunched);
+ proto.write(PackageProto.UserInfoProto.ENABLED_STATE, state.enabled);
+ proto.write(
+ PackageProto.UserInfoProto.LAST_DISABLED_APP_CALLER,
+ state.lastDisableAppCaller);
+ proto.end(userToken);
+ }
+ }
}
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index a8a5ff0..570b31f 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -65,6 +65,7 @@
import android.os.UserManager;
import android.os.storage.StorageManager;
import android.os.storage.VolumeInfo;
+import android.service.pm.PackageServiceDumpProto;
import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.ArraySet;
@@ -77,6 +78,7 @@
import android.util.SparseIntArray;
import android.util.SparseLongArray;
import android.util.Xml;
+import android.util.proto.ProtoOutputStream;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.os.BackgroundThread;
@@ -887,9 +889,9 @@
}
if (p.appId < 0) {
PackageManagerService.reportSettingsProblem(Log.WARN,
- "Package " + p.name + " could not be assigned a valid uid");
+ "Package " + p.name + " could not be assigned a valid UID");
throw new PackageManagerException(INSTALL_FAILED_INSUFFICIENT_STORAGE,
- "Creating application package " + p.name + " failed");
+ "Package " + p.name + " could not be assigned a valid UID");
}
}
@@ -3370,7 +3372,7 @@
private void applyDefaultPreferredActivityLPw(PackageManagerService service,
Intent intent, int flags, ComponentName cn, String scheme, PatternMatcher ssp,
IntentFilter.AuthorityEntry auth, PatternMatcher path, int userId) {
- flags = service.updateFlagsForResolve(flags, userId, intent);
+ flags = service.updateFlagsForResolve(flags, userId, intent, false);
List<ResolveInfo> ri = service.mActivities.queryIntent(intent,
intent.getType(), flags, 0);
if (PackageManagerService.DEBUG_PREFERRED) Log.d(TAG, "Queried " + intent
@@ -4876,6 +4878,16 @@
}
}
+ void dumpPackagesProto(ProtoOutputStream proto) {
+ List<UserInfo> users = getAllUsers(UserManagerService.getInstance());
+
+ final int count = mPackages.size();
+ for (int i = 0; i < count; i++) {
+ final PackageSetting ps = mPackages.valueAt(i);
+ ps.writeToProto(proto, PackageServiceDumpProto.PACKAGES, users);
+ }
+ }
+
void dumpPermissionsLPr(PrintWriter pw, String packageName, ArraySet<String> permissionNames,
DumpState dumpState) {
boolean printedSomething = false;
@@ -4966,6 +4978,17 @@
}
}
+ void dumpSharedUsersProto(ProtoOutputStream proto) {
+ final int count = mSharedUsers.size();
+ for (int i = 0; i < count; i++) {
+ final SharedUserSetting su = mSharedUsers.valueAt(i);
+ final long sharedUserToken = proto.start(PackageServiceDumpProto.SHARED_USERS);
+ proto.write(PackageServiceDumpProto.SharedUserProto.USER_ID, su.userId);
+ proto.write(PackageServiceDumpProto.SharedUserProto.NAME, su.name);
+ proto.end(sharedUserToken);
+ }
+ }
+
void dumpReadMessagesLPr(PrintWriter pw, DumpState dumpState) {
pw.println("Settings parse messages:");
pw.print(mReadMessages.toString());
diff --git a/services/core/java/com/android/server/pm/ShortcutPackage.java b/services/core/java/com/android/server/pm/ShortcutPackage.java
index 570259b..ac98ab9 100644
--- a/services/core/java/com/android/server/pm/ShortcutPackage.java
+++ b/services/core/java/com/android/server/pm/ShortcutPackage.java
@@ -20,6 +20,7 @@
import android.annotation.UserIdInt;
import android.content.ComponentName;
import android.content.Intent;
+import android.content.IntentFilter;
import android.content.pm.PackageInfo;
import android.content.pm.ShortcutInfo;
import android.content.res.Resources;
@@ -31,6 +32,7 @@
import android.util.Slog;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.ArrayUtils;
import com.android.internal.util.Preconditions;
import com.android.internal.util.XmlUtils;
import com.android.server.pm.ShortcutService.ShortcutOperation;
@@ -68,6 +70,9 @@
private static final String TAG_EXTRAS = "extras";
private static final String TAG_SHORTCUT = "shortcut";
private static final String TAG_CATEGORIES = "categories";
+ private static final String TAG_CHOOSER_EXTRAS = "chooser-extras";
+ private static final String TAG_CHOOSER_INTENT_FILTERS = "chooser-intent-filters";
+ private static final String TAG_CHOOSER_COMPONENT_NAMES = "chooser-component-names";
private static final String ATTR_NAME = "name";
private static final String ATTR_CALL_COUNT = "call-count";
@@ -91,6 +96,7 @@
private static final String ATTR_ICON_RES_ID = "icon-res";
private static final String ATTR_ICON_RES_NAME = "icon-resname";
private static final String ATTR_BITMAP_PATH = "bitmap-path";
+ private static final String ATTR_COMPONENT_NAMES = "component-names";
private static final String NAME_CATEGORIES = "categories";
@@ -200,7 +206,7 @@
if (shortcut != null) {
mShortcutUser.mService.removeIcon(getPackageUserId(), shortcut);
shortcut.clearFlags(ShortcutInfo.FLAG_DYNAMIC | ShortcutInfo.FLAG_PINNED
- | ShortcutInfo.FLAG_MANIFEST);
+ | ShortcutInfo.FLAG_MANIFEST | ShortcutInfo.FLAG_CHOOSER);
}
return shortcut;
}
@@ -226,7 +232,7 @@
Preconditions.checkArgument(newShortcut.isEnabled(),
"add/setDynamicShortcuts() cannot publish disabled shortcuts");
- newShortcut.addFlags(ShortcutInfo.FLAG_DYNAMIC);
+ addCorrectDynamicFlags(newShortcut);
final ShortcutInfo oldShortcut = mShortcuts.get(newShortcut.getId());
@@ -250,6 +256,17 @@
addShortcutInner(newShortcut);
}
+ // TODO: Sample code & JavaDoc for ShortcutManager needs updating to reflect the fact that
+ // Chooser shortcuts are not always dynamic.
+ public void addCorrectDynamicFlags(@NonNull ShortcutInfo shortcut) {
+ if (shortcut.getIntent() != null) {
+ shortcut.addFlags(ShortcutInfo.FLAG_DYNAMIC);
+ }
+ if (!ArrayUtils.isEmpty(shortcut.getChooserIntentFilters())) {
+ shortcut.addFlags(ShortcutInfo.FLAG_CHOOSER);
+ }
+ }
+
/**
* Remove all shortcuts that aren't pinned nor dynamic.
*/
@@ -282,11 +299,11 @@
boolean changed = false;
for (int i = mShortcuts.size() - 1; i >= 0; i--) {
final ShortcutInfo si = mShortcuts.valueAt(i);
- if (si.isDynamic()) {
+ if (si.isDynamic() || si.isChooser()) {
changed = true;
si.setTimestamp(now);
- si.clearFlags(ShortcutInfo.FLAG_DYNAMIC);
+ si.clearFlags(ShortcutInfo.FLAG_DYNAMIC | ShortcutInfo.FLAG_CHOOSER);
si.setRank(0); // It may still be pinned, so clear the rank.
}
}
@@ -355,7 +372,8 @@
if (oldShortcut.isPinned()) {
oldShortcut.setRank(0);
- oldShortcut.clearFlags(ShortcutInfo.FLAG_DYNAMIC | ShortcutInfo.FLAG_MANIFEST);
+ oldShortcut.clearFlags(ShortcutInfo.FLAG_DYNAMIC | ShortcutInfo.FLAG_MANIFEST
+ | ShortcutInfo.FLAG_CHOOSER);
if (disable) {
oldShortcut.addFlags(ShortcutInfo.FLAG_DISABLED);
}
@@ -1116,8 +1134,8 @@
// Don't adjust ranks for manifest shortcuts.
continue;
}
- // At this point, it must be dynamic.
- if (!si.isDynamic()) {
+ // At this point, it must be dynamic or a chooser.
+ if (!si.isDynamicOrChooser()) {
s.wtf("Non-dynamic shortcut found.");
continue;
}
@@ -1294,7 +1312,7 @@
ShortcutService.writeAttr(out, ATTR_FLAGS,
si.getFlags() &
~(ShortcutInfo.FLAG_HAS_ICON_FILE | ShortcutInfo.FLAG_HAS_ICON_RES
- | ShortcutInfo.FLAG_DYNAMIC));
+ | ShortcutInfo.FLAG_DYNAMIC | ShortcutInfo.FLAG_CHOOSER));
} else {
// When writing for backup, ranks shouldn't be saved, since shortcuts won't be restored
// as dynamic.
@@ -1317,15 +1335,36 @@
}
final Intent[] intentsNoExtras = si.getIntentsNoExtras();
final PersistableBundle[] intentsExtras = si.getIntentPersistableExtrases();
- final int numIntents = intentsNoExtras.length;
- for (int i = 0; i < numIntents; i++) {
- out.startTag(null, TAG_INTENT);
- ShortcutService.writeAttr(out, ATTR_INTENT_NO_EXTRA, intentsNoExtras[i]);
- ShortcutService.writeTagExtra(out, TAG_EXTRAS, intentsExtras[i]);
- out.endTag(null, TAG_INTENT);
+ if (intentsNoExtras != null) {
+ final int numIntents = intentsNoExtras.length;
+ for (int i = 0; i < numIntents; i++) {
+ out.startTag(null, TAG_INTENT);
+ ShortcutService.writeAttr(out, ATTR_INTENT_NO_EXTRA, intentsNoExtras[i]);
+ ShortcutService.writeTagExtra(out, TAG_EXTRAS, intentsExtras[i]);
+ out.endTag(null, TAG_INTENT);
+ }
+ }
+ ShortcutService.writeTagExtra(out, TAG_EXTRAS, si.getExtras());
+
+ ShortcutService.writeTagExtra(out, TAG_CHOOSER_EXTRAS, si.getChooserExtras());
+
+ final IntentFilter[] intentFilters = si.getChooserIntentFilters();
+ if (intentFilters != null) {
+ for (int i = 0; i < intentFilters.length; i++) {
+ out.startTag(null, TAG_CHOOSER_INTENT_FILTERS);
+ intentFilters[i].writeToXml(out);
+ out.endTag(null, TAG_CHOOSER_INTENT_FILTERS);
+ }
}
- ShortcutService.writeTagExtra(out, TAG_EXTRAS, si.getExtras());
+ final ComponentName[] componentNames = si.getChooserComponentNames();
+ if (componentNames != null) {
+ for (int i = 0; i < componentNames.length; i++) {
+ out.startTag(null, TAG_CHOOSER_COMPONENT_NAMES);
+ ShortcutService.writeAttr(out, ATTR_COMPONENT_NAMES, componentNames[i]);
+ out.endTag(null, TAG_CHOOSER_COMPONENT_NAMES);
+ }
+ }
out.endTag(null, TAG_SHORTCUT);
}
@@ -1398,6 +1437,9 @@
String iconResName;
String bitmapPath;
ArraySet<String> categories = null;
+ PersistableBundle chooserExtras;
+ List<IntentFilter> chooserIntentFilters = new ArrayList<>();
+ List<ComponentName> chooserComponentNames = new ArrayList<>();
id = ShortcutService.parseStringAttribute(parser, ATTR_ID);
activityComponent = ShortcutService.parseComponentNameAttribute(parser,
@@ -1458,6 +1500,18 @@
}
}
continue;
+ case TAG_CHOOSER_EXTRAS:
+ chooserExtras = PersistableBundle.restoreFromXml(parser);
+ continue;
+ case TAG_CHOOSER_COMPONENT_NAMES:
+ chooserComponentNames.add(ShortcutService.parseComponentNameAttribute(parser,
+ ATTR_ACTIVITY));
+ continue;
+ case TAG_CHOOSER_INTENT_FILTERS:
+ IntentFilter toAdd = new IntentFilter();
+ toAdd.readFromXml(parser);
+ chooserIntentFilters.add(toAdd);
+ continue;
}
throw ShortcutService.throwForInvalidTag(depth, tag);
}
@@ -1551,10 +1605,10 @@
// Verify each shortcut's status.
for (int i = mShortcuts.size() - 1; i >= 0; i--) {
final ShortcutInfo si = mShortcuts.valueAt(i);
- if (!(si.isDeclaredInManifest() || si.isDynamic() || si.isPinned())) {
+ if (!(si.isDeclaredInManifest() || si.isDynamicOrChooser() || si.isPinned())) {
failed = true;
Log.e(TAG_VERIFY, "Package " + getPackageName() + ": shortcut " + si.getId()
- + " is not manifest, dynamic or pinned.");
+ + " is not manifest, dynamic, chooser or pinned.");
}
if (si.isDeclaredInManifest() && si.isDynamic()) {
failed = true;
@@ -1596,6 +1650,11 @@
Log.e(TAG_VERIFY, "Package " + getPackageName() + ": shortcut " + si.getId()
+ " has a dummy target activity");
}
+ if (si.getIntent() == null && !si.isChooser()) {
+ failed = true;
+ Log.e(TAG_VERIFY, "Package " + getPackageName() + ": shortcut " + si.getId()
+ + " has a null intent, but is not a chooser");
+ }
}
if (failed) {
diff --git a/services/core/java/com/android/server/pm/ShortcutRequestPinProcessor.java b/services/core/java/com/android/server/pm/ShortcutRequestPinProcessor.java
index 6eac5e3..b0689b8 100644
--- a/services/core/java/com/android/server/pm/ShortcutRequestPinProcessor.java
+++ b/services/core/java/com/android/server/pm/ShortcutRequestPinProcessor.java
@@ -48,7 +48,7 @@
/**
* Internal for {@link android.content.pm.LauncherApps.PinItemRequest} which receives callbacks.
*/
- private static class PinItemRequestInner extends IPinItemRequest.Stub {
+ private abstract static class PinItemRequestInner extends IPinItemRequest.Stub {
protected final ShortcutRequestPinProcessor mProcessor;
private final IntentSender mResultIntent;
private final int mLauncherUid;
@@ -63,6 +63,14 @@
mLauncherUid = launcherUid;
}
+ public ShortcutInfo getShortcutInfo() {
+ return null;
+ }
+
+ public AppWidgetProviderInfo getAppWidgetProviderInfo() {
+ return null;
+ }
+
/**
* Returns true if the caller is same as the default launcher app when this request
* object was created.
@@ -126,6 +134,26 @@
/**
* Internal for {@link android.content.pm.LauncherApps.PinItemRequest} which receives callbacks.
*/
+ private static class PinAppWidgetRequestInner extends PinItemRequestInner {
+ final AppWidgetProviderInfo mAppWidgetProviderInfo;
+
+ private PinAppWidgetRequestInner(ShortcutRequestPinProcessor processor,
+ IntentSender resultIntent, int launcherUid,
+ AppWidgetProviderInfo appWidgetProviderInfo) {
+ super(processor, resultIntent, launcherUid);
+
+ mAppWidgetProviderInfo = appWidgetProviderInfo;
+ }
+
+ @Override
+ public AppWidgetProviderInfo getAppWidgetProviderInfo() {
+ return mAppWidgetProviderInfo;
+ }
+ }
+
+ /**
+ * Internal for {@link android.content.pm.LauncherApps.PinItemRequest} which receives callbacks.
+ */
private static class PinShortcutRequestInner extends PinItemRequestInner {
/** Original shortcut passed by the app. */
public final ShortcutInfo shortcutOriginal;
@@ -153,6 +181,11 @@
}
@Override
+ public ShortcutInfo getShortcutInfo() {
+ return shortcutForLauncher;
+ }
+
+ @Override
protected boolean tryAccept() {
if (DEBUG) {
Slog.d(TAG, "Launcher accepted shortcut. ID=" + shortcutOriginal.getId()
@@ -208,8 +241,9 @@
} else {
int launcherUid = mService.injectGetPackageUid(
confirmActivity.first.getPackageName(), launcherUserId);
- request = new PinItemRequest(inAppWidget,
- new PinItemRequestInner(this, resultIntent, launcherUid));
+ request = new PinItemRequest(
+ new PinAppWidgetRequestInner(this, resultIntent, launcherUid, inAppWidget),
+ PinItemRequest.REQUEST_TYPE_APPWIDGET);
}
return startRequestConfirmActivity(confirmActivity.first, launcherUserId, request,
requestType);
@@ -319,7 +353,7 @@
mService.injectGetPackageUid(launcherPackage, launcherUserId),
existsAlready);
- return new PinItemRequest(shortcutForLauncher, inner);
+ return new PinItemRequest(inner, PinItemRequest.REQUEST_TYPE_SHORTCUT);
}
private void validateExistingShortcut(ShortcutInfo shortcutInfo) {
diff --git a/services/core/java/com/android/server/pm/ShortcutService.java b/services/core/java/com/android/server/pm/ShortcutService.java
index 057e781..74eb340 100644
--- a/services/core/java/com/android/server/pm/ShortcutService.java
+++ b/services/core/java/com/android/server/pm/ShortcutService.java
@@ -27,6 +27,7 @@
import android.appwidget.AppWidgetProviderInfo;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
+import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
@@ -64,6 +65,7 @@
import android.os.Handler;
import android.os.LocaleList;
import android.os.Looper;
+import android.os.Parcel;
import android.os.ParcelFileDescriptor;
import android.os.PersistableBundle;
import android.os.Process;
@@ -1750,6 +1752,7 @@
ps.clearAllImplicitRanks();
assignImplicitRanks(newShortcuts);
+ // TODO: Consider removing Chooser fields. If so, the FLAG_CHOOSER should be removed
for (int i = 0; i < size; i++) {
final ShortcutInfo source = newShortcuts.get(i);
fixUpIncomingShortcutInfo(source, /* forUpdate= */ true);
@@ -1789,6 +1792,13 @@
if (replacingIcon || source.hasStringResources()) {
fixUpShortcutResourceNamesAndValues(target);
}
+
+ // While updating, we keep the dynamic flag as it previously was, but refresh the
+ // chooser flag.
+ // TODO: If we support clearing Chooser fields, we should also remove the flag.
+ if (target.getChooserIntentFilters() != null) {
+ target.addFlags(ShortcutInfo.FLAG_CHOOSER);
+ }
}
// Lastly, adjust the ranks.
@@ -1852,6 +1862,7 @@
return true;
}
+ // TODO: Ensure non-launchable shortcuts can not be pinned
@Override
public boolean requestPinShortcut(String packageName, ShortcutInfo shortcut,
IntentSender resultIntent, int userId) {
@@ -2007,7 +2018,7 @@
return getShortcutsWithQueryLocked(
packageName, userId, ShortcutInfo.CLONE_REMOVE_FOR_CREATOR,
- ShortcutInfo::isDynamic);
+ ShortcutInfo::isDynamicOrChooser);
}
}
@@ -2200,6 +2211,14 @@
synchronized (mLock) {
throwIfUserLockedL(userId);
+ // For the chooser, we just check is the system is calling.
+ // STOPSHIP: We need to implement a new permission here rather than this terrible check.
+ // The packageName check is to try to distinguish between when an actual
+ // launcher is making the call, and when it's the system.
+ if (isCallerSystem() && packageName.equals("android")) {
+ return true;
+ }
+
final ShortcutUser user = getUserShortcutsLocked(userId);
// Always trust the cached component.
@@ -2372,7 +2391,7 @@
public List<ShortcutInfo> getShortcuts(int launcherUserId,
@NonNull String callingPackage, long changedSince,
@Nullable String packageName, @Nullable List<String> shortcutIds,
- @Nullable ComponentName componentName,
+ @Nullable ComponentName componentName, @Nullable Intent intent,
int queryFlags, int userId) {
final ArrayList<ShortcutInfo> ret = new ArrayList<>();
@@ -2394,13 +2413,13 @@
if (packageName != null) {
getShortcutsInnerLocked(launcherUserId,
callingPackage, packageName, shortcutIds, changedSince,
- componentName, queryFlags, userId, ret, cloneFlag);
+ componentName, intent, queryFlags, userId, ret, cloneFlag);
} else {
final List<String> shortcutIdsF = shortcutIds;
getUserShortcutsLocked(userId).forAllPackages(p -> {
getShortcutsInnerLocked(launcherUserId,
callingPackage, p.getPackageName(), shortcutIdsF, changedSince,
- componentName, queryFlags, userId, ret, cloneFlag);
+ componentName, intent, queryFlags, userId, ret, cloneFlag);
});
}
}
@@ -2409,7 +2428,7 @@
private void getShortcutsInnerLocked(int launcherUserId, @NonNull String callingPackage,
@Nullable String packageName, @Nullable List<String> shortcutIds, long changedSince,
- @Nullable ComponentName componentName, int queryFlags,
+ @Nullable ComponentName componentName, Intent intent, int queryFlags,
int userId, ArrayList<ShortcutInfo> ret, int cloneFlag) {
final ArraySet<String> ids = shortcutIds == null ? null
: new ArraySet<>(shortcutIds);
@@ -2434,6 +2453,15 @@
return false;
}
}
+ if (intent != null
+ && !si.hasMatchingFilter(mContext.getContentResolver(), intent)) {
+ return false;
+ }
+
+ if (((queryFlags & ShortcutQuery.FLAG_MATCH_CHOOSER) != 0)
+ && si.isChooser()) {
+ return true;
+ }
if (((queryFlags & ShortcutQuery.FLAG_GET_DYNAMIC) != 0)
&& si.isDynamic()) {
return true;
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index b76a249..d3931fb 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -51,21 +51,23 @@
import android.os.UserHandle;
import android.os.WorkSource;
import android.provider.Settings;
-import android.provider.Settings.Secure;
import android.provider.Settings.SettingNotFoundException;
import android.service.dreams.DreamManagerInternal;
+import android.service.power.PowerServiceDumpProto;
+import android.service.power.PowerServiceSettingsAndConfigurationDumpProto;
+import android.service.power.SuspendBlockerProto;
+import android.service.power.WakeLockProto;
import android.service.vr.IVrManager;
import android.service.vr.IVrStateCallbacks;
import android.util.EventLog;
import android.util.KeyValueListParser;
-import android.util.Log;
import android.util.PrintWriterPrinter;
import android.util.Slog;
import android.util.SparseArray;
import android.util.TimeUtils;
+import android.util.proto.ProtoOutputStream;
import android.view.Display;
import android.view.WindowManagerPolicy;
-
import com.android.internal.app.IAppOpsService;
import com.android.internal.app.IBatteryStats;
import com.android.internal.os.BackgroundThread;
@@ -78,7 +80,7 @@
import com.android.server.am.BatteryStatsService;
import com.android.server.lights.Light;
import com.android.server.lights.LightsManager;
-import com.android.server.vr.VrManagerService;
+
import libcore.util.Objects;
import java.io.FileDescriptor;
@@ -575,6 +577,13 @@
pw.print(" "); pw.print(KEY_NO_CACHED_WAKE_LOCKS); pw.print("=");
pw.println(NO_CACHED_WAKE_LOCKS);
}
+
+ void dumpProto(ProtoOutputStream proto) {
+ final long constantsToken = proto.start(PowerServiceDumpProto.CONSTANTS);
+ proto.write(PowerServiceDumpProto.ConstantsProto.IS_NO_CACHED_WAKE_LOCKS,
+ NO_CACHED_WAKE_LOCKS);
+ proto.end(constantsToken);
+ }
}
final Constants mConstants;
@@ -3244,6 +3253,354 @@
}
}
+ private void dumpProto(FileDescriptor fd) {
+ final WirelessChargerDetector wcd;
+ final ProtoOutputStream proto = new ProtoOutputStream(fd);
+
+ synchronized (mLock) {
+ mConstants.dumpProto(proto);
+ proto.write(PowerServiceDumpProto.DIRTY, mDirty);
+ proto.write(PowerServiceDumpProto.WAKEFULNESS, mWakefulness);
+ proto.write(PowerServiceDumpProto.IS_WAKEFULNESS_CHANGING, mWakefulnessChanging);
+ proto.write(PowerServiceDumpProto.IS_POWERED, mIsPowered);
+ proto.write(PowerServiceDumpProto.PLUG_TYPE, mPlugType);
+ proto.write(PowerServiceDumpProto.BATTERY_LEVEL, mBatteryLevel);
+ proto.write(
+ PowerServiceDumpProto.BATTERY_LEVEL_WHEN_DREAM_STARTED,
+ mBatteryLevelWhenDreamStarted);
+ proto.write(PowerServiceDumpProto.DOCK_STATE, mDockState);
+ proto.write(PowerServiceDumpProto.IS_STAY_ON, mStayOn);
+ proto.write(PowerServiceDumpProto.IS_PROXIMITY_POSITIVE, mProximityPositive);
+ proto.write(PowerServiceDumpProto.IS_BOOT_COMPLETED, mBootCompleted);
+ proto.write(PowerServiceDumpProto.IS_SYSTEM_READY, mSystemReady);
+ proto.write(
+ PowerServiceDumpProto.IS_HAL_AUTO_SUSPEND_MODE_ENABLED,
+ mHalAutoSuspendModeEnabled);
+ proto.write(
+ PowerServiceDumpProto.IS_HAL_AUTO_INTERACTIVE_MODE_ENABLED,
+ mHalInteractiveModeEnabled);
+
+ final long activeWakeLocksToken = proto.start(PowerServiceDumpProto.ACTIVE_WAKE_LOCKS);
+ proto.write(
+ PowerServiceDumpProto.ActiveWakeLocksProto.IS_CPU,
+ (mWakeLockSummary & WAKE_LOCK_CPU) != 0);
+ proto.write(
+ PowerServiceDumpProto.ActiveWakeLocksProto.IS_SCREEN_BRIGHT,
+ (mWakeLockSummary & WAKE_LOCK_SCREEN_BRIGHT) != 0);
+ proto.write(
+ PowerServiceDumpProto.ActiveWakeLocksProto.IS_SCREEN_DIM,
+ (mWakeLockSummary & WAKE_LOCK_SCREEN_DIM) != 0);
+ proto.write(
+ PowerServiceDumpProto.ActiveWakeLocksProto.IS_BUTTON_BRIGHT,
+ (mWakeLockSummary & WAKE_LOCK_BUTTON_BRIGHT) != 0);
+ proto.write(
+ PowerServiceDumpProto.ActiveWakeLocksProto.IS_PROXIMITY_SCREEN_OFF,
+ (mWakeLockSummary & WAKE_LOCK_PROXIMITY_SCREEN_OFF) != 0);
+ proto.write(
+ PowerServiceDumpProto.ActiveWakeLocksProto.IS_STAY_AWAKE,
+ (mWakeLockSummary & WAKE_LOCK_STAY_AWAKE) != 0);
+ proto.write(
+ PowerServiceDumpProto.ActiveWakeLocksProto.IS_DOZE,
+ (mWakeLockSummary & WAKE_LOCK_DOZE) != 0);
+ proto.write(
+ PowerServiceDumpProto.ActiveWakeLocksProto.IS_DRAW,
+ (mWakeLockSummary & WAKE_LOCK_DRAW) != 0);
+ proto.end(activeWakeLocksToken);
+
+ proto.write(PowerServiceDumpProto.NOTIFY_LONG_SCHEDULED_MS, mNotifyLongScheduled);
+ proto.write(PowerServiceDumpProto.NOTIFY_LONG_DISPATCHED_MS, mNotifyLongDispatched);
+ proto.write(PowerServiceDumpProto.NOTIFY_LONG_NEXT_CHECK_MS, mNotifyLongNextCheck);
+
+ final long userActivityToken = proto.start(PowerServiceDumpProto.USER_ACTIVITY);
+ proto.write(
+ PowerServiceDumpProto.UserActivityProto.IS_SCREEN_BRIGHT,
+ (mUserActivitySummary & USER_ACTIVITY_SCREEN_BRIGHT) != 0);
+ proto.write(
+ PowerServiceDumpProto.UserActivityProto.IS_SCREEN_DIM,
+ (mUserActivitySummary & USER_ACTIVITY_SCREEN_DIM) != 0);
+ proto.write(
+ PowerServiceDumpProto.UserActivityProto.IS_SCREEN_DREAM,
+ (mUserActivitySummary & USER_ACTIVITY_SCREEN_DREAM) != 0);
+ proto.end(userActivityToken);
+
+ proto.write(
+ PowerServiceDumpProto.IS_REQUEST_WAIT_FOR_NEGATIVE_PROXIMITY,
+ mRequestWaitForNegativeProximity);
+ proto.write(PowerServiceDumpProto.IS_SANDMAN_SCHEDULED, mSandmanScheduled);
+ proto.write(PowerServiceDumpProto.IS_SANDMAN_SUMMONED, mSandmanSummoned);
+ proto.write(PowerServiceDumpProto.IS_LOW_POWER_MODE_ENABLED, mLowPowerModeEnabled);
+ proto.write(PowerServiceDumpProto.IS_BATTERY_LEVEL_LOW, mBatteryLevelLow);
+ proto.write(PowerServiceDumpProto.IS_LIGHT_DEVICE_IDLE_MODE, mLightDeviceIdleMode);
+ proto.write(PowerServiceDumpProto.IS_DEVICE_IDLE_MODE, mDeviceIdleMode);
+
+ for (int id : mDeviceIdleWhitelist) {
+ proto.write(PowerServiceDumpProto.DEVICE_IDLE_WHITELIST, id);
+ }
+ for (int id : mDeviceIdleTempWhitelist) {
+ proto.write(PowerServiceDumpProto.DEVICE_IDLE_TEMP_WHITELIST, id);
+ }
+
+ proto.write(PowerServiceDumpProto.LAST_WAKE_TIME_MS, mLastWakeTime);
+ proto.write(PowerServiceDumpProto.LAST_SLEEP_TIME_MS, mLastSleepTime);
+ proto.write(PowerServiceDumpProto.LAST_USER_ACTIVITY_TIME_MS, mLastUserActivityTime);
+ proto.write(
+ PowerServiceDumpProto.LAST_USER_ACTIVITY_TIME_NO_CHANGE_LIGHTS_MS,
+ mLastUserActivityTimeNoChangeLights);
+ proto.write(
+ PowerServiceDumpProto.LAST_INTERACTIVE_POWER_HINT_TIME_MS,
+ mLastInteractivePowerHintTime);
+ proto.write(
+ PowerServiceDumpProto.LAST_SCREEN_BRIGHTNESS_BOOST_TIME_MS,
+ mLastScreenBrightnessBoostTime);
+ proto.write(
+ PowerServiceDumpProto.IS_SCREEN_BRIGHTNESS_BOOST_IN_PROGRESS,
+ mScreenBrightnessBoostInProgress);
+ proto.write(PowerServiceDumpProto.IS_DISPLAY_READY, mDisplayReady);
+ proto.write(
+ PowerServiceDumpProto.IS_HOLDING_WAKE_LOCK_SUSPEND_BLOCKER,
+ mHoldingWakeLockSuspendBlocker);
+ proto.write(
+ PowerServiceDumpProto.IS_HOLDING_DISPLAY_SUSPEND_BLOCKER,
+ mHoldingDisplaySuspendBlocker);
+
+ final long settingsAndConfigurationToken =
+ proto.start(PowerServiceDumpProto.SETTINGS_AND_CONFIGURATION);
+ proto.write(
+ PowerServiceSettingsAndConfigurationDumpProto
+ .IS_DECOUPLE_HAL_AUTO_SUSPEND_MODE_FROM_DISPLAY_CONFIG,
+ mDecoupleHalAutoSuspendModeFromDisplayConfig);
+ proto.write(
+ PowerServiceSettingsAndConfigurationDumpProto
+ .IS_DECOUPLE_HAL_INTERACTIVE_MODE_FROM_DISPLAY_CONFIG,
+ mDecoupleHalInteractiveModeFromDisplayConfig);
+ proto.write(
+ PowerServiceSettingsAndConfigurationDumpProto
+ .IS_WAKE_UP_WHEN_PLUGGED_OR_UNPLUGGED_CONFIG,
+ mWakeUpWhenPluggedOrUnpluggedConfig);
+ proto.write(
+ PowerServiceSettingsAndConfigurationDumpProto
+ .IS_WAKE_UP_WHEN_PLUGGED_OR_UNPLUGGED_IN_THEATER_MODE_CONFIG,
+ mWakeUpWhenPluggedOrUnpluggedInTheaterModeConfig);
+ proto.write(
+ PowerServiceSettingsAndConfigurationDumpProto.IS_THEATER_MODE_ENABLED,
+ mTheaterModeEnabled);
+ proto.write(
+ PowerServiceSettingsAndConfigurationDumpProto
+ .IS_SUSPEND_WHEN_SCREEN_OFF_DUE_TO_PROXIMITY_CONFIG,
+ mSuspendWhenScreenOffDueToProximityConfig);
+ proto.write(
+ PowerServiceSettingsAndConfigurationDumpProto.ARE_DREAMS_SUPPORTED_CONFIG,
+ mDreamsSupportedConfig);
+ proto.write(
+ PowerServiceSettingsAndConfigurationDumpProto
+ .ARE_DREAMS_ENABLED_BY_DEFAULT_CONFIG,
+ mDreamsEnabledByDefaultConfig);
+ proto.write(
+ PowerServiceSettingsAndConfigurationDumpProto
+ .ARE_DREAMS_ACTIVATED_ON_SLEEP_BY_DEFAULT_CONFIG,
+ mDreamsActivatedOnSleepByDefaultConfig);
+ proto.write(
+ PowerServiceSettingsAndConfigurationDumpProto
+ .ARE_DREAMS_ACTIVATED_ON_DOCK_BY_DEFAULT_CONFIG,
+ mDreamsActivatedOnDockByDefaultConfig);
+ proto.write(
+ PowerServiceSettingsAndConfigurationDumpProto
+ .ARE_DREAMS_ENABLED_ON_BATTERY_CONFIG,
+ mDreamsEnabledOnBatteryConfig);
+ proto.write(
+ PowerServiceSettingsAndConfigurationDumpProto
+ .DREAMS_BATTERY_LEVEL_MINIMUM_WHEN_POWERED_CONFIG,
+ mDreamsBatteryLevelMinimumWhenPoweredConfig);
+ proto.write(
+ PowerServiceSettingsAndConfigurationDumpProto
+ .DREAMS_BATTERY_LEVEL_MINIMUM_WHEN_NOT_POWERED_CONFIG,
+ mDreamsBatteryLevelMinimumWhenNotPoweredConfig);
+ proto.write(
+ PowerServiceSettingsAndConfigurationDumpProto
+ .DREAMS_BATTERY_LEVEL_DRAIN_CUTOFF_CONFIG,
+ mDreamsBatteryLevelDrainCutoffConfig);
+ proto.write(
+ PowerServiceSettingsAndConfigurationDumpProto.ARE_DREAMS_ENABLED_SETTING,
+ mDreamsEnabledSetting);
+ proto.write(
+ PowerServiceSettingsAndConfigurationDumpProto
+ .ARE_DREAMS_ACTIVATE_ON_SLEEP_SETTING,
+ mDreamsActivateOnSleepSetting);
+ proto.write(
+ PowerServiceSettingsAndConfigurationDumpProto
+ .ARE_DREAMS_ACTIVATE_ON_DOCK_SETTING,
+ mDreamsActivateOnDockSetting);
+ proto.write(
+ PowerServiceSettingsAndConfigurationDumpProto.IS_DOZE_AFTER_SCREEN_OFF_CONFIG,
+ mDozeAfterScreenOffConfig);
+ proto.write(
+ PowerServiceSettingsAndConfigurationDumpProto.IS_LOW_POWER_MODE_SETTING,
+ mLowPowerModeSetting);
+ proto.write(
+ PowerServiceSettingsAndConfigurationDumpProto.IS_AUTO_LOW_POWER_MODE_CONFIGURED,
+ mAutoLowPowerModeConfigured);
+ proto.write(
+ PowerServiceSettingsAndConfigurationDumpProto.IS_AUTO_LOW_POWER_MODE_SNOOZING,
+ mAutoLowPowerModeSnoozing);
+ proto.write(
+ PowerServiceSettingsAndConfigurationDumpProto
+ .MINIMUM_SCREEN_OFF_TIMEOUT_CONFIG_MS,
+ mMinimumScreenOffTimeoutConfig);
+ proto.write(
+ PowerServiceSettingsAndConfigurationDumpProto
+ .MAXIMUM_SCREEN_DIM_DURATION_CONFIG_MS,
+ mMaximumScreenDimDurationConfig);
+ proto.write(
+ PowerServiceSettingsAndConfigurationDumpProto.MAXIMUM_SCREEN_DIM_RATIO_CONFIG,
+ mMaximumScreenDimRatioConfig);
+ proto.write(
+ PowerServiceSettingsAndConfigurationDumpProto.SCREEN_OFF_TIMEOUT_SETTING_MS,
+ mScreenOffTimeoutSetting);
+ proto.write(
+ PowerServiceSettingsAndConfigurationDumpProto.SLEEP_TIMEOUT_SETTING_MS,
+ mSleepTimeoutSetting);
+ proto.write(
+ PowerServiceSettingsAndConfigurationDumpProto
+ .MAXIMUM_SCREEN_OFF_TIMEOUT_FROM_DEVICE_ADMIN_MS,
+ mMaximumScreenOffTimeoutFromDeviceAdmin);
+ proto.write(
+ PowerServiceSettingsAndConfigurationDumpProto
+ .IS_MAXIMUM_SCREEN_OFF_TIMEOUT_FROM_DEVICE_ADMIN_ENFORCED_LOCKED,
+ isMaximumScreenOffTimeoutFromDeviceAdminEnforcedLocked());
+
+ final long stayOnWhilePluggedInToken =
+ proto.start(
+ PowerServiceSettingsAndConfigurationDumpProto.STAY_ON_WHILE_PLUGGED_IN);
+ proto.write(
+ PowerServiceSettingsAndConfigurationDumpProto.StayOnWhilePluggedInProto
+ .IS_STAY_ON_WHILE_PLUGGED_IN_AC,
+ ((mStayOnWhilePluggedInSetting & BatteryManager.BATTERY_PLUGGED_AC) != 0));
+ proto.write(
+ PowerServiceSettingsAndConfigurationDumpProto.StayOnWhilePluggedInProto
+ .IS_STAY_ON_WHILE_PLUGGED_IN_USB,
+ ((mStayOnWhilePluggedInSetting & BatteryManager.BATTERY_PLUGGED_USB) != 0));
+ proto.write(
+ PowerServiceSettingsAndConfigurationDumpProto.StayOnWhilePluggedInProto
+ .IS_STAY_ON_WHILE_PLUGGED_IN_WIRELESS,
+ ((mStayOnWhilePluggedInSetting & BatteryManager.BATTERY_PLUGGED_WIRELESS)
+ != 0));
+ proto.end(stayOnWhilePluggedInToken);
+
+ proto.write(
+ PowerServiceSettingsAndConfigurationDumpProto.SCREEN_BRIGHTNESS_SETTING,
+ mScreenBrightnessSetting);
+ proto.write(
+ PowerServiceSettingsAndConfigurationDumpProto
+ .SCREEN_AUTO_BRIGHTNESS_ADJUSTMENT_SETTING,
+ mScreenAutoBrightnessAdjustmentSetting);
+ proto.write(
+ PowerServiceSettingsAndConfigurationDumpProto.SCREEN_BRIGHTNESS_MODE_SETTING,
+ mScreenBrightnessModeSetting);
+ proto.write(
+ PowerServiceSettingsAndConfigurationDumpProto
+ .SCREEN_BRIGHTNESS_OVERRIDE_FROM_WINDOW_MANAGER,
+ mScreenBrightnessOverrideFromWindowManager);
+ proto.write(
+ PowerServiceSettingsAndConfigurationDumpProto
+ .USER_ACTIVITY_TIMEOUT_OVERRIDE_FROM_WINDOW_MANAGER_MS,
+ mUserActivityTimeoutOverrideFromWindowManager);
+ proto.write(
+ PowerServiceSettingsAndConfigurationDumpProto
+ .IS_USER_INACTIVE_OVERRIDE_FROM_WINDOW_MANAGER,
+ mUserInactiveOverrideFromWindowManager);
+ proto.write(
+ PowerServiceSettingsAndConfigurationDumpProto
+ .TEMPORARY_SCREEN_BRIGHTNESS_SETTING_OVERRIDE,
+ mTemporaryScreenBrightnessSettingOverride);
+ proto.write(
+ PowerServiceSettingsAndConfigurationDumpProto
+ .TEMPORARY_SCREEN_AUTO_BRIGHTNESS_ADJUSTMENT_SETTING_OVERRIDE,
+ mTemporaryScreenAutoBrightnessAdjustmentSettingOverride);
+ proto.write(
+ PowerServiceSettingsAndConfigurationDumpProto
+ .DOZE_SCREEN_STATE_OVERRIDE_FROM_DREAM_MANAGER,
+ mDozeScreenStateOverrideFromDreamManager);
+ proto.write(
+ PowerServiceSettingsAndConfigurationDumpProto
+ .DOZED_SCREEN_BRIGHTNESS_OVERRIDE_FROM_DREAM_MANAGER,
+ mDozeScreenBrightnessOverrideFromDreamManager);
+
+ final long screenBrightnessSettingLimitsToken =
+ proto.start(
+ PowerServiceSettingsAndConfigurationDumpProto
+ .SCREEN_BRIGHTNESS_SETTING_LIMITS);
+ proto.write(
+ PowerServiceSettingsAndConfigurationDumpProto.ScreenBrightnessSettingLimitsProto
+ .SETTING_MINIMUM,
+ mScreenBrightnessSettingMinimum);
+ proto.write(
+ PowerServiceSettingsAndConfigurationDumpProto.ScreenBrightnessSettingLimitsProto
+ .SETTING_MAXIMUM,
+ mScreenBrightnessSettingMaximum);
+ proto.write(
+ PowerServiceSettingsAndConfigurationDumpProto.ScreenBrightnessSettingLimitsProto
+ .SETTING_DEFAULT,
+ mScreenBrightnessSettingDefault);
+ proto.write(
+ PowerServiceSettingsAndConfigurationDumpProto.ScreenBrightnessSettingLimitsProto
+ .SETTING_FOR_VR_DEFAULT,
+ mScreenBrightnessForVrSettingDefault);
+ proto.end(screenBrightnessSettingLimitsToken);
+
+ proto.write(
+ PowerServiceSettingsAndConfigurationDumpProto.SCREEN_BRIGHTNESS_FOR_VR_SETTING,
+ mScreenBrightnessForVrSetting);
+ proto.write(
+ PowerServiceSettingsAndConfigurationDumpProto.IS_DOUBLE_TAP_WAKE_ENABLED,
+ mDoubleTapWakeEnabled);
+ proto.write(
+ PowerServiceSettingsAndConfigurationDumpProto.IS_VR_MODE_ENABLED,
+ mIsVrModeEnabled);
+ proto.end(settingsAndConfigurationToken);
+
+ final int sleepTimeout = getSleepTimeoutLocked();
+ final int screenOffTimeout = getScreenOffTimeoutLocked(sleepTimeout);
+ final int screenDimDuration = getScreenDimDurationLocked(screenOffTimeout);
+ proto.write(PowerServiceDumpProto.SLEEP_TIMEOUT_MS, sleepTimeout);
+ proto.write(PowerServiceDumpProto.SCREEN_OFF_TIMEOUT_MS, screenOffTimeout);
+ proto.write(PowerServiceDumpProto.SCREEN_DIM_DURATION_MS, screenDimDuration);
+ proto.write(PowerServiceDumpProto.ARE_UIDS_CHANGING, mUidsChanging);
+ proto.write(PowerServiceDumpProto.ARE_UIDS_CHANGED, mUidsChanged);
+
+ for (int i = 0; i < mUidState.size(); i++) {
+ final UidState state = mUidState.valueAt(i);
+ final long uIDToken = proto.start(PowerServiceDumpProto.UIDS);
+ final int uid = mUidState.keyAt(i);
+ proto.write(PowerServiceDumpProto.UidProto.UID, uid);
+ proto.write(PowerServiceDumpProto.UidProto.UID_STRING, UserHandle.formatUid(uid));
+ proto.write(PowerServiceDumpProto.UidProto.IS_ACTIVE, state.mActive);
+ proto.write(PowerServiceDumpProto.UidProto.NUM_WAKE_LOCKS, state.mNumWakeLocks);
+ if (state.mProcState == ActivityManager.PROCESS_STATE_UNKNOWN) {
+ proto.write(PowerServiceDumpProto.UidProto.IS_PROCESS_STATE_UNKNOWN, true);
+ } else {
+ proto.write(PowerServiceDumpProto.UidProto.PROCESS_STATE, state.mProcState);
+ }
+ proto.end(uIDToken);
+ }
+
+ mHandler.getLooper().writeToProto(proto, PowerServiceDumpProto.LOOPER);
+
+ for (WakeLock wl : mWakeLocks) {
+ wl.writeToProto(proto, PowerServiceDumpProto.WAKE_LOCKS);
+ }
+
+ for (SuspendBlocker sb : mSuspendBlockers) {
+ sb.writeToProto(proto, PowerServiceDumpProto.SUSPEND_BLOCKERS);
+ }
+ wcd = mWirelessChargerDetector;
+ }
+
+ if (wcd != null) {
+ wcd.writeToProto(proto, PowerServiceDumpProto.WIRELESS_CHARGER_DETECTOR);
+ }
+ proto.flush();
+ }
+
private SuspendBlocker createSuspendBlockerLocked(String name) {
SuspendBlocker suspendBlocker = new SuspendBlockerImpl(name);
mSuspendBlockers.add(suspendBlocker);
@@ -3471,6 +3828,32 @@
return sb.toString();
}
+ public void writeToProto(ProtoOutputStream proto, long fieldId) {
+ final long wakeLockToken = proto.start(fieldId);
+ proto.write(WakeLockProto.LOCK_LEVEL, (mFlags & PowerManager.WAKE_LOCK_LEVEL_MASK));
+ proto.write(WakeLockProto.TAG, mTag);
+
+ final long wakeLockFlagsToken = proto.start(WakeLockProto.FLAGS);
+ proto.write(WakeLockProto.WakeLockFlagsProto.IS_ACQUIRE_CAUSES_WAKEUP,
+ (mFlags & PowerManager.ACQUIRE_CAUSES_WAKEUP)!=0);
+ proto.write(WakeLockProto.WakeLockFlagsProto.IS_ON_AFTER_RELEASE,
+ (mFlags & PowerManager.ON_AFTER_RELEASE)!=0);
+ proto.end(wakeLockFlagsToken);
+
+ proto.write(WakeLockProto.IS_DISABLED, mDisabled);
+ if (mNotifiedAcquired) {
+ proto.write(WakeLockProto.ACQ_MS, mAcquireTime);
+ }
+ proto.write(WakeLockProto.IS_NOTIFIED_LONG, mNotifiedLong);
+ proto.write(WakeLockProto.UID, mOwnerUid);
+ proto.write(WakeLockProto.PID, mOwnerPid);
+
+ if (mWorkSource != null) {
+ mWorkSource.writeToProto(proto, WakeLockProto.WORK_SOURCE);
+ }
+ proto.end(wakeLockToken);
+ }
+
@SuppressWarnings("deprecation")
private String getLockLevelString() {
switch (mFlags & PowerManager.WAKE_LOCK_LEVEL_MASK) {
@@ -3568,6 +3951,15 @@
return mName + ": ref count=" + mReferenceCount;
}
}
+
+ public void writeToProto(ProtoOutputStream proto, long fieldId) {
+ final long sbToken = proto.start(fieldId);
+ synchronized (this) {
+ proto.write(SuspendBlockerProto.NAME, mName);
+ proto.write(SuspendBlockerProto.REFERENCE_COUNT, mReferenceCount);
+ }
+ proto.end(sbToken);
+ }
}
static final class UidState {
@@ -4055,8 +4447,19 @@
}
final long ident = Binder.clearCallingIdentity();
+
+ boolean isDumpProto = false;
+ for (String arg : args) {
+ if (arg.equals("--proto")) {
+ isDumpProto = true;
+ }
+ }
try {
- dumpInternal(pw);
+ if (isDumpProto) {
+ dumpProto(fd);
+ } else {
+ dumpInternal(pw);
+ }
} finally {
Binder.restoreCallingIdentity(ident);
}
diff --git a/services/core/java/com/android/server/power/SuspendBlocker.java b/services/core/java/com/android/server/power/SuspendBlocker.java
index 70b278a..30b35f0 100644
--- a/services/core/java/com/android/server/power/SuspendBlocker.java
+++ b/services/core/java/com/android/server/power/SuspendBlocker.java
@@ -16,6 +16,8 @@
package com.android.server.power;
+import android.util.proto.ProtoOutputStream;
+
/**
* Low-level suspend blocker mechanism equivalent to holding a partial wake lock.
*
@@ -40,4 +42,6 @@
* The system may crash.
*/
void release();
+
+ void writeToProto(ProtoOutputStream proto, long fieldId);
}
diff --git a/services/core/java/com/android/server/power/WirelessChargerDetector.java b/services/core/java/com/android/server/power/WirelessChargerDetector.java
index 38f5d77..6ee9dcd 100644
--- a/services/core/java/com/android/server/power/WirelessChargerDetector.java
+++ b/services/core/java/com/android/server/power/WirelessChargerDetector.java
@@ -24,8 +24,10 @@
import android.os.Handler;
import android.os.Message;
import android.os.SystemClock;
+import android.service.power.WirelessChargerDetectorProto;
import android.util.Slog;
import android.util.TimeUtils;
+import android.util.proto.ProtoOutputStream;
import java.io.PrintWriter;
@@ -170,6 +172,44 @@
}
}
+ public void writeToProto(ProtoOutputStream proto, long fieldId) {
+ final long wcdToken = proto.start(fieldId);
+ synchronized (mLock) {
+ proto.write(WirelessChargerDetectorProto.IS_POWERED_WIRELESSLY, mPoweredWirelessly);
+ proto.write(WirelessChargerDetectorProto.IS_AT_REST, mAtRest);
+
+ final long restVectorToken = proto.start(WirelessChargerDetectorProto.REST);
+ proto.write(WirelessChargerDetectorProto.VectorProto.X, mRestX);
+ proto.write(WirelessChargerDetectorProto.VectorProto.Y, mRestY);
+ proto.write(WirelessChargerDetectorProto.VectorProto.Z, mRestZ);
+ proto.end(restVectorToken);
+
+ proto.write(
+ WirelessChargerDetectorProto.IS_DETECTION_IN_PROGRESS, mDetectionInProgress);
+ proto.write(WirelessChargerDetectorProto.DETECTION_START_TIME_MS, mDetectionStartTime);
+ proto.write(
+ WirelessChargerDetectorProto.IS_MUST_UPDATE_REST_POSITION,
+ mMustUpdateRestPosition);
+ proto.write(WirelessChargerDetectorProto.TOTAL_SAMPLES, mTotalSamples);
+ proto.write(WirelessChargerDetectorProto.MOVING_SAMPLES, mMovingSamples);
+
+ final long firstSampleVectorToken =
+ proto.start(WirelessChargerDetectorProto.FIRST_SAMPLE);
+ proto.write(WirelessChargerDetectorProto.VectorProto.X, mFirstSampleX);
+ proto.write(WirelessChargerDetectorProto.VectorProto.Y, mFirstSampleY);
+ proto.write(WirelessChargerDetectorProto.VectorProto.Z, mFirstSampleZ);
+ proto.end(firstSampleVectorToken);
+
+ final long lastSampleVectorToken =
+ proto.start(WirelessChargerDetectorProto.LAST_SAMPLE);
+ proto.write(WirelessChargerDetectorProto.VectorProto.X, mLastSampleX);
+ proto.write(WirelessChargerDetectorProto.VectorProto.Y, mLastSampleY);
+ proto.write(WirelessChargerDetectorProto.VectorProto.Z, mLastSampleZ);
+ proto.end(lastSampleVectorToken);
+ }
+ proto.end(wcdToken);
+ }
+
/**
* Updates the charging state and returns true if docking was detected.
*
diff --git a/services/core/java/com/android/server/storage/DeviceStorageMonitorService.java b/services/core/java/com/android/server/storage/DeviceStorageMonitorService.java
index afdec9f..12836db 100644
--- a/services/core/java/com/android/server/storage/DeviceStorageMonitorService.java
+++ b/services/core/java/com/android/server/storage/DeviceStorageMonitorService.java
@@ -17,6 +17,7 @@
package com.android.server.storage;
import android.app.NotificationChannel;
+import com.android.internal.notification.SystemNotificationChannels;
import com.android.server.EventLogTags;
import com.android.server.SystemService;
import com.android.server.pm.InstructionSets;
@@ -141,7 +142,7 @@
*/
static final String SERVICE = "devicestoragemonitor";
- private static final String NOTIFICATION_CHANNEL_ID = SERVICE;
+ private static final String TV_NOTIFICATION_CHANNEL_ID = "devicestoragemonitor.tv";
/**
* Handler that checks the amount of disk space on the device and sends a
@@ -388,14 +389,13 @@
PackageManager packageManager = context.getPackageManager();
boolean isTv = packageManager.hasSystemFeature(PackageManager.FEATURE_LEANBACK);
- int importance = isTv
- ? NotificationManager.IMPORTANCE_HIGH // Do not change: this is TV-specific
- : NotificationManager.IMPORTANCE_LOW;
- notificationMgr.createNotificationChannel(
- new NotificationChannel(NOTIFICATION_CHANNEL_ID,
- context.getString(
- com.android.internal.R.string.device_storage_monitor_notification_channel),
- importance));
+ if (isTv) {
+ notificationMgr.createNotificationChannel(new NotificationChannel(
+ TV_NOTIFICATION_CHANNEL_ID,
+ context.getString(
+ com.android.internal.R.string.device_storage_monitor_notification_channel),
+ NotificationManager.IMPORTANCE_HIGH));
+ }
publishBinderService(SERVICE, mRemoteService);
publishLocalService(DeviceStorageMonitorInternal.class, mLocalService);
@@ -495,21 +495,22 @@
: com.android.internal.R.string.low_internal_storage_view_text_no_boot);
PendingIntent intent = PendingIntent.getActivityAsUser(context, 0, lowMemIntent, 0,
null, UserHandle.CURRENT);
- Notification notification = new Notification.Builder(context)
- .setSmallIcon(com.android.internal.R.drawable.stat_notify_disk_full)
- .setTicker(title)
- .setColor(context.getColor(
- com.android.internal.R.color.system_notification_accent_color))
- .setContentTitle(title)
- .setContentText(details)
- .setContentIntent(intent)
- .setStyle(new Notification.BigTextStyle()
- .bigText(details))
- .setVisibility(Notification.VISIBILITY_PUBLIC)
- .setCategory(Notification.CATEGORY_SYSTEM)
- .setChannel(NOTIFICATION_CHANNEL_ID)
- .extend(new Notification.TvExtender())
- .build();
+ Notification notification =
+ new Notification.Builder(context, SystemNotificationChannels.ALERTS)
+ .setSmallIcon(com.android.internal.R.drawable.stat_notify_disk_full)
+ .setTicker(title)
+ .setColor(context.getColor(
+ com.android.internal.R.color.system_notification_accent_color))
+ .setContentTitle(title)
+ .setContentText(details)
+ .setContentIntent(intent)
+ .setStyle(new Notification.BigTextStyle()
+ .bigText(details))
+ .setVisibility(Notification.VISIBILITY_PUBLIC)
+ .setCategory(Notification.CATEGORY_SYSTEM)
+ .extend(new Notification.TvExtender()
+ .setChannel(TV_NOTIFICATION_CHANNEL_ID))
+ .build();
notification.flags |= Notification.FLAG_NO_CLEAR;
notificationMgr.notifyAsUser(null, LOW_MEMORY_NOTIFICATION_ID, notification,
UserHandle.ALL);
diff --git a/services/core/java/com/android/server/vr/VrManagerService.java b/services/core/java/com/android/server/vr/VrManagerService.java
index d179ea7..3df4d24 100644
--- a/services/core/java/com/android/server/vr/VrManagerService.java
+++ b/services/core/java/com/android/server/vr/VrManagerService.java
@@ -680,10 +680,10 @@
}
}
- mCurrentVrModeComponent = calling;
if (calling != null && !Objects.equals(calling, mCurrentVrModeComponent)) {
sendUpdatedCaller = true;
}
+ mCurrentVrModeComponent = calling;
if (mCurrentVrModeUser != userId) {
mCurrentVrModeUser = userId;
diff --git a/services/core/java/com/android/server/wm/AccessibilityController.java b/services/core/java/com/android/server/wm/AccessibilityController.java
index f7a9e41..b7479da 100644
--- a/services/core/java/com/android/server/wm/AccessibilityController.java
+++ b/services/core/java/com/android/server/wm/AccessibilityController.java
@@ -226,8 +226,8 @@
Matrix outMatrix) {
sTempFloats[Matrix.MSCALE_X] = windowState.mWinAnimator.mDsDx;
sTempFloats[Matrix.MSKEW_Y] = windowState.mWinAnimator.mDtDx;
- sTempFloats[Matrix.MSKEW_X] = windowState.mWinAnimator.mDsDy;
- sTempFloats[Matrix.MSCALE_Y] = windowState.mWinAnimator.mDtDy;
+ sTempFloats[Matrix.MSKEW_X] = windowState.mWinAnimator.mDtDy;
+ sTempFloats[Matrix.MSCALE_Y] = windowState.mWinAnimator.mDsDy;
sTempFloats[Matrix.MTRANS_X] = windowState.mShownPosition.x;
sTempFloats[Matrix.MTRANS_Y] = windowState.mShownPosition.y;
sTempFloats[Matrix.MPERSP_0] = 0;
diff --git a/services/core/java/com/android/server/wm/AppWindowAnimator.java b/services/core/java/com/android/server/wm/AppWindowAnimator.java
index c42647e..e3941b9 100644
--- a/services/core/java/com/android/server/wm/AppWindowAnimator.java
+++ b/services/core/java/com/android/server/wm/AppWindowAnimator.java
@@ -248,8 +248,9 @@
}
}
- void updateLayers() {
- thumbnailLayer = mAppToken.adjustAnimLayer(animLayerAdjustment);
+ private void updateLayers() {
+ mAppToken.getDisplayContent().assignWindowLayers(false /* relayoutNeeded */);
+ thumbnailLayer = mAppToken.getHighestAnimLayer();
}
private void stepThumbnailAnimation(long currentTime) {
diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java
index 2263042..e67c91e 100644
--- a/services/core/java/com/android/server/wm/AppWindowToken.java
+++ b/services/core/java/com/android/server/wm/AppWindowToken.java
@@ -762,6 +762,16 @@
if (canFreezeBounds()) {
freezeBounds();
}
+
+ // In the process of tearing down before relaunching, the app will
+ // try and clean up it's child surfaces. We need to prevent this from
+ // happening, so we sever the children, transfering their ownership
+ // from the client it-self to the parent surface (owned by us).
+ for (int i = mChildren.size() - 1; i >= 0; i--) {
+ final WindowState w = mChildren.get(i);
+ w.mWinAnimator.detachChildren();
+ }
+
mPendingRelaunchCount++;
}
@@ -1409,6 +1419,11 @@
}
@Override
+ int getAnimLayerAdjustment() {
+ return mAppAnimator.animLayerAdjustment;
+ }
+
+ @Override
void dump(PrintWriter pw, String prefix) {
super.dump(pw, prefix);
if (appToken != null) {
diff --git a/services/core/java/com/android/server/wm/BoundsAnimationController.java b/services/core/java/com/android/server/wm/BoundsAnimationController.java
index 01bd86d..837b69e 100644
--- a/services/core/java/com/android/server/wm/BoundsAnimationController.java
+++ b/services/core/java/com/android/server/wm/BoundsAnimationController.java
@@ -272,18 +272,10 @@
void onAnimationEnd();
void moveToFullscreen();
-
- void getFullScreenBounds(Rect bounds);
}
- void animateBounds(final AnimateBoundsUser target, Rect from, Rect to, int animationDuration) {
- boolean moveToFullscreen = false;
- if (to == null) {
- to = new Rect();
- target.getFullScreenBounds(to);
- moveToFullscreen = true;
- }
-
+ void animateBounds(final AnimateBoundsUser target, Rect from, Rect to, int animationDuration,
+ boolean moveToFullscreen) {
final BoundsAnimator existing = mRunningAnimations.get(target);
final boolean replacing = existing != null;
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 2c315445..461c3fa 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -341,9 +341,6 @@
}
};
- private final Consumer<WindowState> mSetInputMethodAnimLayerAdjustment =
- w -> w.adjustAnimLayer(mInputMethodAnimLayerAdjustment);
-
private final Consumer<WindowState> mScheduleToastTimeout = w -> {
final int lostFocusUid = mTmpWindow.mOwnerUid;
final Handler handler = mService.mH;
@@ -1281,8 +1278,7 @@
void setInputMethodAnimLayerAdjustment(int adj) {
if (DEBUG_LAYERS) Slog.v(TAG_WM, "Setting im layer adj to " + adj);
mInputMethodAnimLayerAdjustment = adj;
- mImeWindowsContainers.forAllWindows(mSetInputMethodAnimLayerAdjustment,
- true /* traverseTopToBottom */);
+ assignWindowLayers(false /* relayoutNeeded */);
}
/**
@@ -1588,9 +1584,24 @@
// TODO(multidisplay): Needs some serious rethought when the target and IME are not on the
// same display. Or even when the current IME/target are not on the same screen as the next
// IME/target. For now only look for input windows on the main screen.
- mUpdateImeTarget = updateImeTarget;
- WindowState target = getWindow(mComputeImeTargetPredicate);
+ // The target candidate provided by the IME tells us which window token, but not which
+ // window within the token (e.g. child windows...). So, we use the token to look-up the
+ // best target window.
+ // TODO: Have the input method service report the right window with the token vs. just the
+ // base window of the token.
+ final WindowState baseWin = mService.getWindow(mService.mInputMethodTargetCandidate);
+ final WindowToken targetToken = baseWin != null ? baseWin.mToken : null;
+ WindowState target = targetToken != null ?
+ targetToken.getWindow(mComputeImeTargetPredicate) : null;
+ // If there isn't a better candidate in the token (maybe because they are not visible), then
+ // fall back to targeting the base window of the token, so the IME can still maintain the
+ // right z-order based on the last person that set it vs. changing its z-order to the very
+ // up since there if target is null.
+ // TODO: Consider z-ordering IME to bottom instead of top if there is no visible target.
+ // Also, consider tying the visible the visibility of the IME to the current target. I.e if
+ // target isn't visible, then IME shouldn't be visible.
+ target = target == null ? baseWin : target;
// Yet more tricksyness! If this window is a "starting" window, we do actually want
// to be on top of it, but it is not -really- where input will go. So look down below
@@ -1673,7 +1684,7 @@
if (DEBUG_INPUT_METHOD) Slog.w(TAG_WM, "Moving IM target from " + curTarget + " to "
+ target + (SHOW_STACK_CRAWLS ? " Callers=" + Debug.getCallers(4) : ""));
setInputMethodTarget(target, false, target.mAppToken != null
- ? target.mAppToken.mAppAnimator.animLayerAdjustment : 0);
+ ? target.mAppToken.getAnimLayerAdjustment() : 0);
}
return target;
diff --git a/services/core/java/com/android/server/wm/PinnedStackController.java b/services/core/java/com/android/server/wm/PinnedStackController.java
index cfeb198..2a20a70 100644
--- a/services/core/java/com/android/server/wm/PinnedStackController.java
+++ b/services/core/java/com/android/server/wm/PinnedStackController.java
@@ -230,54 +230,37 @@
}
/**
- * @return the movement bounds for the given {@param stackBounds} and the current state of the
- * controller.
+ * Updates the display info, calculating and returning the new stack and movement bounds in the
+ * new orientation of the device if necessary.
*/
- private Rect getMovementBounds(Rect stackBounds) {
- return getMovementBounds(stackBounds, true /* adjustForIme */);
- }
-
- /**
- * @return the movement bounds for the given {@param stackBounds} and the current state of the
- * controller.
- */
- private Rect getMovementBounds(Rect stackBounds, boolean adjustForIme) {
- final Rect movementBounds = new Rect();
- getInsetBounds(movementBounds);
-
- // Apply the movement bounds adjustments based on the current state
- mSnapAlgorithm.getMovementBounds(stackBounds, movementBounds, movementBounds,
- (adjustForIme && mIsImeShowing) ? mImeHeight : 0);
- return movementBounds;
- }
-
- /**
- * @param preChangeTargetBounds The final bounds of the stack if it is currently animating
- * @return the repositioned PIP bounds given it's pre-change bounds, and the new display
- * content.
- */
- Rect onDisplayChanged(Rect preChangeStackBounds, Rect preChangeTargetBounds,
- DisplayContent displayContent) {
- final Rect postChangeStackBounds = new Rect(preChangeTargetBounds);
- final DisplayInfo displayInfo = displayContent.getDisplayInfo();
- if (!mDisplayInfo.equals(displayInfo)) {
- // Calculate the snap fraction of the current stack along the old movement bounds, and
- // then update the stack bounds to the same fraction along the rotated movement bounds.
- final Rect preChangeMovementBounds = getMovementBounds(preChangeStackBounds);
- final float snapFraction = mSnapAlgorithm.getSnapFraction(preChangeStackBounds,
- preChangeMovementBounds);
- mDisplayInfo.copyFrom(displayInfo);
-
- final Rect postChangeMovementBounds = getMovementBounds(preChangeStackBounds,
- false /* adjustForIme */);
- mSnapAlgorithm.applySnapFraction(postChangeStackBounds, postChangeMovementBounds,
- snapFraction);
- if (mIsMinimized) {
- applyMinimizedOffset(postChangeStackBounds, postChangeMovementBounds);
- }
- notifyMovementBoundsChanged(false /* fromImeAdjustment */);
+ void onTaskStackBoundsChanged(Rect targetBounds, Rect outBounds) {
+ final DisplayInfo displayInfo = mDisplayContent.getDisplayInfo();
+ if (mDisplayInfo.equals(displayInfo)) {
+ return;
}
- return postChangeStackBounds;
+
+ mTmpRect.set(targetBounds);
+ final Rect postChangeStackBounds = mTmpRect;
+
+ // Calculate the snap fraction of the current stack along the old movement bounds
+ final Rect preChangeMovementBounds = getMovementBounds(postChangeStackBounds);
+ final float snapFraction = mSnapAlgorithm.getSnapFraction(postChangeStackBounds,
+ preChangeMovementBounds);
+ mDisplayInfo.copyFrom(displayInfo);
+
+ // Calculate the stack bounds in the new orientation to the same same fraction along the
+ // rotated movement bounds.
+ final Rect postChangeMovementBounds = getMovementBounds(postChangeStackBounds,
+ false /* adjustForIme */);
+ mSnapAlgorithm.applySnapFraction(postChangeStackBounds, postChangeMovementBounds,
+ snapFraction);
+ if (mIsMinimized) {
+ applyMinimizedOffset(postChangeStackBounds, postChangeMovementBounds);
+ }
+
+ notifyMovementBoundsChanged(false /* fromImeAdjustment */);
+
+ outBounds.set(postChangeStackBounds);
}
/**
@@ -387,6 +370,28 @@
}
/**
+ * @return the movement bounds for the given {@param stackBounds} and the current state of the
+ * controller.
+ */
+ private Rect getMovementBounds(Rect stackBounds) {
+ return getMovementBounds(stackBounds, true /* adjustForIme */);
+ }
+
+ /**
+ * @return the movement bounds for the given {@param stackBounds} and the current state of the
+ * controller.
+ */
+ private Rect getMovementBounds(Rect stackBounds, boolean adjustForIme) {
+ final Rect movementBounds = new Rect();
+ getInsetBounds(movementBounds);
+
+ // Apply the movement bounds adjustments based on the current state
+ mSnapAlgorithm.getMovementBounds(stackBounds, movementBounds, movementBounds,
+ (adjustForIme && mIsImeShowing) ? mImeHeight : 0);
+ return movementBounds;
+ }
+
+ /**
* Applies the minimized offsets to the given stack bounds.
*/
private void applyMinimizedOffset(Rect stackBounds, Rect movementBounds) {
diff --git a/services/core/java/com/android/server/wm/PinnedStackWindowController.java b/services/core/java/com/android/server/wm/PinnedStackWindowController.java
new file mode 100644
index 0000000..71f88de
--- /dev/null
+++ b/services/core/java/com/android/server/wm/PinnedStackWindowController.java
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.server.wm;
+
+import static android.app.ActivityManager.StackId.FULLSCREEN_WORKSPACE_STACK_ID;
+
+import android.app.RemoteAction;
+import android.graphics.Rect;
+
+import com.android.server.UiThread;
+
+import java.util.List;
+
+/**
+ * Controller for the pinned stack container. See {@link StackWindowController}.
+ */
+public class PinnedStackWindowController extends StackWindowController {
+
+ private Rect mTmpBoundsRect = new Rect();
+
+ public PinnedStackWindowController(int stackId, StackWindowListener listener, int displayId,
+ boolean onTop, Rect outBounds) {
+ super(stackId, listener, displayId, onTop, outBounds, WindowManagerService.getInstance());
+ }
+
+ /**
+ * Animates the pinned stack.
+ */
+ public void animateResizePinnedStack(Rect bounds, int animationDuration) {
+ synchronized (mWindowMap) {
+ if (mContainer == null) {
+ throw new IllegalArgumentException("Pinned stack container not found :(");
+ }
+
+ // Get non-null fullscreen bounds if the bounds are null
+ final boolean moveToFullscreen = bounds == null;
+ bounds = getPinnedStackAnimationBounds(bounds);
+
+ // If the bounds are truly null, then there was no fullscreen stack at this time, so
+ // animate this to the full display bounds
+ final Rect toBounds;
+ if (bounds == null) {
+ toBounds = new Rect();
+ mContainer.getDisplayContent().getLogicalDisplayRect(toBounds);
+ } else {
+ toBounds = bounds;
+ }
+
+ final Rect originalBounds = new Rect();
+ mContainer.getBounds(originalBounds);
+ mContainer.setAnimatingBounds(toBounds);
+ UiThread.getHandler().post(() -> {
+ mService.mBoundsAnimationController.animateBounds(mContainer, originalBounds,
+ toBounds, animationDuration, moveToFullscreen);
+ });
+ }
+ }
+
+ /**
+ * Sets the current picture-in-picture aspect ratio.
+ */
+ public void setPictureInPictureAspectRatio(float aspectRatio) {
+ synchronized (mWindowMap) {
+ if (!mService.mSupportsPictureInPicture || mContainer == null) {
+ return;
+ }
+
+ final int displayId = mContainer.getDisplayContent().getDisplayId();
+ final Rect toBounds = mService.getPictureInPictureBounds(displayId, aspectRatio);
+ final Rect targetBounds = new Rect();
+ mContainer.getAnimatingBounds(targetBounds);
+ if (!toBounds.equals(targetBounds)) {
+ animateResizePinnedStack(toBounds, -1 /* duration */);
+ }
+
+ final PinnedStackController pinnedStackController =
+ mContainer.getDisplayContent().getPinnedStackController();
+ pinnedStackController.setAspectRatio(
+ pinnedStackController.isValidPictureInPictureAspectRatio(aspectRatio)
+ ? aspectRatio : -1f);
+ }
+ }
+
+ /**
+ * Sets the current picture-in-picture actions.
+ */
+ public void setPictureInPictureActions(List<RemoteAction> actions) {
+ synchronized (mWindowMap) {
+ if (!mService.mSupportsPictureInPicture || mContainer == null) {
+ return;
+ }
+
+ mContainer.getDisplayContent().getPinnedStackController().setActions(actions);
+ }
+ }
+
+ /**
+ * Checks the {@param bounds} and retirms non-null fullscreen bounds for the pinned stack
+ * animation if necessary.
+ */
+ private Rect getPinnedStackAnimationBounds(Rect bounds) {
+ mService.getStackBounds(FULLSCREEN_WORKSPACE_STACK_ID, mTmpBoundsRect);
+ if (bounds == null && !mTmpBoundsRect.isEmpty()) {
+ bounds = new Rect(mTmpBoundsRect);
+ }
+ return bounds;
+ }
+}
diff --git a/services/core/java/com/android/server/wm/StackWindowController.java b/services/core/java/com/android/server/wm/StackWindowController.java
index 142f69a..b0e115b 100644
--- a/services/core/java/com/android/server/wm/StackWindowController.java
+++ b/services/core/java/com/android/server/wm/StackWindowController.java
@@ -199,59 +199,6 @@
}
}
- // TODO: This and similar methods should be separated into PinnedStackWindowContainerController
- public void animateResizePinnedStack(final Rect bounds, final int animationDuration) {
- synchronized (mWindowMap) {
- if (mContainer == null) {
- throw new IllegalArgumentException("Pinned stack container not found :(");
- }
- final Rect originalBounds = new Rect();
- mContainer.getBounds(originalBounds);
- mContainer.setAnimatingBounds(bounds);
- UiThread.getHandler().post(new Runnable() {
- @Override
- public void run() {
- mService.mBoundsAnimationController.animateBounds(
- mContainer, originalBounds, bounds, animationDuration);
- }
- });
- }
- }
-
- /** Sets the current picture-in-picture aspect ratio. */
- public void setPictureInPictureAspectRatio(float aspectRatio) {
- synchronized (mWindowMap) {
- if (!mService.mSupportsPictureInPicture || mContainer == null) {
- return;
- }
-
- final int displayId = mContainer.getDisplayContent().getDisplayId();
- final Rect toBounds = mService.getPictureInPictureBounds(displayId, aspectRatio);
- final Rect targetBounds = new Rect();
- mContainer.getAnimatingBounds(targetBounds);
- if (!toBounds.equals(targetBounds)) {
- animateResizePinnedStack(toBounds, -1 /* duration */);
- }
-
- final PinnedStackController pinnedStackController =
- mContainer.getDisplayContent().getPinnedStackController();
- pinnedStackController.setAspectRatio(
- pinnedStackController.isValidPictureInPictureAspectRatio(aspectRatio)
- ? aspectRatio : -1f);
- }
- }
-
- /** Sets the current picture-in-picture actions. */
- public void setPictureInPictureActions(List<RemoteAction> actions) {
- synchronized (mWindowMap) {
- if (!mService.mSupportsPictureInPicture || mContainer == null) {
- return;
- }
-
- mContainer.getDisplayContent().getPinnedStackController().setActions(actions);
- }
- }
-
public void getStackDockedModeBounds(Rect outBounds, Rect outTempBounds,
Rect outTempInsetBounds, boolean ignoreVisibility) {
synchronized (mWindowMap) {
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotController.java b/services/core/java/com/android/server/wm/TaskSnapshotController.java
index 2b74f84..5041138 100644
--- a/services/core/java/com/android/server/wm/TaskSnapshotController.java
+++ b/services/core/java/com/android/server/wm/TaskSnapshotController.java
@@ -19,6 +19,7 @@
import static android.app.ActivityManager.ENABLE_TASK_SNAPSHOTS;
import android.annotation.Nullable;
+import android.app.ActivityManager;
import android.app.ActivityManager.StackId;
import android.app.ActivityManager.TaskSnapshot;
import android.graphics.GraphicBuffer;
@@ -65,26 +66,22 @@
}
void onTransitionStarting() {
- if (!ENABLE_TASK_SNAPSHOTS) {
- return;
- }
handleClosingApps(mService.mClosingApps);
}
-
/**
* Called when the visibility of an app changes outside of the regular app transition flow.
*/
void notifyAppVisibilityChanged(AppWindowToken appWindowToken, boolean visible) {
- if (!ENABLE_TASK_SNAPSHOTS) {
- return;
- }
if (!visible) {
handleClosingApps(Sets.newArraySet(appWindowToken));
}
}
private void handleClosingApps(ArraySet<AppWindowToken> closingApps) {
+ if (!ENABLE_TASK_SNAPSHOTS || ActivityManager.isLowRamDeviceStatic()) {
+ return;
+ }
// We need to take a snapshot of the task if and only if all activities of the task are
// either closing or hidden.
diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java
index 5f8b694..b79ea71 100644
--- a/services/core/java/com/android/server/wm/TaskStack.java
+++ b/services/core/java/com/android/server/wm/TaskStack.java
@@ -19,6 +19,7 @@
import static android.app.ActivityManager.DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT;
import static android.app.ActivityManager.DOCKED_STACK_CREATE_MODE_BOTTOM_OR_RIGHT;
import static android.app.ActivityManager.StackId.DOCKED_STACK_ID;
+import static android.app.ActivityManager.StackId.FULLSCREEN_WORKSPACE_STACK_ID;
import static android.app.ActivityManager.StackId.HOME_STACK_ID;
import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET;
@@ -261,6 +262,12 @@
if (mDisplayContent != null) {
mDisplayContent.mDimLayerController.updateDimLayer(this);
+ if (mStackId == PINNED_STACK_ID) {
+ // Update the bounds based on any changes to the display info
+ getAnimatingBounds(mTmpRect2);
+ mDisplayContent.mPinnedStackControllerLocked.onTaskStackBoundsChanged(mTmpRect2,
+ bounds);
+ }
mAnimationBackgroundSurface.setBounds(bounds);
}
@@ -390,15 +397,18 @@
return false;
}
+ if (StackId.tasksAreFloating(mStackId)) {
+ // Update stack bounds again since the display info has changed since updateDisplayInfo,
+ // however, for floating tasks, we don't need to apply the new rotation to the bounds,
+ // we can just update and return them here
+ setBounds(mBounds);
+ mBoundsAfterRotation.set(mBounds);
+ return true;
+ }
+
mTmpRect2.set(mBounds);
mDisplayContent.rotateBounds(mRotation, newRotation, mTmpRect2);
switch (mStackId) {
- case PINNED_STACK_ID:
- Rect targetBounds = new Rect();
- getAnimatingBounds(targetBounds);
- mTmpRect2 = mDisplayContent.getPinnedStackController().onDisplayChanged(mBounds,
- targetBounds, mDisplayContent);
- break;
case DOCKED_STACK_ID:
repositionDockedStackAfterRotation(mTmpRect2);
snapDockedStackAfterRotation(mTmpRect2);
@@ -650,7 +660,6 @@
mAnimationBackgroundSurface = new DimLayer(mService, this, mDisplayContent.getDisplayId(),
"animation background stackId=" + mStackId);
- final Rect oldBounds = new Rect(mBounds);
Rect bounds = null;
final TaskStack dockedStack = dc.getDockedStackIgnoringVisibility();
if (mStackId == DOCKED_STACK_ID
@@ -674,15 +683,6 @@
}
updateDisplayInfo(bounds);
-
- // Update the pinned stack controller after the display info is updated
- if (mStackId == PINNED_STACK_ID) {
- Rect targetBounds = new Rect();
- getAnimatingBounds(targetBounds);
- mDisplayContent.getPinnedStackController().onDisplayChanged(oldBounds, targetBounds,
- mDisplayContent);
- }
-
super.onDisplayChanged(dc);
}
@@ -1425,16 +1425,6 @@
}
public boolean setPinnedStackSize(Rect bounds, Rect tempTaskBounds) {
- synchronized (mService.mWindowMap) {
- if (mDisplayContent == null) {
- return false;
- }
- if (mStackId != PINNED_STACK_ID) {
- Slog.w(TAG_WM, "Attempt to use pinned stack resize animation helper on"
- + "non pinned stack");
- return false;
- }
- }
try {
mService.mActivityManager.resizePinnedStack(bounds, tempTaskBounds);
} catch (RemoteException e) {
@@ -1476,14 +1466,6 @@
}
}
- @Override
- public void getFullScreenBounds(Rect bounds) {
- // This is currently only used for the pinned stack animation when leaving PiP
- // (see {@link BoundsAnimationController}), and in that case we need to animate this back
- // to the full bounds to match the fullscreen stack
- getDisplayContent().getLogicalDisplayRect(bounds);
- }
-
public boolean hasMovementAnimations() {
return StackId.hasMovementAnimations(mStackId);
}
diff --git a/services/core/java/com/android/server/wm/WallpaperController.java b/services/core/java/com/android/server/wm/WallpaperController.java
index c32e689..7213c95 100644
--- a/services/core/java/com/android/server/wm/WallpaperController.java
+++ b/services/core/java/com/android/server/wm/WallpaperController.java
@@ -547,6 +547,7 @@
for (int curTokenNdx = mWallpaperTokens.size() - 1; curTokenNdx >= 0; curTokenNdx--) {
final WallpaperWindowToken token = mWallpaperTokens.get(curTokenNdx);
token.updateWallpaperWindows(visible, mWallpaperAnimLayerAdjustment);
+ token.getDisplayContent().assignWindowLayers(false);
}
}
@@ -568,7 +569,7 @@
// Only do this if we are not transferring between two wallpaper targets.
mWallpaperAnimLayerAdjustment =
(mPrevWallpaperTarget == null && mWallpaperTarget.mAppToken != null)
- ? mWallpaperTarget.mAppToken.mAppAnimator.animLayerAdjustment : 0;
+ ? mWallpaperTarget.mAppToken.getAnimLayerAdjustment() : 0;
if (mWallpaperTarget.mWallpaperX >= 0) {
mLastWallpaperX = mWallpaperTarget.mWallpaperX;
diff --git a/services/core/java/com/android/server/wm/WallpaperWindowToken.java b/services/core/java/com/android/server/wm/WallpaperWindowToken.java
index 28aebbb..a12c0e5 100644
--- a/services/core/java/com/android/server/wm/WallpaperWindowToken.java
+++ b/services/core/java/com/android/server/wm/WallpaperWindowToken.java
@@ -142,7 +142,6 @@
// First, make sure the client has the current visibility state.
wallpaper.dispatchWallpaperVisibility(visible);
- wallpaper.adjustAnimLayer(animLayerAdj);
if (DEBUG_LAYERS || DEBUG_WALLPAPER_LIGHT) Slog.v(TAG, "adjustWallpaper win "
+ wallpaper + " anim layer: " + wallpaper.mWinAnimator.mAnimLayer);
diff --git a/services/core/java/com/android/server/wm/WindowLayersController.java b/services/core/java/com/android/server/wm/WindowLayersController.java
index 1cd2b53d..172ec48 100644
--- a/services/core/java/com/android/server/wm/WindowLayersController.java
+++ b/services/core/java/com/android/server/wm/WindowLayersController.java
@@ -129,7 +129,7 @@
final WindowStateAnimator winAnimator = w.mWinAnimator;
Slog.v(TAG_WM, "Assign layer " + w + ": " + "mBase=" + w.mBaseLayer
+ " mLayer=" + w.mLayer + (w.mAppToken == null
- ? "" : " mAppLayer=" + w.mAppToken.mAppAnimator.animLayerAdjustment)
+ ? "" : " mAppLayer=" + w.mAppToken.getAnimLayerAdjustment())
+ " =mAnimLayer=" + winAnimator.mAnimLayer);
}, false /* traverseTopToBottom */);
}
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 9397c9e..eb10f0c 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -16,7 +16,6 @@
package com.android.server.wm;
-import static android.Manifest.permission.INTERNAL_SYSTEM_WINDOW;
import static android.Manifest.permission.MANAGE_APP_TOKENS;
import static android.Manifest.permission.REGISTER_WINDOW_MANAGER_LISTENERS;
import static android.app.ActivityManager.DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT;
@@ -30,7 +29,6 @@
import static android.content.Intent.EXTRA_UID;
import static android.content.Intent.EXTRA_USER_HANDLE;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
-import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.os.UserHandle.USER_NULL;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.WindowManager.DOCKED_INVALID;
@@ -69,8 +67,6 @@
import static com.android.server.wm.AppTransition.TRANSIT_UNSET;
import static com.android.server.wm.AppWindowAnimator.PROLONG_ANIMATION_AT_END;
import static com.android.server.wm.AppWindowAnimator.PROLONG_ANIMATION_AT_START;
-import static com.android.server.wm.DragResizeMode.DRAG_RESIZE_MODE_DOCKED_DIVIDER;
-import static com.android.server.wm.DragResizeMode.DRAG_RESIZE_MODE_FREEFORM;
import static com.android.server.wm.KeyguardDisableHandler.KEYGUARD_POLICY_CHANGED;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ADD_REMOVE;
@@ -112,7 +108,6 @@
import android.app.ActivityManagerInternal;
import android.app.AppOpsManager;
import android.app.IActivityManager;
-import android.app.admin.DevicePolicyManager;
import android.content.BroadcastReceiver;
import android.content.ContentResolver;
import android.content.Context;
@@ -626,9 +621,14 @@
WindowState mCurrentFocus = null;
WindowState mLastFocus = null;
- /** This just indicates the window the input method is on top of, not
- * necessarily the window its input is going to. */
+ // TODO: All the IME window tracking should be moved to DisplayContent and tracked per display.
+ // This just indicates the window the input method is on top of, not necessarily the window its
+ // input is going to.
WindowState mInputMethodTarget = null;
+ // The binder token currently using the IME as determined by the input method service.
+ // Window manager uses this to determine the final input method target
+ // (almost always this candidate) for z-ordering.
+ IBinder mInputMethodTargetCandidate = null;
/** If true hold off on modifying the animation layer of mInputMethodTarget */
boolean mInputMethodTargetWaitingAnim;
@@ -2199,6 +2199,15 @@
if (mAccessibilityController != null && win.getDisplayId() == DEFAULT_DISPLAY) {
mAccessibilityController.onWindowTransitionLocked(win, transit);
}
+
+ // When we start the exit animation we take the Surface from the client
+ // so it will stop perturbing it. We need to likewise takeaway the SurfaceFlinger
+ // side child surfaces, so they will remain preserved in their current state
+ // (rather than be cleaned up immediately by the app code).
+ SurfaceControl.openTransaction();
+ winAnimator.detachChildren();
+ SurfaceControl.closeTransaction();
+
return focusMayChange;
}
@@ -5172,7 +5181,7 @@
// Async Handler
// -------------------------------------------------------------
- final class H extends Handler {
+ final class H extends android.os.Handler {
public static final int REPORT_FOCUS_CHANGE = 2;
public static final int REPORT_LOSING_FOCUS = 3;
public static final int DO_TRAVERSAL = 4;
@@ -6951,8 +6960,9 @@
pw.print(" mLastFocus="); pw.println(mLastFocus);
}
pw.print(" mFocusedApp="); pw.println(mFocusedApp);
- if (mInputMethodTarget != null) {
- pw.print(" mInputMethodTarget="); pw.println(mInputMethodTarget);
+ if (mInputMethodTarget != null || mInputMethodTargetCandidate != null) {
+ pw.println(" mInputMethodTarget=" + mInputMethodTarget
+ + " mInputMethodTargetCandidate=" + getWindow(mInputMethodTargetCandidate));
}
pw.print(" mInTouchMode="); pw.print(mInTouchMode);
pw.print(" mLayoutSeq="); pw.println(mLayoutSeq);
@@ -7267,10 +7277,6 @@
return mRoot.getDisplayContentOrCreate(DEFAULT_DISPLAY);
}
- private DisplayInfo getDefaultDisplayInfoLocked() {
- return getDefaultDisplayContentLocked().getDisplayInfo();
- }
-
public void onDisplayAdded(int displayId) {
mH.sendMessage(mH.obtainMessage(H.DO_DISPLAY_ADDED, displayId, 0));
}
@@ -7823,11 +7829,28 @@
@Override
public void updateInputMethodWindowStatus(@NonNull IBinder imeToken,
boolean imeWindowVisible, @Nullable IBinder targetWindowToken) {
- // TODO (b/34628091): Use this method to address the window animation issue.
- if (DEBUG_INPUT_METHOD) {
- Slog.w(TAG_WM, "updateInputMethodWindowStatus: imeToken=" + imeToken
- + " imeWindowVisible=" + imeWindowVisible
- + " targetWindowToken=" + targetWindowToken);
+ synchronized (mWindowMap) {
+ final WindowState newTargetWin = getWindow(targetWindowToken);
+ final WindowState currentTargetWin = getWindow(mInputMethodTargetCandidate);
+
+ if (DEBUG_INPUT_METHOD) Slog.w(TAG_WM, "updateInputMethodWindowStatus: imeToken="
+ + imeToken + " imeWindowVisible=" + imeWindowVisible
+ + " targetWindowToken=" + targetWindowToken
+ + " newTargetWin=" + newTargetWin
+ + " currentTargetWin=" + currentTargetWin);
+
+ if (newTargetWin == currentTargetWin) {
+ return;
+ }
+
+ final DisplayContent dc = newTargetWin != null
+ ? newTargetWin.getDisplayContent() : currentTargetWin.getDisplayContent();
+
+ // It is possible the window for the target candidate isn't added yet, so we
+ // remember the token instead and use it to look-up the window each time we compute
+ // the ime target.
+ mInputMethodTargetCandidate = targetWindowToken;
+ dc.computeImeTarget(true /* updateImeTarget */);
}
}
@@ -7873,6 +7896,10 @@
}
}
+ WindowState getWindow(IBinder binder) {
+ return binder == null ? null : mWindowMap.get(binder);
+ }
+
void registerAppFreezeListener(AppFreezeListener listener) {
if (!mAppFreezeListeners.contains(listener)) {
mAppFreezeListeners.add(listener);
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 945a349..14f14c5 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -1923,16 +1923,11 @@
if (mIsImWindow && mService.mInputMethodTarget != null) {
final AppWindowToken appToken = mService.mInputMethodTarget.mAppToken;
if (appToken != null) {
- return appToken.mAppAnimator.animLayerAdjustment;
+ return appToken.getAnimLayerAdjustment();
}
}
- if (mAppToken != null) {
- return mAppToken.mAppAnimator.animLayerAdjustment;
- }
-
- // Nothing is animating, so there is no animation adjustment.
- return 0;
+ return mToken.getAnimLayerAdjustment();
}
int getSpecialWindowAnimLayerAdjustment() {
@@ -3860,20 +3855,6 @@
return highest;
}
- int adjustAnimLayer(int adj) {
- int highestAnimLayer = mWinAnimator.mAnimLayer = mLayer + adj;
- if (DEBUG_LAYERS || DEBUG_WALLPAPER) Slog.v(TAG_WM,
- "adjustAnimLayer win=" + this + " anim layer: " + mWinAnimator.mAnimLayer);
- for (int i = mChildren.size() - 1; i >= 0; i--) {
- final WindowState childWindow = mChildren.get(i);
- childWindow.adjustAnimLayer(adj);
- if (childWindow.mWinAnimator.mAnimLayer > highestAnimLayer) {
- highestAnimLayer = childWindow.mWinAnimator.mAnimLayer;
- }
- }
- return highestAnimLayer;
- }
-
@Override
boolean forAllWindows(ToBooleanFunction<WindowState> callback, boolean traverseTopToBottom) {
if (mChildren.isEmpty()) {
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index c0929cb..4b71338 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -172,7 +172,7 @@
private boolean mAnimateMove = false;
float mDsDx=1, mDtDx=0, mDsDy=0, mDtDy=1;
- float mLastDsDx=1, mLastDtDx=0, mLastDsDy=0, mLastDtDy=1;
+ private float mLastDsDx=1, mLastDtDx=0, mLastDsDy=0, mLastDtDy=1;
boolean mHaveMatrix;
@@ -566,6 +566,20 @@
if (!mDestroyPreservedSurfaceUponRedraw) {
return;
}
+ if (mSurfaceController != null) {
+ if (mPendingDestroySurface != null) {
+ // If we are preserving a surface but we aren't relaunching that means
+ // we are just doing an in-place switch. In that case any SurfaceFlinger side
+ // child layers need to be reparented to the new surface to make this
+ // transparent to the app.
+ if (mWin.mAppToken == null || mWin.mAppToken.isRelaunching() == false) {
+ SurfaceControl.openTransaction();
+ mPendingDestroySurface.reparentChildrenInTransaction(mSurfaceController);
+ SurfaceControl.closeTransaction();
+ }
+ }
+ }
+
destroyDeferredSurfaceLocked();
mDestroyPreservedSurfaceUponRedraw = false;
}
@@ -945,8 +959,8 @@
tmpMatrix.getValues(tmpFloats);
mDsDx = tmpFloats[Matrix.MSCALE_X];
mDtDx = tmpFloats[Matrix.MSKEW_Y];
- mDsDy = tmpFloats[Matrix.MSKEW_X];
- mDtDy = tmpFloats[Matrix.MSCALE_Y];
+ mDtDy = tmpFloats[Matrix.MSKEW_X];
+ mDsDy = tmpFloats[Matrix.MSCALE_Y];
float x = tmpFloats[Matrix.MTRANS_X];
float y = tmpFloats[Matrix.MTRANS_Y];
mWin.mShownPosition.set(Math.round(x), Math.round(y));
@@ -959,7 +973,7 @@
mShownAlpha = mAlpha;
if (!mService.mLimitedAlphaCompositing
|| (!PixelFormat.formatHasAlpha(mWin.mAttrs.format)
- || (mWin.isIdentityMatrix(mDsDx, mDtDx, mDsDy, mDtDy)
+ || (mWin.isIdentityMatrix(mDsDx, mDtDx, mDtDy, mDsDy)
&& x == frame.left && y == frame.top))) {
//Slog.i(TAG_WM, "Applying alpha transform");
if (selfTransformation) {
@@ -1038,8 +1052,8 @@
mHaveMatrix = true;
mDsDx = tmpFloats[Matrix.MSCALE_X];
mDtDx = tmpFloats[Matrix.MSKEW_Y];
- mDsDy = tmpFloats[Matrix.MSKEW_X];
- mDtDy = tmpFloats[Matrix.MSCALE_Y];
+ mDtDy = tmpFloats[Matrix.MSKEW_X];
+ mDsDy = tmpFloats[Matrix.MSCALE_Y];
float x = tmpFloats[Matrix.MTRANS_X];
float y = tmpFloats[Matrix.MTRANS_Y];
mWin.mShownPosition.set(Math.round(x), Math.round(y));
@@ -1054,8 +1068,8 @@
mHaveMatrix = false;
mDsDx = mWin.mGlobalScale;
mDtDx = 0;
- mDsDy = 0;
- mDtDy = mWin.mGlobalScale;
+ mDtDy = 0;
+ mDsDy = mWin.mGlobalScale;
}
}
@@ -1384,8 +1398,8 @@
applyCrop(clipRect, finalClipRect, recoveringMemory);
mSurfaceController.setMatrixInTransaction(mDsDx * w.mHScale * mExtraHScale,
mDtDx * w.mVScale * mExtraVScale,
- mDsDy * w.mHScale * mExtraHScale,
- mDtDy * w.mVScale * mExtraVScale, recoveringMemory);
+ mDtDy * w.mHScale * mExtraHScale,
+ mDsDy * w.mVScale * mExtraVScale, recoveringMemory);
}
if (mSurfaceResized) {
@@ -1467,15 +1481,15 @@
"alpha=" + mShownAlpha + " layer=" + mAnimLayer
+ " matrix=[" + mDsDx + "*" + w.mHScale
+ "," + mDtDx + "*" + w.mVScale
- + "][" + mDsDy + "*" + w.mHScale
- + "," + mDtDy + "*" + w.mVScale + "]", false);
+ + "][" + mDtDy + "*" + w.mHScale
+ + "," + mDsDy + "*" + w.mVScale + "]", false);
boolean prepared =
mSurfaceController.prepareToShowInTransaction(mShownAlpha, mAnimLayer,
mDsDx * w.mHScale * mExtraHScale,
mDtDx * w.mVScale * mExtraVScale,
- mDsDy * w.mHScale * mExtraHScale,
- mDtDy * w.mVScale * mExtraVScale,
+ mDtDy * w.mHScale * mExtraHScale,
+ mDsDy * w.mVScale * mExtraVScale,
recoveringMemory);
if (prepared && mLastHidden && mDrawState == HAS_DRAWN) {
@@ -1777,8 +1791,8 @@
pw.print(prefix); pw.print("mGlobalScale="); pw.print(mWin.mGlobalScale);
pw.print(" mDsDx="); pw.print(mDsDx);
pw.print(" mDtDx="); pw.print(mDtDx);
- pw.print(" mDsDy="); pw.print(mDsDy);
- pw.print(" mDtDy="); pw.println(mDtDy);
+ pw.print(" mDtDy="); pw.print(mDtDy);
+ pw.print(" mDsDy="); pw.println(mDsDy);
}
if (mAnimationStartDelayed) {
pw.print(prefix); pw.print("mAnimationStartDelayed="); pw.print(mAnimationStartDelayed);
@@ -1926,15 +1940,15 @@
float DsDx = mService.mTmpFloats[Matrix.MSCALE_X];
float DtDx = mService.mTmpFloats[Matrix.MSKEW_Y];
- float DsDy = mService.mTmpFloats[Matrix.MSKEW_X];
- float DtDy = mService.mTmpFloats[Matrix.MSCALE_Y];
+ float DtDy = mService.mTmpFloats[Matrix.MSKEW_X];
+ float DsDy = mService.mTmpFloats[Matrix.MSCALE_Y];
float nx = mService.mTmpFloats[Matrix.MTRANS_X];
float ny = mService.mTmpFloats[Matrix.MTRANS_Y];
mSurfaceController.setPositionInTransaction(nx, ny, false);
mSurfaceController.setMatrixInTransaction(DsDx * w.mHScale,
DtDx * w.mVScale,
- DsDy * w.mHScale,
- DtDy * w.mVScale, false);
+ DtDy * w.mHScale,
+ DsDy * w.mVScale, false);
}
}
@@ -1965,4 +1979,10 @@
}
return mForceScaleUntilResize;
}
+
+ void detachChildren() {
+ if (mSurfaceController != null) {
+ mSurfaceController.detachChildren();
+ }
+ }
}
diff --git a/services/core/java/com/android/server/wm/WindowSurfaceController.java b/services/core/java/com/android/server/wm/WindowSurfaceController.java
index f8e7428..f7d3343 100644
--- a/services/core/java/com/android/server/wm/WindowSurfaceController.java
+++ b/services/core/java/com/android/server/wm/WindowSurfaceController.java
@@ -135,6 +135,20 @@
}
}
+ void reparentChildrenInTransaction(WindowSurfaceController other) {
+ if (SHOW_TRANSACTIONS) Slog.i(TAG, "REPARENT from: " + this + " to: " + other);
+ if ((mSurfaceControl != null) && (other.mSurfaceControl != null)) {
+ mSurfaceControl.reparentChildren(other.getHandle());
+ }
+ }
+
+ void detachChildren() {
+ if (SHOW_TRANSACTIONS) Slog.i(TAG, "SEVER CHILDREN");
+ if (mSurfaceControl != null) {
+ mSurfaceControl.detachChildren();
+ }
+ }
+
void hideInTransaction(String reason) {
if (SHOW_TRANSACTIONS) logSurface("HIDE ( " + reason + " )", null);
mHiddenForOtherReasons = true;
diff --git a/services/core/java/com/android/server/wm/WindowToken.java b/services/core/java/com/android/server/wm/WindowToken.java
index 8beb87d..fab59d6 100644
--- a/services/core/java/com/android/server/wm/WindowToken.java
+++ b/services/core/java/com/android/server/wm/WindowToken.java
@@ -151,21 +151,6 @@
}
}
- int adjustAnimLayer(int adj) {
- int highestAnimLayer = -1;
- for (int j = mChildren.size() - 1; j >= 0; j--) {
- final WindowState w = mChildren.get(j);
- final int winHighestAnimLayer = w.adjustAnimLayer(adj);
- if (winHighestAnimLayer > highestAnimLayer) {
- highestAnimLayer = winHighestAnimLayer;
- }
- if (w == mService.mInputMethodTarget && !mService.mInputMethodTargetWaitingAnim) {
- mDisplayContent.setInputMethodAnimLayerAdjustment(adj);
- }
- }
- return highestAnimLayer;
- }
-
/**
* Returns true if the new window is considered greater than the existing window in terms of
* z-order.
@@ -197,6 +182,11 @@
return mChildren.isEmpty();
}
+ // Used by AppWindowToken.
+ int getAnimLayerAdjustment() {
+ return 0;
+ }
+
WindowState getReplacingWindow() {
for (int i = mChildren.size() - 1; i >= 0; i--) {
final WindowState win = mChildren.get(i);
diff --git a/services/core/jni/com_android_server_location_ContextHubService.cpp b/services/core/jni/com_android_server_location_ContextHubService.cpp
index 05ef0d1..27d2b6d 100644
--- a/services/core/jni/com_android_server_location_ContextHubService.cpp
+++ b/services/core/jni/com_android_server_location_ContextHubService.cpp
@@ -558,7 +558,7 @@
void initContextHubService() {
db.hubInfo.numHubs = 0;
- db.hubInfo.contextHub = IContexthub::getService("context_hub");
+ db.hubInfo.contextHub = IContexthub::getService();
if (db.hubInfo.contextHub == nullptr) {
ALOGE("Could not load context hub hal");
diff --git a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
index 4c89705..36ae94b 100644
--- a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
+++ b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
@@ -1036,7 +1036,7 @@
}
// TODO(b/31632518)
- gnssHal = IGnss::getService("gnss");
+ gnssHal = IGnss::getService();
if (gnssHal != nullptr) {
auto gnssXtra = gnssHal->getExtensionXtra();
if (!gnssXtra.isOk()) {
@@ -1144,7 +1144,7 @@
}
auto result = gnssHal->setCallback(gnssCbIface);
- if ((!result) || (!result.isOk())) {
+ if (!result.isOk() || !result) {
ALOGE("SetCallback for Gnss Interface fails\n");
return JNI_FALSE;
}
@@ -1154,7 +1154,7 @@
ALOGE("Unable to initialize GNSS Xtra interface\n");
} else {
result = gnssXtraIface->setCallback(gnssXtraCbIface);
- if ((!result) || (!result.isOk())) {
+ if (!result.isOk() || !result) {
gnssXtraIface = nullptr;
ALOGE("SetCallback for Gnss Xtra Interface fails\n");
}
@@ -1344,7 +1344,7 @@
jlong time, jlong timeReference, jint uncertainty) {
if (gnssHal != nullptr) {
auto result = gnssHal->injectTime(time, timeReference, uncertainty);
- if (!result || !result.isOk()) {
+ if (!result.isOk() || !result) {
ALOGE("%s: Gnss injectTime() failed", __func__);
}
}
@@ -1354,7 +1354,7 @@
jobject /* obj */, jdouble latitude, jdouble longitude, jfloat accuracy) {
if (gnssHal != nullptr) {
auto result = gnssHal->injectLocation(latitude, longitude, accuracy);
- if (!result || !result.isOk()) {
+ if (!result.isOk() || !result) {
ALOGE("%s: Gnss injectLocation() failed", __func__);
}
}
@@ -1391,7 +1391,7 @@
const char *apnStr = env->GetStringUTFChars(apn, NULL);
auto result = agnssIface->dataConnOpen(apnStr, static_cast<IAGnss::ApnIpType>(apnIpType));
- if ((!result) || (!result.isOk())) {
+ if (!result.isOk() || !result){
ALOGE("%s: Failed to set APN and its IP type", __func__);
}
env->ReleaseStringUTFChars(apn, apnStr);
@@ -1405,7 +1405,7 @@
}
auto result = agnssIface->dataConnClosed();
- if ((!result) || (!result.isOk())) {
+ if (!result.isOk() || !result) {
ALOGE("%s: Failed to close AGnss data connection", __func__);
}
}
@@ -1418,7 +1418,7 @@
}
auto result = agnssIface->dataConnFailed();
- if ((!result) || (!result.isOk())) {
+ if (!result.isOk() || !result) {
ALOGE("%s: Failed to notify unavailability of AGnss data connection", __func__);
}
}
@@ -1434,7 +1434,7 @@
auto result = agnssIface->setServer(static_cast<IAGnssCallback::AGnssType>(type),
c_hostname,
port);
- if ((!result) || (!result.isOk())) {
+ if (!result.isOk() || !result) {
ALOGE("%s: Failed to set AGnss host name and port", __func__);
}
@@ -1512,13 +1512,13 @@
auto result = agnssRilIface->updateNetworkState(connected,
static_cast<IAGnssRil::NetworkType>(type),
roaming);
- if ((!result) || (!result.isOk())) {
+ if (!result.isOk() || !result) {
ALOGE("updateNetworkState failed");
}
const char *c_apn = env->GetStringUTFChars(apn, NULL);
result = agnssRilIface->updateNetworkAvailability(available, c_apn);
- if ((!result) || (!result.isOk())) {
+ if (!result.isOk() || !result) {
ALOGE("updateNetworkAvailability failed");
}
diff --git a/services/core/jni/com_android_server_vr_VrManagerService.cpp b/services/core/jni/com_android_server_vr_VrManagerService.cpp
index e06e051..9052697 100644
--- a/services/core/jni/com_android_server_vr_VrManagerService.cpp
+++ b/services/core/jni/com_android_server_vr_VrManagerService.cpp
@@ -38,7 +38,7 @@
return;
}
- gVr = IVr::getService("vr");
+ gVr = IVr::getService();
if (gVr == nullptr) {
ALOGW("%s: Could not open IVr interface", __FUNCTION__);
return;
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 620d441..8b94ca0 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -41,6 +41,7 @@
import static android.app.admin.DevicePolicyManager.DELEGATION_PACKAGE_ACCESS;
import static android.app.admin.DevicePolicyManager.DELEGATION_PERMISSION_GRANT;
import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_COMPLEX;
+import static android.app.admin.DevicePolicyManager.PROFILE_KEYGUARD_FEATURES_AFFECT_OWNER;
import static android.app.admin.DevicePolicyManager.WIPE_EXTERNAL_STORAGE;
import static android.app.admin.DevicePolicyManager.WIPE_RESET_PROTECTION_DATA;
import static android.content.pm.PackageManager.MATCH_UNINSTALLED_PACKAGES;
@@ -164,10 +165,10 @@
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.logging.MetricsLogger;
+import com.android.internal.notification.SystemNotificationChannels;
import com.android.internal.statusbar.IStatusBarService;
import com.android.internal.util.FastXmlSerializer;
import com.android.internal.util.JournaledFile;
-import com.android.internal.util.ParcelableString;
import com.android.internal.util.Preconditions;
import com.android.internal.util.XmlUtils;
import com.android.internal.widget.LockPatternUtils;
@@ -332,15 +333,6 @@
}
/**
- * Keyguard features that when set on a managed profile that doesn't have its own challenge will
- * affect the profile's parent user. These can also be set on the managed profile's parent DPM
- * instance.
- */
- private static final int PROFILE_KEYGUARD_FEATURES_AFFECT_OWNER =
- DevicePolicyManager.KEYGUARD_DISABLE_TRUST_AGENTS
- | DevicePolicyManager.KEYGUARD_DISABLE_FINGERPRINT;
-
- /**
* Keyguard features that when set on a profile affect the profile content or challenge only.
* These cannot be set on the managed profile's parent DPM instance
*/
@@ -4859,19 +4851,37 @@
private void sendPrivateKeyAliasResponse(final String alias, final IBinder responseBinder) {
final IKeyChainAliasCallback keyChainAliasResponse =
IKeyChainAliasCallback.Stub.asInterface(responseBinder);
- new AsyncTask<Void, Void, Void>() {
- @Override
- protected Void doInBackground(Void... unused) {
- try {
- keyChainAliasResponse.alias(alias);
- } catch (Exception e) {
- // Catch everything (not just RemoteException): caller could throw a
- // RuntimeException back across processes.
- Log.e(LOG_TAG, "error while responding to callback", e);
- }
- return null;
- }
- }.execute();
+ // Send the response. It's OK to do this from the main thread because IKeyChainAliasCallback
+ // is oneway, which means it won't block if the recipient lives in another process.
+ try {
+ keyChainAliasResponse.alias(alias);
+ } catch (Exception e) {
+ // Caller could throw RuntimeException or RemoteException back across processes. Catch
+ // everything just to be sure.
+ Log.e(LOG_TAG, "error while responding to callback", e);
+ }
+ }
+
+ /**
+ * Determine whether DPMS should check if a delegate package is already installed before
+ * granting it new delegations via {@link #setDelegatedScopes}.
+ */
+ private static boolean shouldCheckIfDelegatePackageIsInstalled(String delegatePackage,
+ int targetSdk, List<String> scopes) {
+ // 1) Never skip is installed check from N.
+ if (targetSdk >= Build.VERSION_CODES.N) {
+ return true;
+ }
+ // 2) Skip if DELEGATION_CERT_INSTALL is the only scope being given.
+ if (scopes.size() == 1 && scopes.get(0).equals(DELEGATION_CERT_INSTALL)) {
+ return false;
+ }
+ // 3) Skip if all previously granted scopes are being cleared.
+ if (scopes.isEmpty()) {
+ return false;
+ }
+ // Otherwise it should check that delegatePackage is installed.
+ return true;
}
/**
@@ -4900,8 +4910,8 @@
// Ensure calling process is device/profile owner.
getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
// Ensure the delegate is installed (skip this for DELEGATION_CERT_INSTALL in pre-N).
- if (scopes.size() == 1 && scopes.get(0).equals(DELEGATION_CERT_INSTALL) ||
- getTargetSdk(who.getPackageName(), userId) >= Build.VERSION_CODES.N) {
+ if (shouldCheckIfDelegatePackageIsInstalled(delegatePackage,
+ getTargetSdk(who.getPackageName(), userId), scopes)) {
// Throw when the delegate package is not installed.
if (!isPackageInstalledForUser(delegatePackage, userId)) {
throw new IllegalArgumentException("Package " + delegatePackage
@@ -5119,8 +5129,10 @@
final String currentPackage = policy.mDelegationMap.keyAt(i);
final List<String> currentScopes = policy.mDelegationMap.valueAt(i);
- if (!currentPackage.equals(delegatePackage) && currentScopes.remove(scope)) {
- setDelegatedScopes(who, currentPackage, currentScopes);
+ if (!currentPackage.equals(delegatePackage) && currentScopes.contains(scope)) {
+ final List<String> newScopes = new ArrayList(currentScopes);
+ newScopes.remove(scope);
+ setDelegatedScopes(who, currentPackage, newScopes);
}
}
}
@@ -5281,13 +5293,14 @@
private void sendWipeProfileNotification() {
String contentText = mContext.getString(R.string.work_profile_deleted_description_dpm_wipe);
- Notification notification = new Notification.Builder(mContext)
- .setSmallIcon(android.R.drawable.stat_sys_warning)
- .setContentTitle(mContext.getString(R.string.work_profile_deleted))
- .setContentText(contentText)
- .setColor(mContext.getColor(R.color.system_notification_accent_color))
- .setStyle(new Notification.BigTextStyle().bigText(contentText))
- .build();
+ Notification notification =
+ new Notification.Builder(mContext, SystemNotificationChannels.DEVICE_ADMIN)
+ .setSmallIcon(android.R.drawable.stat_sys_warning)
+ .setContentTitle(mContext.getString(R.string.work_profile_deleted))
+ .setContentText(contentText)
+ .setColor(mContext.getColor(R.color.system_notification_accent_color))
+ .setStyle(new Notification.BigTextStyle().bigText(contentText))
+ .build();
mInjector.getNotificationManager().notify(PROFILE_WIPED_NOTIFICATION_ID, notification);
}
@@ -10707,7 +10720,8 @@
intent.setPackage("com.android.systemui");
final PendingIntent pendingIntent = PendingIntent.getBroadcastAsUser(mContext, 0, intent, 0,
UserHandle.CURRENT);
- Notification notification = new Notification.Builder(mContext)
+ Notification notification =
+ new Notification.Builder(mContext, SystemNotificationChannels.DEVICE_ADMIN)
.setSmallIcon(R.drawable.ic_qs_network_logging)
.setContentTitle(mContext.getString(R.string.network_logging_notification_title))
.setContentText(mContext.getString(R.string.network_logging_notification_text))
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/MonitoringCertNotificationTask.java b/services/devicepolicy/java/com/android/server/devicepolicy/MonitoringCertNotificationTask.java
index 03c137a..1933fe7 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/MonitoringCertNotificationTask.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/MonitoringCertNotificationTask.java
@@ -34,8 +34,8 @@
import android.security.KeyChain.KeyChainConnection;
import android.util.Log;
+import com.android.internal.notification.SystemNotificationChannels;
import com.android.internal.R;
-import com.android.internal.util.ParcelableString;
import java.util.ArrayList;
import java.util.List;
@@ -132,16 +132,16 @@
dialogIntent, PendingIntent.FLAG_UPDATE_CURRENT, null,
UserHandle.of(parentUserId));
- final Notification noti = new Notification.Builder(userContext)
- .setSmallIcon(smallIconId)
- .setContentTitle(resources.getQuantityText(R.plurals.ssl_ca_cert_warning,
- pendingCertificateCount))
- .setContentText(contentText)
- .setContentIntent(notifyIntent)
- .setPriority(Notification.PRIORITY_HIGH)
- .setShowWhen(false)
- .setColor(R.color.system_notification_accent_color)
- .build();
+ final Notification noti =
+ new Notification.Builder(userContext, SystemNotificationChannels.SECURITY)
+ .setSmallIcon(smallIconId)
+ .setContentTitle(resources.getQuantityText(R.plurals.ssl_ca_cert_warning,
+ pendingCertificateCount))
+ .setContentText(contentText)
+ .setContentIntent(notifyIntent)
+ .setShowWhen(false)
+ .setColor(R.color.system_notification_accent_color)
+ .build();
mInjector.getNotificationManager().notifyAsUser(
LOG_TAG, MONITORING_CERT_NOTIFICATION_ID, noti, userHandle);
@@ -150,12 +150,7 @@
private List<String> getInstalledCaCertificates(UserHandle userHandle)
throws RemoteException, RuntimeException {
try (KeyChainConnection conn = mInjector.keyChainBindAsUser(userHandle)) {
- List<ParcelableString> aliases = conn.getService().getUserCaAliases().getList();
- List<String> result = new ArrayList<>(aliases.size());
- for (int i = 0; i < aliases.size(); i++) {
- result.add(aliases.get(i).string);
- }
- return result;
+ return conn.getService().getUserCaAliases().getList();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
return null;
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/RemoteBugreportUtils.java b/services/devicepolicy/java/com/android/server/devicepolicy/RemoteBugreportUtils.java
index 6d42dc9..969c89e 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/RemoteBugreportUtils.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/RemoteBugreportUtils.java
@@ -28,6 +28,7 @@
import android.text.format.DateUtils;
import com.android.internal.R;
+import com.android.internal.notification.SystemNotificationChannels;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -62,14 +63,14 @@
PendingIntent pendingDialogIntent = PendingIntent.getActivityAsUser(context, type,
dialogIntent, 0, null, UserHandle.CURRENT);
- Notification.Builder builder = new Notification.Builder(context)
- .setSmallIcon(com.android.internal.R.drawable.stat_sys_adb)
- .setOngoing(true)
- .setLocalOnly(true)
- .setPriority(Notification.PRIORITY_HIGH)
- .setContentIntent(pendingDialogIntent)
- .setColor(context.getColor(
- com.android.internal.R.color.system_notification_accent_color));
+ Notification.Builder builder =
+ new Notification.Builder(context, SystemNotificationChannels.DEVELOPER)
+ .setSmallIcon(com.android.internal.R.drawable.stat_sys_adb)
+ .setOngoing(true)
+ .setLocalOnly(true)
+ .setContentIntent(pendingDialogIntent)
+ .setColor(context.getColor(
+ com.android.internal.R.color.system_notification_accent_color));
if (type == DevicePolicyManager.NOTIFICATION_BUGREPORT_ACCEPTED_NOT_FINISHED) {
builder.setContentTitle(context.getString(
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index c8a80c2..1a0aff7 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -53,6 +53,7 @@
import com.android.internal.R;
import com.android.internal.app.NightDisplayController;
import com.android.internal.logging.MetricsLogger;
+import com.android.internal.notification.SystemNotificationChannels;
import com.android.internal.os.BinderInternal;
import com.android.internal.os.SamplingProfilerIntegration;
import com.android.internal.policy.EmergencyAffordanceManager;
@@ -82,6 +83,7 @@
import com.android.server.net.NetworkPolicyManagerService;
import com.android.server.net.NetworkStatsService;
import com.android.server.notification.NotificationManagerService;
+import com.android.server.om.OverlayManagerService;
import com.android.server.os.DeviceIdentifiersPolicyService;
import com.android.server.os.SchedulingPolicyService;
import com.android.server.pm.Installer;
@@ -182,10 +184,8 @@
"com.google.android.clockwork.ThermalObserver";
private static final String WEAR_BLUETOOTH_SERVICE_CLASS =
"com.google.android.clockwork.bluetooth.WearBluetoothService";
- private static final String WEAR_WIFI_MEDIATOR_SERVICE_CLASS =
- "com.google.android.clockwork.wifi.WearWifiMediatorService";
- private static final String WEAR_CELLULAR_MEDIATOR_SERVICE_CLASS =
- "com.google.android.clockwork.cellular.WearCellularMediatorService";
+ private static final String WEAR_CONNECTIVITY_SERVICE_CLASS =
+ "com.google.android.clockwork.connectivity.WearConnectivityService";
private static final String WEAR_TIME_SERVICE_CLASS =
"com.google.android.clockwork.time.WearTimeService";
private static final String ACCOUNT_SERVICE_CLASS =
@@ -376,6 +376,7 @@
startBootstrapServices();
startCoreServices();
startOtherServices();
+ SystemServerInitThreadPool.shutdown();
} catch (Throwable ex) {
Slog.e("System", "******************************************");
Slog.e("System", "************ Failure starting system services", ex);
@@ -383,7 +384,6 @@
} finally {
traceEnd();
}
- SystemServerInitThreadPool.shutdown();
// For debug builds, log event loop stalls to dropbox for analysis.
if (StrictMode.conditionallyEnableDebugLogging()) {
@@ -594,6 +594,11 @@
mActivityManagerService.setSystemProcess();
traceEnd();
+ // Manages Overlay packages
+ traceBeginAndSlog("StartOverlayManagerService");
+ mSystemServiceManager.startService(new OverlayManagerService(mSystemContext, installer));
+ traceEnd();
+
// The sensor service needs access to package manager service, app ops
// service, and permissions service, therefore we start it after them.
// Start sensor service in a separate thread. Completion should be checked
@@ -1114,6 +1119,7 @@
traceBeginAndSlog("StartNotificationManager");
mSystemServiceManager.startService(NotificationManagerService.class);
+ SystemNotificationChannels.createAll(context);
notification = INotificationManager.Stub.asInterface(
ServiceManager.getService(Context.NOTIFICATION_SERVICE));
networkPolicy.bindNotificationManager(notification);
@@ -1459,16 +1465,10 @@
mSystemServiceManager.startService(WEAR_BLUETOOTH_SERVICE_CLASS);
traceEnd();
- traceBeginAndSlog("StartWearWifiMediator");
- mSystemServiceManager.startService(WEAR_WIFI_MEDIATOR_SERVICE_CLASS);
+ traceBeginAndSlog("StartWearConnectivityService");
+ mSystemServiceManager.startService(WEAR_CONNECTIVITY_SERVICE_CLASS);
traceEnd();
- if (SystemProperties.getBoolean("config.enable_cellmediator", false)) {
- traceBeginAndSlog("StartWearCellularMediator");
- mSystemServiceManager.startService(WEAR_CELLULAR_MEDIATOR_SERVICE_CLASS);
- traceEnd();
- }
-
if (!disableNonCoreServices) {
traceBeginAndSlog("StartWearTimeService");
mSystemServiceManager.startService(WEAR_TIME_SERVICE_CLASS);
@@ -1694,6 +1694,9 @@
Watchdog.getInstance().start();
traceEnd();
+ // Wait for all packages to be prepared
+ mPackageManagerService.waitForAppDataPrepared();
+
// It is now okay to let the various system services start their
// third party code...
traceBeginAndSlog("PhaseThirdPartyAppsCanStart");
diff --git a/services/retaildemo/java/com/android/server/retaildemo/RetailDemoModeService.java b/services/retaildemo/java/com/android/server/retaildemo/RetailDemoModeService.java
index f943ee2c..472f984 100644
--- a/services/retaildemo/java/com/android/server/retaildemo/RetailDemoModeService.java
+++ b/services/retaildemo/java/com/android/server/retaildemo/RetailDemoModeService.java
@@ -61,6 +61,7 @@
import android.text.TextUtils;
import android.util.KeyValueListParser;
import android.util.Slog;
+import com.android.internal.notification.SystemNotificationChannels;
import com.android.internal.os.BackgroundThread;
import com.android.internal.R;
import com.android.internal.annotations.GuardedBy;
@@ -818,7 +819,7 @@
}
Notification createResetNotification() {
- return new Notification.Builder(getContext())
+ return new Notification.Builder(getContext(), SystemNotificationChannels.RETAIL_MODE)
.setContentTitle(getContext().getString(R.string.reset_retail_demo_mode_title))
.setContentText(getContext().getString(R.string.reset_retail_demo_mode_text))
.setOngoing(true)
diff --git a/services/tests/notification/AndroidManifest.xml b/services/tests/notification/AndroidManifest.xml
index 92f155f..cf050a8 100644
--- a/services/tests/notification/AndroidManifest.xml
+++ b/services/tests/notification/AndroidManifest.xml
@@ -23,6 +23,7 @@
<uses-permission android:name="android.permission.MANAGE_USERS" />
<uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" />
<uses-permission android:name="android.permission.ACCESS_NOTIFICATIONS" />
+ <uses-permission android:name="android.permission.READ_CONTACTS" />
<application>
<uses-library android:name="android.test.runner" />
diff --git a/services/tests/notification/src/com/android/server/notification/BadgeExtractorTest.java b/services/tests/notification/src/com/android/server/notification/BadgeExtractorTest.java
index b26bac3..0cf4994 100644
--- a/services/tests/notification/src/com/android/server/notification/BadgeExtractorTest.java
+++ b/services/tests/notification/src/com/android/server/notification/BadgeExtractorTest.java
@@ -89,6 +89,7 @@
when(mConfig.canShowBadge(mPkg, mUid)).thenReturn(true);
NotificationChannel channel =
new NotificationChannel("a", "a", NotificationManager.IMPORTANCE_UNSPECIFIED);
+ when(mConfig.getNotificationChannel(mPkg, mUid, "a", false)).thenReturn(channel);
channel.setShowBadge(false);
NotificationRecord r = getNotificationRecord(channel);
@@ -107,6 +108,7 @@
NotificationChannel channel =
new NotificationChannel("a", "a", NotificationManager.IMPORTANCE_HIGH);
channel.setShowBadge(true);
+ when(mConfig.getNotificationChannel(mPkg, mUid, "a", false)).thenReturn(channel);
NotificationRecord r = getNotificationRecord(channel);
@@ -124,6 +126,7 @@
NotificationChannel channel =
new NotificationChannel("a", "a", NotificationManager.IMPORTANCE_UNSPECIFIED);
channel.setShowBadge(true);
+ when(mConfig.getNotificationChannel(mPkg, mUid, "a", false)).thenReturn(channel);
NotificationRecord r = getNotificationRecord(channel);
@@ -141,6 +144,7 @@
NotificationChannel channel =
new NotificationChannel("a", "a", NotificationManager.IMPORTANCE_UNSPECIFIED);
channel.setShowBadge(false);
+ when(mConfig.getNotificationChannel(mPkg, mUid, "a", false)).thenReturn(channel);
NotificationRecord r = getNotificationRecord(channel);
diff --git a/services/tests/notification/src/com/android/server/notification/GroupHelperTest.java b/services/tests/notification/src/com/android/server/notification/GroupHelperTest.java
index 936531b..05c33a4 100644
--- a/services/tests/notification/src/com/android/server/notification/GroupHelperTest.java
+++ b/services/tests/notification/src/com/android/server/notification/GroupHelperTest.java
@@ -64,7 +64,7 @@
private StatusBarNotification getSbn(String pkg, int id, String tag,
UserHandle user, String groupKey) {
- Notification.Builder nb = new Notification.Builder(getContext())
+ Notification.Builder nb = new Notification.Builder(getContext(), "test_channel_id")
.setContentTitle("A")
.setWhen(1205);
if (groupKey != null) {
diff --git a/services/tests/notification/src/com/android/server/notification/NotificationComparatorTest.java b/services/tests/notification/src/com/android/server/notification/NotificationComparatorTest.java
index 064ab0a..176342b 100644
--- a/services/tests/notification/src/com/android/server/notification/NotificationComparatorTest.java
+++ b/services/tests/notification/src/com/android/server/notification/NotificationComparatorTest.java
@@ -63,6 +63,7 @@
private final int smsUid = 11;
private final String pkg2 = "pkg2";
private final int uid2 = 1111111;
+ private static final String TEST_CHANNEL_ID = "test_channel_id";
private NotificationRecord mRecordMinCall;
private NotificationRecord mRecordHighCall;
@@ -100,7 +101,7 @@
smsPkg = Settings.Secure.getString(mContext.getContentResolver(),
Settings.Secure.SMS_DEFAULT_APPLICATION);
- Notification n1 = new Notification.Builder(mContext)
+ Notification n1 = new Notification.Builder(mContext, TEST_CHANNEL_ID)
.setCategory(Notification.CATEGORY_CALL)
.setFlag(Notification.FLAG_FOREGROUND_SERVICE, true)
.build();
@@ -109,7 +110,7 @@
new UserHandle(userId), "", 2000), getDefaultChannel());
mRecordMinCall.setUserImportance(NotificationManager.IMPORTANCE_MIN);
- Notification n2 = new Notification.Builder(mContext)
+ Notification n2 = new Notification.Builder(mContext, TEST_CHANNEL_ID)
.setCategory(Notification.CATEGORY_CALL)
.setFlag(Notification.FLAG_FOREGROUND_SERVICE, true)
.setColorized(true /* colorized */)
@@ -119,7 +120,7 @@
new UserHandle(userId), "", 1999), getDefaultChannel());
mRecordHighCall.setUserImportance(NotificationManager.IMPORTANCE_HIGH);
- Notification n3 = new Notification.Builder(mContext)
+ Notification n3 = new Notification.Builder(mContext, TEST_CHANNEL_ID)
.setStyle(new Notification.MediaStyle()
.setMediaSession(new MediaSession.Token(null)))
.setFlag(Notification.FLAG_FOREGROUND_SERVICE, true)
@@ -129,7 +130,7 @@
"", 1499), getDefaultChannel());
mRecordDefaultMedia.setUserImportance(NotificationManager.IMPORTANCE_DEFAULT);
- Notification n4 = new Notification.Builder(mContext)
+ Notification n4 = new Notification.Builder(mContext, TEST_CHANNEL_ID)
.setStyle(new Notification.MessagingStyle("sender!")).build();
mRecordInlineReply = new NotificationRecord(mContext, new StatusBarNotification(pkg2,
pkg2, 1, "inlinereply", uid2, uid2, n4, new UserHandle(userId),
@@ -137,34 +138,34 @@
mRecordInlineReply.setUserImportance(NotificationManager.IMPORTANCE_HIGH);
mRecordInlineReply.setPackagePriority(Notification.PRIORITY_MAX);
- Notification n5 = new Notification.Builder(mContext)
+ Notification n5 = new Notification.Builder(mContext, TEST_CHANNEL_ID)
.setCategory(Notification.CATEGORY_MESSAGE).build();
mRecordSms = new NotificationRecord(mContext, new StatusBarNotification(smsPkg,
smsPkg, 1, "sms", smsUid, smsUid, n5, new UserHandle(userId),
"", 1299), getDefaultChannel());
mRecordSms.setUserImportance(NotificationManager.IMPORTANCE_DEFAULT);
- Notification n6 = new Notification.Builder(mContext).build();
+ Notification n6 = new Notification.Builder(mContext, TEST_CHANNEL_ID).build();
mRecordStarredContact = new NotificationRecord(mContext, new StatusBarNotification(pkg2,
pkg2, 1, "starred", uid2, uid2, n6, new UserHandle(userId),
"", 1259), getDefaultChannel());
mRecordStarredContact.setContactAffinity(ValidateNotificationPeople.STARRED_CONTACT);
mRecordStarredContact.setUserImportance(NotificationManager.IMPORTANCE_DEFAULT);
- Notification n7 = new Notification.Builder(mContext).build();
+ Notification n7 = new Notification.Builder(mContext, TEST_CHANNEL_ID).build();
mRecordContact = new NotificationRecord(mContext, new StatusBarNotification(pkg2,
pkg2, 1, "contact", uid2, uid2, n7, new UserHandle(userId),
"", 1259), getDefaultChannel());
mRecordContact.setContactAffinity(ValidateNotificationPeople.VALID_CONTACT);
mRecordContact.setUserImportance(NotificationManager.IMPORTANCE_DEFAULT);
- Notification n8 = new Notification.Builder(mContext).build();
+ Notification n8 = new Notification.Builder(mContext, TEST_CHANNEL_ID).build();
mRecordUrgent = new NotificationRecord(mContext, new StatusBarNotification(pkg2,
pkg2, 1, "urgent", uid2, uid2, n8, new UserHandle(userId),
"", 1258), getDefaultChannel());
mRecordUrgent.setUserImportance(NotificationManager.IMPORTANCE_HIGH);
- Notification n9 = new Notification.Builder(mContext)
+ Notification n9 = new Notification.Builder(mContext, TEST_CHANNEL_ID)
.setCategory(Notification.CATEGORY_MESSAGE)
.setFlag(Notification.FLAG_ONGOING_EVENT
|Notification.FLAG_FOREGROUND_SERVICE, true)
@@ -174,7 +175,7 @@
"", 9258), getDefaultChannel());
mRecordCheater.setUserImportance(NotificationManager.IMPORTANCE_LOW);
- Notification n10 = new Notification.Builder(mContext)
+ Notification n10 = new Notification.Builder(mContext, TEST_CHANNEL_ID)
.setStyle(new Notification.InboxStyle().setSummaryText("message!")).build();
mRecordEmail = new NotificationRecord(mContext, new StatusBarNotification(pkg2,
pkg2, 1, "email", uid2, uid2, n10, new UserHandle(userId),
diff --git a/services/tests/notification/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/notification/src/com/android/server/notification/NotificationManagerServiceTest.java
index 88f1a53..b7b3617 100644
--- a/services/tests/notification/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/notification/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -129,11 +129,9 @@
if (channel == null) {
channel = new NotificationChannel("id", "name", NotificationManager.IMPORTANCE_DEFAULT);
}
- Notification.Builder nb = new Notification.Builder(mContext)
+ Notification.Builder nb = new Notification.Builder(mContext, channel.getId())
.setContentTitle("foo")
- .setSmallIcon(android.R.drawable.sym_def_app_icon)
- .setChannel(channel.getId())
- .setPriority(Notification.PRIORITY_HIGH);
+ .setSmallIcon(android.R.drawable.sym_def_app_icon);
if (extender != null) {
nb.extend(extender);
}
diff --git a/services/tests/notification/src/com/android/server/notification/RankingHelperTest.java b/services/tests/notification/src/com/android/server/notification/RankingHelperTest.java
index 9ea9ce9..6212626 100644
--- a/services/tests/notification/src/com/android/server/notification/RankingHelperTest.java
+++ b/services/tests/notification/src/com/android/server/notification/RankingHelperTest.java
@@ -93,6 +93,7 @@
private final int uid = 0;
private final String pkg2 = "pkg2";
private final int uid2 = 1111111;
+ private static final String TEST_CHANNEL_ID = "test_channel_id";
private AudioAttributes mAudioAttributes;
private Context getContext() {
@@ -107,7 +108,7 @@
mHelper = new RankingHelper(getContext(), mPm, handler, mUsageStats,
new String[]{ImportanceExtractor.class.getName()});
- mNotiGroupGSortA = new Notification.Builder(getContext())
+ mNotiGroupGSortA = new Notification.Builder(getContext(), TEST_CHANNEL_ID)
.setContentTitle("A")
.setGroup("G")
.setSortKey("A")
@@ -117,7 +118,7 @@
"package", "package", 1, null, 0, 0, mNotiGroupGSortA, user,
null, System.currentTimeMillis()), getDefaultChannel());
- mNotiGroupGSortB = new Notification.Builder(getContext())
+ mNotiGroupGSortB = new Notification.Builder(getContext(), TEST_CHANNEL_ID)
.setContentTitle("B")
.setGroup("G")
.setSortKey("B")
@@ -127,7 +128,7 @@
"package", "package", 1, null, 0, 0, mNotiGroupGSortB, user,
null, System.currentTimeMillis()), getDefaultChannel());
- mNotiNoGroup = new Notification.Builder(getContext())
+ mNotiNoGroup = new Notification.Builder(getContext(), TEST_CHANNEL_ID)
.setContentTitle("C")
.setWhen(1201)
.build();
@@ -135,7 +136,7 @@
"package", "package", 1, null, 0, 0, mNotiNoGroup, user,
null, System.currentTimeMillis()), getDefaultChannel());
- mNotiNoGroup2 = new Notification.Builder(getContext())
+ mNotiNoGroup2 = new Notification.Builder(getContext(), TEST_CHANNEL_ID)
.setContentTitle("D")
.setWhen(1202)
.build();
@@ -143,7 +144,7 @@
"package", "package", 1, null, 0, 0, mNotiNoGroup2, user,
null, System.currentTimeMillis()), getDefaultChannel());
- mNotiNoGroupSortA = new Notification.Builder(getContext())
+ mNotiNoGroupSortA = new Notification.Builder(getContext(), TEST_CHANNEL_ID)
.setContentTitle("E")
.setWhen(1201)
.setSortKey("A")
@@ -776,6 +777,26 @@
}
@Test
+ public void testCreateChannel_addMissingSound() throws Exception {
+ final NotificationChannel channel =
+ new NotificationChannel("id2", "name2", IMPORTANCE_LOW);
+ mHelper.createNotificationChannel(pkg, uid, channel, true);
+ assertNotNull(mHelper.getNotificationChannel(
+ pkg, uid, channel.getId(), false).getSound());
+ }
+
+ @Test
+ public void testCreateChannel_noOverrideSound() throws Exception {
+ Uri sound = new Uri.Builder().scheme("test").build();
+ final NotificationChannel channel = new NotificationChannel("id2", "name2",
+ NotificationManager.IMPORTANCE_DEFAULT);
+ channel.setSound(sound, mAudioAttributes);
+ mHelper.createNotificationChannel(pkg, uid, channel, true);
+ assertEquals(sound, mHelper.getNotificationChannel(
+ pkg, uid, channel.getId(), false).getSound());
+ }
+
+ @Test
public void testPermanentlyDeleteChannels() throws Exception {
NotificationChannel channel1 =
new NotificationChannel("id1", "name1", NotificationManager.IMPORTANCE_HIGH);
diff --git a/services/tests/notification/src/com/android/server/notification/SnoozeHelperTest.java b/services/tests/notification/src/com/android/server/notification/SnoozeHelperTest.java
index 69724f4..9575d32 100644
--- a/services/tests/notification/src/com/android/server/notification/SnoozeHelperTest.java
+++ b/services/tests/notification/src/com/android/server/notification/SnoozeHelperTest.java
@@ -18,6 +18,7 @@
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
@@ -27,6 +28,7 @@
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
+import android.os.SystemClock;
import android.os.UserHandle;
import android.service.notification.StatusBarNotification;
import android.support.test.InstrumentationRegistry;
@@ -49,6 +51,8 @@
@SmallTest
@RunWith(AndroidJUnit4.class)
public class SnoozeHelperTest {
+ private static final String TEST_CHANNEL_ID = "test_channel_id";
+
@Mock SnoozeHelper.Callback mCallback;
@Mock AlarmManager mAm;
@Mock ManagedServices.UserProfiles mUserProfiles;
@@ -71,8 +75,11 @@
public void testSnoozeForTime() throws Exception {
NotificationRecord r = getNotificationRecord("pkg", 1, "one", UserHandle.SYSTEM);
mSnoozeHelper.snooze(r, 1000);
+ ArgumentCaptor<Long> captor = ArgumentCaptor.forClass(Long.class);
verify(mAm, times(1)).setExactAndAllowWhileIdle(
- anyInt(), eq((long) 1000), any(PendingIntent.class));
+ anyInt(), captor.capture(), any(PendingIntent.class));
+ long actualSnoozedUntilDuration = captor.getValue() - SystemClock.elapsedRealtime();
+ assertTrue(Math.abs(actualSnoozedUntilDuration - 1000) < 25);
assertTrue(mSnoozeHelper.isSnoozed(
UserHandle.USER_SYSTEM, r.sbn.getPackageName(), r.getKey()));
}
@@ -227,20 +234,16 @@
private NotificationRecord getNotificationRecord(String pkg, int id, String tag,
UserHandle user) {
- Notification n = new Notification.Builder(getContext())
+ Notification n = new Notification.Builder(getContext(), TEST_CHANNEL_ID)
.setContentTitle("A")
.setGroup("G")
.setSortKey("A")
.setWhen(1205)
.build();
+ final NotificationChannel notificationChannel = new NotificationChannel(
+ TEST_CHANNEL_ID, "name", NotificationManager.IMPORTANCE_LOW);
return new NotificationRecord(getContext(), new StatusBarNotification(
pkg, pkg, id, tag, 0, 0, n, user, null,
- System.currentTimeMillis()), getDefaultChannel());
+ System.currentTimeMillis()), notificationChannel);
}
-
- private NotificationChannel getDefaultChannel() {
- return new NotificationChannel(NotificationChannel.DEFAULT_CHANNEL_ID, "name",
- NotificationManager.IMPORTANCE_LOW);
- }
-
}
diff --git a/services/tests/servicestests/src/com/android/server/NetworkScoreServiceTest.java b/services/tests/servicestests/src/com/android/server/NetworkScoreServiceTest.java
index c0b79be..4141f2f 100644
--- a/services/tests/servicestests/src/com/android/server/NetworkScoreServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/NetworkScoreServiceTest.java
@@ -56,8 +56,7 @@
import android.net.INetworkScoreCache;
import android.net.NetworkKey;
import android.net.NetworkScoreManager;
-import android.net.NetworkScorerAppManager;
-import android.net.NetworkScorerAppManager.NetworkScorerAppData;
+import android.net.NetworkScorerAppData;
import android.net.RecommendationRequest;
import android.net.RecommendationResult;
import android.net.ScoredNetwork;
@@ -120,14 +119,16 @@
private static final String INVALID_BSSID = "invalid_bssid";
private static final ComponentName RECOMMENDATION_SERVICE_COMP =
new ComponentName("newPackageName", "newScoringServiceClass");
+ private static final ComponentName USE_WIFI_ENABLE_ACTIVITY_COMP =
+ new ComponentName("useWifiPackageName", "enableUseWifiActivityClass");
private static final ScoredNetwork SCORED_NETWORK =
new ScoredNetwork(new NetworkKey(new WifiKey(quote(SSID), "00:00:00:00:00:00")),
null /* rssiCurve*/);
private static final ScoredNetwork SCORED_NETWORK_2 =
new ScoredNetwork(new NetworkKey(new WifiKey(quote(SSID_2), "00:00:00:00:00:00")),
null /* rssiCurve*/);
- private static final NetworkScorerAppData NEW_SCORER =
- new NetworkScorerAppData(1, RECOMMENDATION_SERVICE_COMP);
+ private static final NetworkScorerAppData NEW_SCORER = new NetworkScorerAppData(
+ 1, RECOMMENDATION_SERVICE_COMP, USE_WIFI_ENABLE_ACTIVITY_COMP);
@Mock private NetworkScorerAppManager mNetworkScorerAppManager;
@Mock private Context mContext;
@@ -199,10 +200,10 @@
}
@Test
- public void testSystemRunning() {
+ public void testOnUserUnlocked() {
when(mNetworkScorerAppManager.getActiveScorer()).thenReturn(NEW_SCORER);
- mNetworkScoreService.systemRunning();
+ mNetworkScoreService.onUserUnlocked(0);
verify(mContext).bindServiceAsUser(MockUtils.checkIntent(
new Intent(NetworkScoreManager.ACTION_RECOMMEND_NETWORKS)
@@ -547,9 +548,9 @@
}
@Test
- public void testSetActiveScorer_noScoreNetworksPermission() {
- doThrow(new SecurityException()).when(mContext)
- .enforceCallingOrSelfPermission(eq(permission.SCORE_NETWORKS), anyString());
+ public void testSetActiveScorer_noRequestNetworkScoresPermission() {
+ when(mContext.checkCallingOrSelfPermission(permission.REQUEST_NETWORK_SCORES))
+ .thenReturn(PackageManager.PERMISSION_DENIED);
try {
mNetworkScoreService.setActiveScorer(null);
@@ -628,7 +629,7 @@
@Test
public void testIsCallerActiveScorer_noBoundService() throws Exception {
- mNetworkScoreService.systemRunning();
+ mNetworkScoreService.onUserUnlocked(0);
assertFalse(mNetworkScoreService.isCallerActiveScorer(Binder.getCallingUid()));
}
@@ -649,7 +650,7 @@
@Test
public void testGetActiveScorerPackage_notActive() throws Exception {
- mNetworkScoreService.systemRunning();
+ mNetworkScoreService.onUserUnlocked(0);
assertNull(mNetworkScoreService.getActiveScorerPackage());
}
@@ -657,10 +658,12 @@
@Test
public void testGetActiveScorerPackage_active() throws Exception {
when(mNetworkScorerAppManager.getActiveScorer()).thenReturn(NEW_SCORER);
- mNetworkScoreService.systemRunning();
+ mNetworkScoreService.onUserUnlocked(0);
assertEquals(NEW_SCORER.getRecommendationServicePackageName(),
mNetworkScoreService.getActiveScorerPackage());
+ assertEquals(NEW_SCORER.getEnableUseOpenWifiActivity(),
+ mNetworkScoreService.getActiveScorer().getEnableUseOpenWifiActivity());
}
@Test
@@ -920,8 +923,8 @@
throws Exception {
when(mContext.checkCallingOrSelfPermission(permission.REQUEST_NETWORK_SCORES))
.thenReturn(PackageManager.PERMISSION_GRANTED);
- NetworkScorerAppData expectedAppData =
- new NetworkScorerAppData(Binder.getCallingUid(), RECOMMENDATION_SERVICE_COMP);
+ NetworkScorerAppData expectedAppData = new NetworkScorerAppData(Binder.getCallingUid(),
+ RECOMMENDATION_SERVICE_COMP, USE_WIFI_ENABLE_ACTIVITY_COMP);
bindToScorer(expectedAppData);
assertEquals(expectedAppData, mNetworkScoreService.getActiveScorer());
}
@@ -956,13 +959,13 @@
return true;
}
});
- mNetworkScoreService.systemRunning();
+ mNetworkScoreService.onUserUnlocked(0);
}
private void bindToScorer(boolean callerIsScorer) {
final int callingUid = callerIsScorer ? Binder.getCallingUid() : Binder.getCallingUid() + 1;
- NetworkScorerAppData appData =
- new NetworkScorerAppData(callingUid, RECOMMENDATION_SERVICE_COMP);
+ NetworkScorerAppData appData = new NetworkScorerAppData(callingUid,
+ RECOMMENDATION_SERVICE_COMP, USE_WIFI_ENABLE_ACTIVITY_COMP);
bindToScorer(appData);
}
@@ -970,7 +973,7 @@
when(mNetworkScorerAppManager.getActiveScorer()).thenReturn(appData);
when(mContext.bindServiceAsUser(isA(Intent.class), isA(ServiceConnection.class), anyInt(),
isA(UserHandle.class))).thenReturn(true);
- mNetworkScoreService.systemRunning();
+ mNetworkScoreService.onUserUnlocked(0);
}
private static class OnResultListener implements RemoteCallback.OnResultListener {
diff --git a/services/tests/servicestests/src/com/android/server/NetworkScorerAppManagerTest.java b/services/tests/servicestests/src/com/android/server/NetworkScorerAppManagerTest.java
new file mode 100644
index 0000000..e9a2d34
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/NetworkScorerAppManagerTest.java
@@ -0,0 +1,322 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.server;
+
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertNotNull;
+import static junit.framework.Assert.assertNull;
+import static junit.framework.Assert.assertTrue;
+
+import static org.junit.Assert.assertFalse;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.Manifest.permission;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ActivityInfo;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.content.pm.ServiceInfo;
+import android.content.res.Resources;
+import android.net.NetworkScoreManager;
+import android.net.NetworkScorerAppData;
+import android.os.Bundle;
+import android.provider.Settings;
+import android.support.test.runner.AndroidJUnit4;
+
+import com.android.internal.R;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentMatcher;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.MockitoAnnotations;
+
+import java.util.ArrayList;
+import java.util.List;
+
+@RunWith(AndroidJUnit4.class)
+public class NetworkScorerAppManagerTest {
+ @Mock private Context mMockContext;
+ @Mock private PackageManager mMockPm;
+ @Mock private Resources mResources;
+ @Mock private NetworkScorerAppManager.SettingsFacade mSettingsFacade;
+ private NetworkScorerAppManager mNetworkScorerAppManager;
+ private List<ResolveInfo> mAvailableServices;
+
+ @Before
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
+ mAvailableServices = new ArrayList<>();
+ when(mMockContext.getPackageManager()).thenReturn(mMockPm);
+ when(mMockPm.queryIntentServices(Mockito.argThat(new ArgumentMatcher<Intent>() {
+ @Override
+ public boolean matches(Object object) {
+ Intent intent = (Intent) object;
+ return NetworkScoreManager.ACTION_RECOMMEND_NETWORKS.equals(intent.getAction());
+ }
+ }), eq(PackageManager.GET_META_DATA))).thenReturn(mAvailableServices);
+ when(mMockContext.getResources()).thenReturn(mResources);
+
+ mNetworkScorerAppManager = new NetworkScorerAppManager(mMockContext, mSettingsFacade);
+ }
+
+ @Test
+ public void testGetActiveScorer_providerAvailable() throws Exception {
+ final ComponentName recoComponent = new ComponentName("package1", "class1");
+ setNetworkRecoPackageSetting(recoComponent.getPackageName());
+ mockScoreNetworksGranted(recoComponent.getPackageName());
+ mockRecommendationServiceAvailable(recoComponent, 924 /* packageUid */);
+
+ final NetworkScorerAppData activeScorer = mNetworkScorerAppManager.getActiveScorer();
+ assertNotNull(activeScorer);
+ assertEquals(recoComponent, activeScorer.getRecommendationServiceComponent());
+ assertEquals(924, activeScorer.packageUid);
+ }
+
+ @Test
+ public void testGetActiveScorer_permissionMissing() throws Exception {
+ final ComponentName recoComponent = new ComponentName("package1", "class1");
+ setNetworkRecoPackageSetting(recoComponent.getPackageName());
+ mockScoreNetworksDenied(recoComponent.getPackageName());
+ mockRecommendationServiceAvailable(recoComponent, 924 /* packageUid */);
+
+ final NetworkScorerAppData activeScorer = mNetworkScorerAppManager.getActiveScorer();
+ assertNull(activeScorer);
+ }
+
+ @Test
+ public void testGetActiveScorer_providerAvailable_enableUseOpenWifiActivityNotSet()
+ throws Exception {
+ final ComponentName recoComponent = new ComponentName("package1", "class1");
+ setNetworkRecoPackageSetting(recoComponent.getPackageName());
+ mockScoreNetworksGranted(recoComponent.getPackageName());
+ mockRecommendationServiceAvailable(recoComponent, 924 /* packageUid */,
+ null /* enableUseOpenWifiPackageActivityPackage*/);
+
+ final NetworkScorerAppData activeScorer = mNetworkScorerAppManager.getActiveScorer();
+ assertNotNull(activeScorer);
+ assertEquals(recoComponent, activeScorer.getRecommendationServiceComponent());
+ assertEquals(924, activeScorer.packageUid);
+ assertNull(activeScorer.getEnableUseOpenWifiActivity());
+ }
+
+ @Test
+ public void testGetActiveScorer_providerAvailable_enableUseOpenWifiActivityNotResolved()
+ throws Exception {
+ final ComponentName recoComponent = new ComponentName("package1", "class1");
+ setNetworkRecoPackageSetting(recoComponent.getPackageName());
+ mockScoreNetworksGranted(recoComponent.getPackageName());
+ mockRecommendationServiceAvailable(recoComponent, 924 /* packageUid */,
+ "package2" /* enableUseOpenWifiPackageActivityPackage*/);
+
+ final NetworkScorerAppData activeScorer = mNetworkScorerAppManager.getActiveScorer();
+ assertNotNull(activeScorer);
+ assertEquals(recoComponent, activeScorer.getRecommendationServiceComponent());
+ assertEquals(924, activeScorer.packageUid);
+ assertNull(activeScorer.getEnableUseOpenWifiActivity());
+ }
+
+ @Test
+ public void testGetActiveScorer_providerAvailable_enableUseOpenWifiActivityResolved()
+ throws Exception {
+ final ComponentName recoComponent = new ComponentName("package1", "class1");
+ final ComponentName enableUseOpenWifiComponent = new ComponentName("package2", "class2");
+ setNetworkRecoPackageSetting(recoComponent.getPackageName());
+ mockScoreNetworksGranted(recoComponent.getPackageName());
+ mockRecommendationServiceAvailable(recoComponent, 924 /* packageUid */,
+ enableUseOpenWifiComponent.getPackageName());
+ mockEnableUseOpenWifiActivity(enableUseOpenWifiComponent);
+
+ final NetworkScorerAppData activeScorer = mNetworkScorerAppManager.getActiveScorer();
+ assertNotNull(activeScorer);
+ assertEquals(recoComponent, activeScorer.getRecommendationServiceComponent());
+ assertEquals(924, activeScorer.packageUid);
+ assertEquals(enableUseOpenWifiComponent, activeScorer.getEnableUseOpenWifiActivity());
+ }
+
+ @Test
+ public void testGetActiveScorer_packageSettingIsNull()
+ throws Exception {
+ // NETWORK_RECOMMENDATIONS_PACKAGE is null
+
+ final NetworkScorerAppData activeScorer = mNetworkScorerAppManager.getActiveScorer();
+ assertNull(activeScorer);
+ }
+
+ @Test
+ public void testGetActiveScorer_packageSettingIsInvalid() throws Exception {
+ final ComponentName recoComponent = new ComponentName("package1", "class1");
+ setDefaultNetworkRecommendationPackage(recoComponent.getPackageName());
+ mockScoreNetworksGranted(recoComponent.getPackageName());
+ // NETWORK_RECOMMENDATIONS_PACKAGE is set to a package that isn't a recommender.
+
+ final NetworkScorerAppData activeScorer = mNetworkScorerAppManager.getActiveScorer();
+ assertNull(activeScorer);
+ }
+
+ @Test
+ public void testSetActiveScorer_noChange() throws Exception {
+ String packageName = "package";
+ setNetworkRecoPackageSetting(packageName);
+
+ assertTrue(mNetworkScorerAppManager.setActiveScorer(packageName));
+ verify(mSettingsFacade, never()).putString(any(), any(), any());
+ }
+
+ @Test
+ public void testSetActiveScorer_nullPackage() throws Exception {
+ String packageName = "package";
+ String defaultPackage = "defaultPackage";
+ setNetworkRecoPackageSetting(packageName);
+ setDefaultNetworkRecommendationPackage(defaultPackage);
+
+ assertTrue(mNetworkScorerAppManager.setActiveScorer(null));
+ verify(mSettingsFacade).putString(mMockContext,
+ Settings.Global.NETWORK_RECOMMENDATIONS_PACKAGE, defaultPackage);
+ }
+
+ @Test
+ public void testSetActiveScorer_validPackage() throws Exception {
+ String packageName = "package";
+ String newPackage = "newPackage";
+ setNetworkRecoPackageSetting(packageName);
+ final ComponentName recoComponent = new ComponentName(newPackage, "class1");
+ mockScoreNetworksGranted(recoComponent.getPackageName());
+ mockRecommendationServiceAvailable(recoComponent, 924 /* packageUid */, null);
+
+ assertTrue(mNetworkScorerAppManager.setActiveScorer(newPackage));
+ verify(mSettingsFacade).putString(mMockContext,
+ Settings.Global.NETWORK_RECOMMENDATIONS_PACKAGE, newPackage);
+ }
+
+ @Test
+ public void testSetActiveScorer_invalidPackage() throws Exception {
+ String packageName = "package";
+ String newPackage = "newPackage";
+ setNetworkRecoPackageSetting(packageName);
+ // newPackage doesn't resolve to a valid recommender
+
+ assertFalse(mNetworkScorerAppManager.setActiveScorer(newPackage));
+ verify(mSettingsFacade, never()).putString(any(), any(), any());
+ }
+
+
+ @Test
+ public void testRevertToDefaultIfNoActive_notActive() throws Exception {
+ String defaultPackage = "defaultPackage";
+ setDefaultNetworkRecommendationPackage(defaultPackage);
+
+ mNetworkScorerAppManager.revertToDefaultIfNoActive();
+
+ verify(mSettingsFacade).putString(mMockContext,
+ Settings.Global.NETWORK_RECOMMENDATIONS_PACKAGE, defaultPackage);
+ }
+
+ @Test
+ public void testRevertToDefaultIfNoActive_active() throws Exception {
+ String packageName = "package";
+ setNetworkRecoPackageSetting(packageName);
+ final ComponentName recoComponent = new ComponentName(packageName, "class1");
+ mockScoreNetworksGranted(recoComponent.getPackageName());
+ mockRecommendationServiceAvailable(recoComponent, 924 /* packageUid */, null);
+
+ mNetworkScorerAppManager.revertToDefaultIfNoActive();
+
+ verify(mSettingsFacade, never()).putString(any(), any(), any());
+ }
+
+ private void setNetworkRecoPackageSetting(String packageName) {
+ when(mSettingsFacade.getString(mMockContext,
+ Settings.Global.NETWORK_RECOMMENDATIONS_PACKAGE)).thenReturn(packageName);
+ }
+
+ private void setDefaultNetworkRecommendationPackage(String name) {
+ when(mResources.getString(R.string.config_defaultNetworkRecommendationProviderPackage))
+ .thenReturn(name);
+ }
+
+ private void mockScoreNetworksGranted(String packageName) {
+ when(mMockPm.checkPermission(permission.SCORE_NETWORKS, packageName))
+ .thenReturn(PackageManager.PERMISSION_GRANTED);
+ }
+
+ private void mockScoreNetworksDenied(String packageName) {
+ when(mMockPm.checkPermission(permission.SCORE_NETWORKS, packageName))
+ .thenReturn(PackageManager.PERMISSION_DENIED);
+ }
+
+ private void mockRecommendationServiceAvailable(final ComponentName compName, int packageUid) {
+ mockRecommendationServiceAvailable(compName, packageUid, null);
+ }
+
+ private void mockRecommendationServiceAvailable(final ComponentName compName, int packageUid,
+ String enableUseOpenWifiActivityPackage) {
+ final ResolveInfo serviceInfo = new ResolveInfo();
+ serviceInfo.serviceInfo = new ServiceInfo();
+ serviceInfo.serviceInfo.name = compName.getClassName();
+ serviceInfo.serviceInfo.packageName = compName.getPackageName();
+ serviceInfo.serviceInfo.applicationInfo = new ApplicationInfo();
+ serviceInfo.serviceInfo.applicationInfo.uid = packageUid;
+ if (enableUseOpenWifiActivityPackage != null) {
+ serviceInfo.serviceInfo.metaData = new Bundle();
+ serviceInfo.serviceInfo.metaData.putString(
+ NetworkScoreManager.USE_OPEN_WIFI_PACKAGE_META_DATA,
+ enableUseOpenWifiActivityPackage);
+ }
+
+ final int flags = PackageManager.GET_META_DATA;
+ when(mMockPm.resolveService(
+ Mockito.argThat(new ArgumentMatcher<Intent>() {
+ @Override
+ public boolean matches(Object object) {
+ Intent intent = (Intent) object;
+ return NetworkScoreManager.ACTION_RECOMMEND_NETWORKS
+ .equals(intent.getAction())
+ && compName.getPackageName().equals(intent.getPackage());
+ }
+ }), Mockito.eq(flags))).thenReturn(serviceInfo);
+
+ mAvailableServices.add(serviceInfo);
+ }
+
+ private void mockEnableUseOpenWifiActivity(final ComponentName useOpenWifiComp) {
+ final ResolveInfo resolveActivityInfo = new ResolveInfo();
+ resolveActivityInfo.activityInfo = new ActivityInfo();
+ resolveActivityInfo.activityInfo.name = useOpenWifiComp.getClassName();
+ resolveActivityInfo.activityInfo.packageName = useOpenWifiComp.getPackageName();
+
+ final int flags = 0;
+ when(mMockPm.resolveActivity(
+ Mockito.argThat(new ArgumentMatcher<Intent>() {
+ @Override
+ public boolean matches(Object object) {
+ Intent intent = (Intent) object;
+ return NetworkScoreManager.ACTION_CUSTOM_ENABLE.equals(intent.getAction())
+ && useOpenWifiComp.getPackageName().equals(intent.getPackage());
+ }
+ }), Mockito.eq(flags))).thenReturn(resolveActivityInfo);
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
index d65a9bf..756514b 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -34,7 +34,7 @@
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
-import android.content.pm.ParceledListSlice;
+import android.content.pm.StringParceledListSlice;
import android.content.res.Resources;
import android.graphics.Color;
import android.net.IIpConnectivityMetrics;
@@ -56,7 +56,6 @@
import android.util.Pair;
import com.android.internal.R;
-import com.android.internal.util.ParcelableString;
import com.android.internal.widget.LockPatternUtils;
import com.android.server.LocalServices;
import com.android.server.SystemService;
@@ -1220,8 +1219,8 @@
mContext.userContexts.put(user, mContext);
when(mContext.resources.getColor(anyInt(), anyObject())).thenReturn(Color.WHITE);
- ParceledListSlice<ParcelableString> oneCert = asSlice(new String[] {"1"});
- ParceledListSlice<ParcelableString> fourCerts = asSlice(new String[] {"1", "2", "3", "4"});
+ StringParceledListSlice oneCert = asSlice(new String[] {"1"});
+ StringParceledListSlice fourCerts = asSlice(new String[] {"1", "2", "3", "4"});
final String TEST_STRING = "Test for exactly 2 certs out of 4";
doReturn(TEST_STRING).when(mContext.resources).getQuantityText(anyInt(), eq(2));
@@ -1229,7 +1228,7 @@
// Given that we have exactly one certificate installed,
when(mContext.keyChainConnection.getService().getUserCaAliases()).thenReturn(oneCert);
// when that certificate is approved,
- dpms.approveCaCert(oneCert.getList().get(0).string, userId, true);
+ dpms.approveCaCert(oneCert.getList().get(0), userId, true);
// a notification should not be shown.
verify(mContext.notificationManager, timeout(1000))
.cancelAsUser(anyString(), anyInt(), eq(user));
@@ -1237,8 +1236,8 @@
// Given that we have four certificates installed,
when(mContext.keyChainConnection.getService().getUserCaAliases()).thenReturn(fourCerts);
// when two of them are approved (one of them approved twice hence no action),
- dpms.approveCaCert(fourCerts.getList().get(0).string, userId, true);
- dpms.approveCaCert(fourCerts.getList().get(1).string, userId, true);
+ dpms.approveCaCert(fourCerts.getList().get(0), userId, true);
+ dpms.approveCaCert(fourCerts.getList().get(1), userId, true);
// a notification should be shown saying that there are two certificates left to approve.
verify(mContext.notificationManager, timeout(1000))
.notifyAsUser(anyString(), anyInt(), argThat(
@@ -3974,18 +3973,9 @@
}
/**
- * Convert String[] to ParceledListSlice<ParcelableString>.
- * <p>
- * TODO: This shouldn't be necessary. If ParcelableString does need to exist, it also needs
- * a real constructor.
+ * Convert String[] to StringParceledListSlice.
*/
- private static ParceledListSlice<ParcelableString> asSlice(String[] s) {
- List<ParcelableString> list = new ArrayList<>(s.length);
- for (int i = 0; i < s.length; i++) {
- ParcelableString item = new ParcelableString();
- item.string = s[i];
- list.add(i, item);
- }
- return new ParceledListSlice<ParcelableString>(list);
+ private static StringParceledListSlice asSlice(String[] s) {
+ return new StringParceledListSlice(Arrays.asList(s));
}
}
diff --git a/services/tests/servicestests/src/com/android/server/job/JobStoreTest.java b/services/tests/servicestests/src/com/android/server/job/JobStoreTest.java
index f615bf3..33e1a16 100644
--- a/services/tests/servicestests/src/com/android/server/job/JobStoreTest.java
+++ b/services/tests/servicestests/src/com/android/server/job/JobStoreTest.java
@@ -10,7 +10,6 @@
import android.test.AndroidTestCase;
import android.test.RenamingDelegatingContext;
import android.util.Log;
-import android.util.ArraySet;
import com.android.server.job.JobStore.JobSet;
import com.android.server.job.controllers.JobStatus;
@@ -278,6 +277,8 @@
assertEquals("Invalid charging constraint.", first.isRequireCharging(),
second.isRequireCharging());
+ assertEquals("Invalid battery not low constraint.", first.isRequireBatteryNotLow(),
+ second.isRequireBatteryNotLow());
assertEquals("Invalid idle constraint.", first.isRequireDeviceIdle(),
second.isRequireDeviceIdle());
assertEquals("Invalid unmetered constraint.",
diff --git a/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java b/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java
index 100338e..1b59d72 100644
--- a/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java
@@ -34,6 +34,7 @@
import static org.mockito.Mockito.when;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.annotation.UserIdInt;
import android.app.Activity;
import android.app.ActivityManager;
@@ -1324,20 +1325,23 @@
protected ShortcutInfo makeShortcut(String id) {
return makeShortcut(
id, "Title-" + id, /* activity =*/ null, /* icon =*/ null,
- makeIntent(Intent.ACTION_VIEW, ShortcutActivity.class), /* rank =*/ 0);
+ makeIntent(Intent.ACTION_VIEW, ShortcutActivity.class), /* rank =*/ 0,
+ /* chooserFilter=*/ null, /* chooserComponentNames=*/ null);
}
@Deprecated // Title was renamed to short label.
protected ShortcutInfo makeShortcutWithTitle(String id, String title) {
return makeShortcut(
id, title, /* activity =*/ null, /* icon =*/ null,
- makeIntent(Intent.ACTION_VIEW, ShortcutActivity.class), /* rank =*/ 0);
+ makeIntent(Intent.ACTION_VIEW, ShortcutActivity.class), /* rank =*/ 0,
+ /* chooserFilter=*/ null, /* chooserComponentNames=*/ null);
}
protected ShortcutInfo makeShortcutWithShortLabel(String id, String shortLabel) {
return makeShortcut(
id, shortLabel, /* activity =*/ null, /* icon =*/ null,
- makeIntent(Intent.ACTION_VIEW, ShortcutActivity.class), /* rank =*/ 0);
+ makeIntent(Intent.ACTION_VIEW, ShortcutActivity.class), /* rank =*/ 0,
+ /* chooserFilter=*/ null, /* chooserComponentNames=*/ null);
}
/**
@@ -1346,7 +1350,8 @@
protected ShortcutInfo makeShortcutWithTimestamp(String id, long timestamp) {
final ShortcutInfo s = makeShortcut(
id, "Title-" + id, /* activity =*/ null, /* icon =*/ null,
- makeIntent(Intent.ACTION_VIEW, ShortcutActivity.class), /* rank =*/ 0);
+ makeIntent(Intent.ACTION_VIEW, ShortcutActivity.class), /* rank =*/ 0,
+ /* chooserFilter=*/ null, /* chooserComponentNames=*/ null);
s.setTimestamp(timestamp);
return s;
}
@@ -1358,7 +1363,8 @@
ComponentName activity) {
final ShortcutInfo s = makeShortcut(
id, "Title-" + id, activity, /* icon =*/ null,
- makeIntent(Intent.ACTION_VIEW, ShortcutActivity.class), /* rank =*/ 0);
+ makeIntent(Intent.ACTION_VIEW, ShortcutActivity.class), /* rank =*/ 0,
+ /* chooserFilter=*/ null, /* chooserComponentNames=*/ null);
s.setTimestamp(timestamp);
return s;
}
@@ -1369,7 +1375,27 @@
protected ShortcutInfo makeShortcutWithIcon(String id, Icon icon) {
return makeShortcut(
id, "Title-" + id, /* activity =*/ null, icon,
- makeIntent(Intent.ACTION_VIEW, ShortcutActivity.class), /* rank =*/ 0);
+ makeIntent(Intent.ACTION_VIEW, ShortcutActivity.class), /* rank =*/ 0,
+ /* chooserFilter=*/ null, /* chooserComponentNames=*/ null);
+ }
+
+ protected ShortcutInfo makeChooserShortcut(String id, int i, boolean includeIntent) {
+ List<IntentFilter> filters = new ArrayList<>();
+ List<ComponentName> componentNames = new ArrayList<>();
+ for(int j = 0; j < i; j++) {
+ final IntentFilter filter = new IntentFilter();
+ filter.addAction("view");
+ filters.add(filter);
+
+ componentNames.add(new ComponentName("xxxx", "yy" + i));
+ }
+ Intent intent = null;
+ if (includeIntent) {
+ intent = makeIntent(Intent.ACTION_VIEW, ShortcutActivity.class);
+ }
+ return makeShortcut(
+ id, "Title-" + id, /* activity =*/ null, /* icon */ null,
+ intent, /* rank =*/ 0, filters, componentNames);
}
protected ShortcutInfo makePackageShortcut(String packageName, String id) {
@@ -1378,7 +1404,8 @@
setCaller(packageName);
ShortcutInfo s = makeShortcut(
id, "Title-" + id, /* activity =*/ null, /* icon =*/ null,
- makeIntent(Intent.ACTION_VIEW, ShortcutActivity.class), /* rank =*/ 0);
+ makeIntent(Intent.ACTION_VIEW, ShortcutActivity.class), /* rank =*/ 0,
+ /* chooserFilter=*/ null, /* chooserComponentNames=*/ null);
setCaller(origCaller); // restore the caller
return s;
@@ -1402,39 +1429,52 @@
protected ShortcutInfo makeShortcutWithActivity(String id, ComponentName activity) {
return makeShortcut(
id, "Title-" + id, activity, /* icon =*/ null,
- makeIntent(Intent.ACTION_VIEW, ShortcutActivity.class), /* rank =*/ 0);
+ makeIntent(Intent.ACTION_VIEW, ShortcutActivity.class), /* rank =*/ 0,
+ /* chooserFilters =*/ null, /* chooserComponentNames =*/ null);
}
protected ShortcutInfo makeShortcutWithIntent(String id, Intent intent) {
return makeShortcut(
id, "Title-" + id, /* activity =*/ null, /* icon =*/ null,
- intent, /* rank =*/ 0);
+ intent, /* rank =*/ 0, /* chooserFilters =*/ null,
+ /* chooserComponentNames =*/ null);
+
}
protected ShortcutInfo makeShortcutWithActivityAndTitle(String id, ComponentName activity,
String title) {
return makeShortcut(
id, title, activity, /* icon =*/ null,
- makeIntent(Intent.ACTION_VIEW, ShortcutActivity.class), /* rank =*/ 0);
+ makeIntent(Intent.ACTION_VIEW, ShortcutActivity.class), /* rank =*/ 0,
+ /* chooserFilters =*/ null, /* chooserComponentNames =*/ null);
}
protected ShortcutInfo makeShortcutWithActivityAndRank(String id, ComponentName activity,
int rank) {
return makeShortcut(
id, "Title-" + id, activity, /* icon =*/ null,
- makeIntent(Intent.ACTION_VIEW, ShortcutActivity.class), rank);
+ makeIntent(Intent.ACTION_VIEW, ShortcutActivity.class), rank,
+ /* chooserFilters =*/ null, /* chooserComponentNames =*/ null);
}
/**
* Make a shortcut with details.
*/
protected ShortcutInfo makeShortcut(String id, String title, ComponentName activity,
- Icon icon, Intent intent, int rank) {
+ Icon icon, Intent intent, int rank, @Nullable List<IntentFilter> chooserFilters,
+ @Nullable List<ComponentName> chooserComponentNames) {
final ShortcutInfo.Builder b = new ShortcutInfo.Builder(mClientContext, id)
.setActivity(new ComponentName(mClientContext.getPackageName(), "main"))
.setShortLabel(title)
- .setRank(rank)
- .setIntent(intent);
+ .setRank(rank);
+ if (intent != null) {
+ b.setIntent(intent);
+ }
+ if (chooserFilters != null) {
+ for (int i = 0; i < chooserFilters.size(); i++) {
+ b.addChooserIntentFilter(chooserFilters.get(i), chooserComponentNames.get(i));
+ }
+ }
if (icon != null) {
b.setIcon(icon);
}
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java b/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java
index 384f49f..d8db331 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java
@@ -197,7 +197,6 @@
assertEquals(a.installLocation, b.installLocation);
assertEquals(a.coreApp, b.coreApp);
assertEquals(a.mRequiredForAllUsers, b.mRequiredForAllUsers);
- assertEquals(a.mOverlayPriority, b.mOverlayPriority);
assertEquals(a.mTrustedOverlay, b.mTrustedOverlay);
assertEquals(a.use32bitAbi, b.use32bitAbi);
assertEquals(a.packageName, b.packageName);
@@ -414,9 +413,7 @@
assertTrue(Arrays.equals(a.sharedLibraryFiles, that.sharedLibraryFiles));
assertEquals(a.dataDir, that.dataDir);
assertEquals(a.deviceProtectedDataDir, that.deviceProtectedDataDir);
- assertEquals(a.deviceEncryptedDataDir, that.deviceEncryptedDataDir);
assertEquals(a.credentialProtectedDataDir, that.credentialProtectedDataDir);
- assertEquals(a.credentialEncryptedDataDir, that.credentialEncryptedDataDir);
assertEquals(a.nativeLibraryDir, that.nativeLibraryDir);
assertEquals(a.secondaryNativeLibraryDir, that.secondaryNativeLibraryDir);
assertEquals(a.nativeLibraryRootDir, that.nativeLibraryRootDir);
@@ -433,7 +430,6 @@
pkg.installLocation = 100;
pkg.coreApp = true;
pkg.mRequiredForAllUsers = true;
- pkg.mOverlayPriority = 100;
pkg.mTrustedOverlay = true;
pkg.use32bitAbi = true;
pkg.packageName = "foo";
diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java
index e4d92ba..94ff07f 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java
@@ -15,6 +15,7 @@
*/
package com.android.server.pm;
+import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertAllChooser;
import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertAllDisabled;
import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertAllDynamic;
import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertAllDynamicOrPinned;
@@ -256,7 +257,9 @@
icon1,
makeIntent(Intent.ACTION_ASSIST, ShortcutActivity2.class,
"key1", "val1", "nest", makeBundle("key", 123)),
- /* weight */ 10);
+ /* weight */ 10,
+ /* chooserFilter=*/ null,
+ /* chooserComponentNames=*/ null);
final ShortcutInfo si2 = makeShortcut(
"shortcut2",
@@ -264,14 +267,18 @@
/* activity */ null,
icon2,
makeIntent(Intent.ACTION_ASSIST, ShortcutActivity3.class),
- /* weight */ 12);
+ /* weight */ 12,
+ /* chooserFilter=*/ null,
+ /* chooserComponentNames=*/ null);
final ShortcutInfo si3 = makeShortcut(
"shortcut3",
"Title 3",
/* activity */ null,
icon3,
makeIntent(Intent.ACTION_ASSIST, ShortcutActivity3.class),
- /* weight */ 13);
+ /* weight */ 13,
+ /* chooserFilter=*/ null,
+ /* chooserComponentNames=*/ null);
assertTrue(mManager.setDynamicShortcuts(list(si1, si2, si3)));
assertShortcutIds(assertAllNotKeyFieldsOnly(
@@ -982,8 +989,10 @@
makeShortcut("s2"),
makeShortcut("s3"),
makeShortcut("s4"),
- makeShortcut("s5")
- )));
+ makeShortcut("s5"),
+ makeChooserShortcut("s6", 2, true),
+ makeChooserShortcut("s7", 2, true),
+ makeChooserShortcut("s8", 1, true))));
});
runWithCaller(CALLING_PACKAGE_2, UserHandle.USER_SYSTEM, () -> {
assertTrue(mManager.setDynamicShortcuts(list(
@@ -991,11 +1000,13 @@
makeShortcut("s2"),
makeShortcut("s3"),
makeShortcut("s4"),
- makeShortcut("s5")
- )));
+ makeShortcut("s5"),
+ makeChooserShortcut("s6", 2, true),
+ makeChooserShortcut("s7", 2, true),
+ makeChooserShortcut("s8", 1, true))));
});
runWithCaller(LAUNCHER_1, UserHandle.USER_SYSTEM, () -> {
- mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s2", "s3"),
+ mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s2", "s3", "s6"),
getCallingUser());
mLauncherApps.pinShortcuts(CALLING_PACKAGE_2, list("s4", "s5"),
getCallingUser());
@@ -1008,19 +1019,20 @@
mManager.removeDynamicShortcuts(list("s1"));
mManager.removeDynamicShortcuts(list("s3"));
mManager.removeDynamicShortcuts(list("s5"));
+ mManager.removeDynamicShortcuts(list("s7"));
});
runWithCaller(CALLING_PACKAGE_1, UserHandle.USER_SYSTEM, () -> {
assertShortcutIds(assertAllDynamic(
mManager.getDynamicShortcuts()),
- "s3", "s4", "s5");
+ "s3", "s4", "s5", "s6", "s7", "s8");
assertShortcutIds(assertAllPinned(
mManager.getPinnedShortcuts()),
- "s2", "s3");
+ "s2", "s3", "s6");
});
runWithCaller(CALLING_PACKAGE_2, UserHandle.USER_SYSTEM, () -> {
assertShortcutIds(assertAllDynamic(
mManager.getDynamicShortcuts()),
- "s2", "s4");
+ "s2", "s4", "s6", "s8");
assertShortcutIds(assertAllPinned(
mManager.getPinnedShortcuts()),
"s4", "s5");
@@ -1057,10 +1069,10 @@
runWithCaller(CALLING_PACKAGE_1, UserHandle.USER_SYSTEM, () -> {
assertShortcutIds(assertAllDynamic(
mManager.getDynamicShortcuts()),
- "s3", "s4", "s5");
+ "s3", "s4", "s5", "s6", "s7", "s8");
assertShortcutIds(assertAllPinned(
mManager.getPinnedShortcuts()),
- "s2", "s3");
+ "s2", "s3", "s6");
ShortcutInfo s = getCallerShortcut("s2");
assertTrue(s.hasIconResource());
@@ -1076,7 +1088,7 @@
runWithCaller(CALLING_PACKAGE_2, UserHandle.USER_SYSTEM, () -> {
assertShortcutIds(assertAllDynamic(
mManager.getDynamicShortcuts()),
- "s2", "s4");
+ "s2", "s4", "s6", "s8");
assertShortcutIds(assertAllPinned(
mManager.getPinnedShortcuts()),
"s4", "s5");
@@ -1173,7 +1185,46 @@
});
}
- // === Test for launcher side APIs ===
+ public void testUpdateShortcuts_chooser() {
+ runWithCaller(CALLING_PACKAGE_1, UserHandle.USER_SYSTEM, () -> {
+ assertTrue(mManager.setDynamicShortcuts(list(
+ makeShortcut("s1"),
+ makeChooserShortcut("s2", 2, false),
+ makeChooserShortcut("s3", 2, false)
+ )));
+
+ assertFalse(getCallerShortcut("s1").isChooser());
+ assertTrue(getCallerShortcut("s2").isChooser());
+ assertTrue(getCallerShortcut("s3").isChooser());
+
+ ShortcutInfo s = getCallerShortcut("s1");
+ assertNull(s.getChooserIntentFilters());
+ assertNull(s.getChooserComponentNames());
+
+ assertTrue(getCallerShortcut("s1").isDynamic());
+ assertFalse(getCallerShortcut("s2").isDynamic());
+ assertFalse(getCallerShortcut("s3").isDynamic());
+
+
+ // Replace 2 with a chooser shortcut
+ mManager.updateShortcuts(list(makeChooserShortcut("s1", 2, true)));
+
+ s = getCallerShortcut("s1");
+ assertEquals(2, s.getChooserIntentFilters().length);
+ assertEquals(2, s.getChooserComponentNames().length);
+
+ assertShortcutIds(assertAllChooser(
+ mManager.getDynamicShortcuts()),
+ "s1", "s2", "s3");
+
+ assertTrue(getCallerShortcut("s1").isDynamic());
+ assertFalse(getCallerShortcut("s2").isDynamic());
+ assertFalse(getCallerShortcut("s3").isDynamic());
+ });
+ }
+
+
+ // === Test for launcher side APIs ===
public void testGetShortcuts() {
@@ -1484,15 +1535,17 @@
/* icon =*/ null,
makeIntent(Intent.ACTION_ASSIST, ShortcutActivity2.class,
"key1", "val1", "nest", makeBundle("key", 123)),
- /* weight */ 10);
+ /* weight */ 10, /* chooserFilter=*/ null,
+ /* chooserComponentNames=*/ null);
final ShortcutInfo s1_2 = makeShortcut(
- "s2",
- "Title 2",
+ "s2", "Title 2",
/* activity */ null,
/* icon =*/ null,
makeIntent(Intent.ACTION_ASSIST, ShortcutActivity3.class),
- /* weight */ 12);
+ /* weight */ 12,
+ /* chooserFilter=*/ null,
+ /* chooserComponentNames=*/ null);
assertTrue(mManager.setDynamicShortcuts(list(s1_1, s1_2)));
dumpsysOnLogcat();
@@ -1505,7 +1558,9 @@
/* icon =*/ null,
makeIntent(Intent.ACTION_ANSWER, ShortcutActivity2.class,
"key1", "val1", "nest", makeBundle("key", 123)),
- /* weight */ 10);
+ /* weight */ 10,
+ /* chooserFilter=*/ null,
+ /* chooserComponentNames=*/ null);
assertTrue(mManager.setDynamicShortcuts(list(s2_1)));
dumpsysOnLogcat();
@@ -2674,10 +2729,12 @@
final ShortcutInfo s1_2 = makeShortcut(
"s2",
"Title 2",
- /* activity */ null,
- /* icon =*/ null,
+ /* activity */ null,
+ /* icon =*/ null,
makeIntent(Intent.ACTION_ASSIST, ShortcutActivity3.class),
- /* rank */ 12);
+ /* rank */ 12,
+ /* chooserFilter=*/ null,
+ /* chooserComponentNames=*/ null);
final ShortcutInfo s1_3 = makeShortcut("s3");
@@ -2692,7 +2749,9 @@
/* icon =*/ null,
makeIntent(Intent.ACTION_ANSWER, ShortcutActivity.class,
"key1", "val1", "nest", makeBundle("key", 123)),
- /* weight */ 10);
+ /* weight */ 10,
+ /* chooserFilter=*/ null,
+ /* chooserComponentNames=*/ null);
assertTrue(mManager.setDynamicShortcuts(list(s2_1)));
});
@@ -3110,7 +3169,9 @@
icon1,
makeIntent(Intent.ACTION_ASSIST, ShortcutActivity2.class,
"key1", "val1", "nest", makeBundle("key", 123)),
- /* weight */ 10);
+ /* weight */ 10,
+ /* chooserFilter=*/ null,
+ /* chooserComponentNames=*/ null);
final ShortcutInfo si2 = makeShortcut(
"s2",
@@ -3118,7 +3179,9 @@
/* activity */ null,
icon2,
makeIntent(Intent.ACTION_ASSIST, ShortcutActivity3.class),
- /* weight */ 12);
+ /* weight */ 12,
+ /* chooserFilter=*/ null,
+ /* chooserComponentNames=*/ null);
assertTrue(mManager.setDynamicShortcuts(list(si1, si2)));
@@ -3136,8 +3199,8 @@
makeComponent(ShortcutActivity.class),
icon1,
makeIntent(Intent.ACTION_ASSIST, ShortcutActivity2.class,
- "key1", "val1", "nest", makeBundle("key", 123)),
- /* weight */ 10);
+ "key1", "val1", "nest", makeBundle("key", 123)), /* weight */ 10,
+ /* chooserFilter=*/ null, /* chooserComponentNames=*/ null);
final ShortcutInfo si2 = makeShortcut(
"s2",
@@ -3145,7 +3208,8 @@
/* activity */ null,
icon2,
makeIntent(Intent.ACTION_ASSIST, ShortcutActivity3.class),
- /* weight */ 12);
+ /* weight */ 12, /* chooserFilter=*/ null,
+ /* chooserComponentNames=*/ null);
assertTrue(mManager.setDynamicShortcuts(list(si1, si2)));
@@ -3167,7 +3231,8 @@
icon1,
makeIntent(Intent.ACTION_ASSIST, ShortcutActivity2.class,
"key1", "val1", "nest", makeBundle("key", 123)),
- /* weight */ 10);
+ /* weight */ 10, /* chooserFilter=*/ null,
+ /* chooserComponentNames=*/ null);
final ShortcutInfo si2 = makeShortcut(
"s2",
@@ -3175,7 +3240,8 @@
/* activity */ null,
icon2,
makeIntent(Intent.ACTION_ASSIST, ShortcutActivity3.class),
- /* weight */ 12);
+ /* weight */ 12, /* chooserFilter=*/ null,
+ /* chooserComponentNames=*/ null);
assertTrue(mManager.setDynamicShortcuts(list(si1, si2)));
@@ -6800,10 +6866,12 @@
mManager.setDynamicShortcuts(list(
makeShortcut("ms1", "title1",
new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()),
- /* icon */ null, new Intent("action1"), /* rank */ 0),
+ /* icon */ null, new Intent("action1"), /* rank */ 0,
+ /* chooserFilter=*/ null, /* chooserComponentNames=*/ null),
makeShortcut("ms2", "title2",
new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()),
- /* icon */ null, new Intent("action1"), /* rank */ 0)));
+ /* icon */ null, new Intent("action1"), /* rank */ 0, /* chooserFilter=*/ null,
+ /* chooserComponentNames=*/ null)));
});
runWithCaller(LAUNCHER_1, USER_0, () -> {
diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java
index 28ec4fd..c54fa02 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java
@@ -34,6 +34,7 @@
import android.app.ActivityManager;
import android.content.ComponentName;
import android.content.Intent;
+import android.content.IntentFilter;
import android.content.pm.ShortcutInfo;
import android.content.res.Resources;
import android.graphics.BitmapFactory;
@@ -93,11 +94,6 @@
assertExpectException(
RuntimeException.class,
- "intents cannot contain null",
- () -> new ShortcutInfo.Builder(getTestContext(), "id").setIntent(null));
-
- assertExpectException(
- RuntimeException.class,
"action must be set",
() -> new ShortcutInfo.Builder(getTestContext(), "id").setIntent(new Intent()));
@@ -142,6 +138,19 @@
"disabledMessage cannot be empty",
() -> new ShortcutInfo.Builder(getTestContext(), "id").setDisabledMessage(""));
+
+ assertExpectException(
+ RuntimeException.class,
+ "component name cannot be null",
+ () -> new ShortcutInfo.Builder(getTestContext(), "id")
+ .addChooserIntentFilter(new IntentFilter(Intent.ACTION_SEND), null));
+
+ assertExpectException(
+ RuntimeException.class,
+ "intent filter cannot be null",
+ () -> new ShortcutInfo.Builder(getTestContext(), "id")
+ .addChooserIntentFilter(null, new ComponentName("xxx", "s")));
+
assertExpectException(NullPointerException.class, "action must be set",
() -> new ShortcutInfo.Builder(getTestContext(), "id").setIntent(new Intent()));
@@ -240,6 +249,10 @@
PersistableBundle pb = new PersistableBundle();
pb.putInt("k", 1);
+ IntentFilter chooserFilter = new IntentFilter();
+ chooserFilter.addAction(Intent.ACTION_VIEW);
+ PersistableBundle pb2 = new PersistableBundle();
+ pb2.putInt("l", 1);
si = new ShortcutInfo.Builder(getTestContext())
.setId("id")
@@ -252,6 +265,8 @@
.setCategories(set(ShortcutInfo.SHORTCUT_CATEGORY_CONVERSATION, "xyz"))
.setRank(123)
.setExtras(pb)
+ .addChooserIntentFilter(chooserFilter, new ComponentName("a", "b"))
+ .setChooserExtras(pb2)
.build();
si.addFlags(ShortcutInfo.FLAG_PINNED);
si.setBitmapPath("abc");
@@ -282,6 +297,12 @@
assertEquals(null, si.getTextResName());
assertEquals(0, si.getDisabledMessageResourceId());
assertEquals(null, si.getDisabledMessageResName());
+
+ assertEquals(1, si.getChooserIntentFilters().length);
+ assertEquals(Intent.ACTION_VIEW, si.getChooserIntentFilters()[0].getAction(0));
+ assertEquals(1, si.getChooserComponentNames().length);
+ assertEquals(new ComponentName("a", "b"), si.getChooserComponentNames()[0]);
+ assertEquals(1, si.getChooserExtras().getInt("l"));
}
public void testShortcutInfoParcel_resId() {
@@ -290,6 +311,10 @@
PersistableBundle pb = new PersistableBundle();
pb.putInt("k", 1);
+ IntentFilter chooserFilter = new IntentFilter();
+ chooserFilter.addAction(Intent.ACTION_VIEW);
+ PersistableBundle pb2 = new PersistableBundle();
+ pb2.putInt("l", 1);
si = new ShortcutInfo.Builder(getTestContext())
.setId("id")
@@ -302,6 +327,8 @@
.setCategories(set(ShortcutInfo.SHORTCUT_CATEGORY_CONVERSATION, "xyz"))
.setRank(123)
.setExtras(pb)
+ .addChooserIntentFilter(chooserFilter, new ComponentName("a", "b"))
+ .setChooserExtras(pb2)
.build();
si.addFlags(ShortcutInfo.FLAG_PINNED);
si.setBitmapPath("abc");
@@ -338,6 +365,11 @@
PersistableBundle pb = new PersistableBundle();
pb.putInt("k", 1);
+ IntentFilter chooserFilter = new IntentFilter();
+ chooserFilter.addAction(Intent.ACTION_VIEW);
+ PersistableBundle pb2 = new PersistableBundle();
+ pb2.putInt("l", 1);
+
ShortcutInfo sorig = new ShortcutInfo.Builder(mClientContext)
.setId("id")
.setActivity(new ComponentName("a", "b"))
@@ -349,6 +381,8 @@
.setIntent(makeIntent("action", ShortcutActivity.class, "key", "val"))
.setRank(123)
.setExtras(pb)
+ .addChooserIntentFilter(chooserFilter, new ComponentName("a", "b"))
+ .setChooserExtras(pb2)
.build();
sorig.addFlags(ShortcutInfo.FLAG_PINNED);
sorig.setBitmapPath("abc");
@@ -378,6 +412,12 @@
assertEquals(456, si.getIconResourceId());
assertEquals("string/r456", si.getIconResName());
+ assertEquals(1, si.getChooserIntentFilters().length);
+ assertEquals(Intent.ACTION_VIEW, si.getChooserIntentFilters()[0].getAction(0));
+ assertEquals(1, si.getChooserComponentNames().length);
+ assertEquals(new ComponentName("a", "b"), si.getChooserComponentNames()[0]);
+ assertEquals(1, si.getChooserExtras().getInt("l"));
+
si = sorig.clone(ShortcutInfo.CLONE_REMOVE_FOR_CREATOR);
assertEquals(mClientContext.getPackageName(), si.getPackage());
@@ -445,6 +485,10 @@
PersistableBundle pb = new PersistableBundle();
pb.putInt("k", 1);
+ IntentFilter chooserFilter = new IntentFilter();
+ chooserFilter.addAction(Intent.ACTION_VIEW);
+ PersistableBundle pb2 = new PersistableBundle();
+ pb2.putInt("l", 1);
ShortcutInfo sorig = new ShortcutInfo.Builder(mClientContext)
.setId("id")
.setActivity(new ComponentName("a", "b"))
@@ -456,6 +500,8 @@
.setIntent(makeIntent("action", ShortcutActivity.class, "key", "val"))
.setRank(123)
.setExtras(pb)
+ .addChooserIntentFilter(chooserFilter, new ComponentName("a", "b"))
+ .setChooserExtras(pb2)
.build();
sorig.addFlags(ShortcutInfo.FLAG_PINNED);
sorig.setBitmapPath("abc");
@@ -488,6 +534,12 @@
assertEquals(456, si.getIconResourceId());
assertEquals("string/r456", si.getIconResName());
+ assertEquals(1, si.getChooserIntentFilters().length);
+ assertEquals(Intent.ACTION_VIEW, si.getChooserIntentFilters()[0].getAction(0));
+ assertEquals(1, si.getChooserComponentNames().length);
+ assertEquals(new ComponentName("a", "b"), si.getChooserComponentNames()[0]);
+ assertEquals(1, si.getChooserExtras().getInt("l"));
+
si = sorig.clone(ShortcutInfo.CLONE_REMOVE_FOR_CREATOR);
assertEquals(mClientContext.getPackageName(), si.getPackage());
@@ -603,6 +655,10 @@
public void testShortcutInfoCopyNonNullFieldsFrom() throws InterruptedException {
PersistableBundle pb = new PersistableBundle();
pb.putInt("k", 1);
+ IntentFilter chooserFilter = new IntentFilter();
+ chooserFilter.addAction(Intent.ACTION_VIEW);
+ PersistableBundle pb2 = new PersistableBundle();
+ pb2.putInt("l", 1);
ShortcutInfo sorig = new ShortcutInfo.Builder(getTestContext())
.setId("id")
.setActivity(new ComponentName("a", "b"))
@@ -714,12 +770,12 @@
assertEquals(999, si.getRank());
- PersistableBundle pb2 = new PersistableBundle();
- pb2.putInt("x", 99);
+ PersistableBundle pb3 = new PersistableBundle();
+ pb3.putInt("x", 99);
si = sorig.clone(/* flags=*/ 0);
si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getTestContext()).setId("id")
- .setExtras(pb2).build());
+ .setExtras(pb3).build());
assertEquals("text", si.getText());
assertEquals(99, si.getExtras().getInt("x"));
}
diff --git a/services/tests/servicestests/src/com/android/server/usage/AppIdleHistoryTests.java b/services/tests/servicestests/src/com/android/server/usage/AppIdleHistoryTests.java
index 0bd014c..42ddedf 100644
--- a/services/tests/servicestests/src/com/android/server/usage/AppIdleHistoryTests.java
+++ b/services/tests/servicestests/src/com/android/server/usage/AppIdleHistoryTests.java
@@ -45,12 +45,12 @@
final int userId = 0;
AppIdleHistory aih = new AppIdleHistory(mStorageDir, 0);
- aih.updateDisplayLocked(true, /* elapsedRealtime= */ 1000);
- aih.updateDisplayLocked(false, /* elapsedRealtime= */ 2000);
+ aih.updateDisplay(true, /* elapsedRealtime= */ 1000);
+ aih.updateDisplay(false, /* elapsedRealtime= */ 2000);
// Screen On time file should be written right away
assertTrue(aih.getScreenOnTimeFile().exists());
- aih.writeAppIdleTimesLocked(userId);
+ aih.writeAppIdleTimes(userId);
// stats file should be written now
assertTrue(new File(new File(mStorageDir, "users/" + userId),
AppIdleHistory.APP_IDLE_FILENAME).exists());
@@ -58,43 +58,43 @@
public void testScreenOnTime() {
AppIdleHistory aih = new AppIdleHistory(mStorageDir, 1000);
- aih.updateDisplayLocked(false, 2000);
- assertEquals(aih.getScreenOnTimeLocked(2000), 0);
- aih.updateDisplayLocked(true, 3000);
- assertEquals(aih.getScreenOnTimeLocked(4000), 1000);
- assertEquals(aih.getScreenOnTimeLocked(5000), 2000);
- aih.updateDisplayLocked(false, 6000);
+ aih.updateDisplay(false, 2000);
+ assertEquals(aih.getScreenOnTime(2000), 0);
+ aih.updateDisplay(true, 3000);
+ assertEquals(aih.getScreenOnTime(4000), 1000);
+ assertEquals(aih.getScreenOnTime(5000), 2000);
+ aih.updateDisplay(false, 6000);
// Screen on time should not keep progressing with screen is off
- assertEquals(aih.getScreenOnTimeLocked(7000), 3000);
- assertEquals(aih.getScreenOnTimeLocked(8000), 3000);
- aih.writeAppIdleDurationsLocked();
+ assertEquals(aih.getScreenOnTime(7000), 3000);
+ assertEquals(aih.getScreenOnTime(8000), 3000);
+ aih.writeAppIdleDurations();
// Check if the screen on time is persisted across instantiations
AppIdleHistory aih2 = new AppIdleHistory(mStorageDir, 0);
- assertEquals(aih2.getScreenOnTimeLocked(11000), 3000);
- aih2.updateDisplayLocked(true, 4000);
- aih2.updateDisplayLocked(false, 5000);
- assertEquals(aih2.getScreenOnTimeLocked(13000), 4000);
+ assertEquals(aih2.getScreenOnTime(11000), 3000);
+ aih2.updateDisplay(true, 4000);
+ aih2.updateDisplay(false, 5000);
+ assertEquals(aih2.getScreenOnTime(13000), 4000);
}
public void testPackageEvents() {
AppIdleHistory aih = new AppIdleHistory(mStorageDir, 1000);
aih.setThresholds(4000, 1000);
- aih.updateDisplayLocked(true, 1000);
+ aih.updateDisplay(true, 1000);
// App is not-idle by default
- assertFalse(aih.isIdleLocked(PACKAGE_1, 0, 1500));
+ assertFalse(aih.isIdle(PACKAGE_1, 0, 1500));
// Still not idle
- assertFalse(aih.isIdleLocked(PACKAGE_1, 0, 3000));
+ assertFalse(aih.isIdle(PACKAGE_1, 0, 3000));
// Idle now
- assertTrue(aih.isIdleLocked(PACKAGE_1, 0, 8000));
+ assertTrue(aih.isIdle(PACKAGE_1, 0, 8000));
// Not idle
- assertFalse(aih.isIdleLocked(PACKAGE_2, 0, 9000));
+ assertFalse(aih.isIdle(PACKAGE_2, 0, 9000));
// Screen off
- aih.updateDisplayLocked(false, 9100);
+ aih.updateDisplay(false, 9100);
// Still idle after 10 seconds because screen hasn't been on long enough
- assertFalse(aih.isIdleLocked(PACKAGE_2, 0, 20000));
- aih.updateDisplayLocked(true, 21000);
- assertTrue(aih.isIdleLocked(PACKAGE_2, 0, 23000));
+ assertFalse(aih.isIdle(PACKAGE_2, 0, 20000));
+ aih.updateDisplay(true, 21000);
+ assertTrue(aih.isIdle(PACKAGE_2, 0, 23000));
}
}
\ No newline at end of file
diff --git a/services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java b/services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java
index bd3271b..73ad7c2 100644
--- a/services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java
@@ -22,6 +22,7 @@
import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
import static android.view.WindowManager.LayoutParams.TYPE_VOICE_INTERACTION;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertTrue;
import org.junit.Test;
@@ -146,6 +147,7 @@
final WindowState appWin = createWindow(null, TYPE_APPLICATION, sDisplayContent, "appWin");
appWin.setHasSurface(true);
assertTrue(appWin.canBeImeTarget());
+ sWm.mInputMethodTargetCandidate = appWin.mClient.asBinder();
WindowState imeTarget = sDisplayContent.computeImeTarget(false /* updateImeTarget */);
assertEquals(appWin, imeTarget);
@@ -156,6 +158,20 @@
assertTrue(childWin.canBeImeTarget());
imeTarget = sDisplayContent.computeImeTarget(false /* updateImeTarget */);
assertEquals(childWin, imeTarget);
+
+ final WindowState appWin2 =
+ createWindow(null, TYPE_APPLICATION, sDisplayContent, "appWin2");
+ appWin2.setHasSurface(true);
+ assertTrue(appWin2.canBeImeTarget());
+ // Verify that the IME target isn't adjusted since mInputMethodTargetCandidate didn't change
+ // to the new app.
+ imeTarget = sDisplayContent.computeImeTarget(false /* updateImeTarget */);
+ assertNotEquals(appWin2, imeTarget);
+
+ sWm.mInputMethodTargetCandidate = appWin2.mClient.asBinder();
+ // Verify app is not IME target since its token is set as a candidate.
+ imeTarget = sDisplayContent.computeImeTarget(false /* updateImeTarget */);
+ assertEquals(appWin2, imeTarget);
}
/**
diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java b/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java
index 52e10a5..8392665 100644
--- a/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java
+++ b/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java
@@ -69,7 +69,6 @@
class WindowTestsBase {
static WindowManagerService sWm = null;
static TestWindowManagerPolicy sPolicy = null;
- private final static IWindow sIWindow = new TestIWindow();
private final static Session sMockSession = mock(Session.class);
private static int sNextDisplayId = Display.DEFAULT_DISPLAY + 1;
static int sNextStackId = FIRST_DYNAMIC_STACK_ID;
@@ -148,6 +147,7 @@
}
sWm.mInputMethodTarget = null;
+ sWm.mInputMethodTargetCandidate = null;
}
private static WindowState createCommonWindow(WindowState parent, int type, String name) {
@@ -237,11 +237,12 @@
final WindowManager.LayoutParams attrs = new WindowManager.LayoutParams(type);
attrs.setTitle(name);
- final WindowState w = new WindowState(sWm, sMockSession, sIWindow, token, parent, OP_NONE,
- 0, attrs, 0, 0, ownerCanAddInternalSystemWindow);
+ final WindowState w = new WindowState(sWm, sMockSession, new TestIWindow(), token, parent,
+ OP_NONE, 0, attrs, 0, 0, ownerCanAddInternalSystemWindow);
// TODO: Probably better to make this call in the WindowState ctor to avoid errors with
// adding it to the token...
token.addWindow(w);
+ sWm.mWindowMap.put(w.mClient.asBinder(), w);
return w;
}
@@ -279,6 +280,7 @@
/* Used so we can gain access to some protected members of the {@link WindowToken} class */
static class TestWindowToken extends WindowToken {
+ int adj = 0;
TestWindowToken(int type, DisplayContent dc) {
this(type, dc, false /* persistOnEmpty */);
@@ -296,6 +298,11 @@
boolean hasWindow(WindowState w) {
return mChildren.contains(w);
}
+
+ @Override
+ int getAnimLayerAdjustment() {
+ return adj;
+ }
}
/** Used so we can gain access to some protected members of the {@link AppWindowToken} class. */
@@ -463,8 +470,9 @@
boolean resizeReported;
TestWindowState(WindowManager.LayoutParams attrs, WindowToken token) {
- super(sWm, sMockSession, sIWindow, token, null, OP_NONE, 0, attrs, 0, 0,
+ super(sWm, sMockSession, new TestIWindow(), token, null, OP_NONE, 0, attrs, 0, 0,
false /* ownerCanAddInternalSystemWindow */);
+ sWm.mWindowMap.put(mClient.asBinder(), this);
}
@Override
diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowTokenTests.java b/services/tests/servicestests/src/com/android/server/wm/WindowTokenTests.java
index 0c053b9..babb6d9 100644
--- a/services/tests/servicestests/src/com/android/server/wm/WindowTokenTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/WindowTokenTests.java
@@ -102,14 +102,28 @@
final WindowState window2 = createWindow(null, TYPE_APPLICATION, token, "window2");
final WindowState window3 = createWindow(null, TYPE_APPLICATION, token, "window3");
- final int adj = 50;
- final int window2StartLayer = window2.mLayer = 100;
- final int window3StartLayer = window3.mLayer = 200;
- final int highestLayer = token.adjustAnimLayer(adj);
+ window2.mLayer = 100;
+ window3.mLayer = 200;
- assertEquals(adj, window1.mWinAnimator.mAnimLayer);
- assertEquals(adj, window11.mWinAnimator.mAnimLayer);
- assertEquals(adj, window12.mWinAnimator.mAnimLayer);
+ // We assign layers once, to get the base values computed by
+ // the controller.
+ sLayersController.assignWindowLayers(sDisplayContent);
+
+ final int window1StartLayer = window1.mWinAnimator.mAnimLayer;
+ final int window11StartLayer = window11.mWinAnimator.mAnimLayer;
+ final int window12StartLayer = window12.mWinAnimator.mAnimLayer;
+ final int window2StartLayer = window2.mWinAnimator.mAnimLayer;
+ final int window3StartLayer = window3.mWinAnimator.mAnimLayer;
+
+ // Then we set an adjustment, and assign them again, they should
+ // be offset.
+ int adj = token.adj = 50;
+ sLayersController.assignWindowLayers(sDisplayContent);
+ final int highestLayer = token.getHighestAnimLayer();
+
+ assertEquals(window1StartLayer + adj, window1.mWinAnimator.mAnimLayer);
+ assertEquals(window11StartLayer + adj, window11.mWinAnimator.mAnimLayer);
+ assertEquals(window12StartLayer + adj, window12.mWinAnimator.mAnimLayer);
assertEquals(window2StartLayer + adj, window2.mWinAnimator.mAnimLayer);
assertEquals(window3StartLayer + adj, window3.mWinAnimator.mAnimLayer);
assertEquals(window3StartLayer + adj, highestLayer);
diff --git a/services/tests/shortcutmanagerutils/src/com/android/server/pm/shortcutmanagertest/ShortcutManagerTestUtils.java b/services/tests/shortcutmanagerutils/src/com/android/server/pm/shortcutmanagertest/ShortcutManagerTestUtils.java
index ea45bd1..fd335c3 100644
--- a/services/tests/shortcutmanagerutils/src/com/android/server/pm/shortcutmanagertest/ShortcutManagerTestUtils.java
+++ b/services/tests/shortcutmanagerutils/src/com/android/server/pm/shortcutmanagertest/ShortcutManagerTestUtils.java
@@ -508,6 +508,13 @@
return actualShortcuts;
}
+ public static List<ShortcutInfo> assertAllChooser(List<ShortcutInfo> actualShortcuts) {
+ for (ShortcutInfo s : actualShortcuts) {
+ assertTrue("ID " + s.getId(), s.isChooser());
+ }
+ return actualShortcuts;
+ }
+
public static List<ShortcutInfo> assertAllPinned(List<ShortcutInfo> actualShortcuts) {
for (ShortcutInfo s : actualShortcuts) {
assertTrue("ID " + s.getId(), s.isPinned());
diff --git a/services/usage/java/com/android/server/usage/AppIdleHistory.java b/services/usage/java/com/android/server/usage/AppIdleHistory.java
index f69dae4..f298559 100644
--- a/services/usage/java/com/android/server/usage/AppIdleHistory.java
+++ b/services/usage/java/com/android/server/usage/AppIdleHistory.java
@@ -18,7 +18,6 @@
import android.os.Environment;
import android.os.SystemClock;
-import android.os.UserHandle;
import android.util.ArrayMap;
import android.util.AtomicFile;
import android.util.Slog;
@@ -101,7 +100,7 @@
mElapsedSnapshot = elapsedRealtime;
mScreenOnSnapshot = elapsedRealtime;
mStorageDir = storageDir;
- readScreenOnTimeLocked();
+ readScreenOnTime();
}
public void setThresholds(long elapsedTimeThreshold, long screenOnTimeThreshold) {
@@ -109,7 +108,7 @@
mScreenOnTimeThreshold = screenOnTimeThreshold;
}
- public void updateDisplayLocked(boolean screenOn, long elapsedRealtime) {
+ public void updateDisplay(boolean screenOn, long elapsedRealtime) {
if (screenOn == mScreenOn) return;
mScreenOn = screenOn;
@@ -122,7 +121,7 @@
}
}
- public long getScreenOnTimeLocked(long elapsedRealtime) {
+ public long getScreenOnTime(long elapsedRealtime) {
long screenOnTime = mScreenOnDuration;
if (mScreenOn) {
screenOnTime += elapsedRealtime - mScreenOnSnapshot;
@@ -135,7 +134,7 @@
return new File(mStorageDir, "screen_on_time");
}
- private void readScreenOnTimeLocked() {
+ private void readScreenOnTime() {
File screenOnTimeFile = getScreenOnTimeFile();
if (screenOnTimeFile.exists()) {
try {
@@ -146,11 +145,11 @@
} catch (IOException | NumberFormatException e) {
}
} else {
- writeScreenOnTimeLocked();
+ writeScreenOnTime();
}
}
- private void writeScreenOnTimeLocked() {
+ private void writeScreenOnTime() {
AtomicFile screenOnTimeFile = new AtomicFile(getScreenOnTimeFile());
FileOutputStream fos = null;
try {
@@ -166,30 +165,30 @@
/**
* To be called periodically to keep track of elapsed time when app idle times are written
*/
- public void writeAppIdleDurationsLocked() {
+ public void writeAppIdleDurations() {
final long elapsedRealtime = SystemClock.elapsedRealtime();
// Only bump up and snapshot the elapsed time. Don't change screen on duration.
mElapsedDuration += elapsedRealtime - mElapsedSnapshot;
mElapsedSnapshot = elapsedRealtime;
- writeScreenOnTimeLocked();
+ writeScreenOnTime();
}
- public void reportUsageLocked(String packageName, int userId, long elapsedRealtime) {
- ArrayMap<String, PackageHistory> userHistory = getUserHistoryLocked(userId);
- PackageHistory packageHistory = getPackageHistoryLocked(userHistory, packageName,
+ public void reportUsage(String packageName, int userId, long elapsedRealtime) {
+ ArrayMap<String, PackageHistory> userHistory = getUserHistory(userId);
+ PackageHistory packageHistory = getPackageHistory(userHistory, packageName,
elapsedRealtime);
shiftHistoryToNow(userHistory, elapsedRealtime);
packageHistory.lastUsedElapsedTime = mElapsedDuration
+ (elapsedRealtime - mElapsedSnapshot);
- packageHistory.lastUsedScreenTime = getScreenOnTimeLocked(elapsedRealtime);
+ packageHistory.lastUsedScreenTime = getScreenOnTime(elapsedRealtime);
packageHistory.recent[HISTORY_SIZE - 1] = FLAG_LAST_STATE | FLAG_PARTIAL_ACTIVE;
}
public void setIdle(String packageName, int userId, long elapsedRealtime) {
- ArrayMap<String, PackageHistory> userHistory = getUserHistoryLocked(userId);
- PackageHistory packageHistory = getPackageHistoryLocked(userHistory, packageName,
+ ArrayMap<String, PackageHistory> userHistory = getUserHistory(userId);
+ PackageHistory packageHistory = getPackageHistory(userHistory, packageName,
elapsedRealtime);
shiftHistoryToNow(userHistory, elapsedRealtime);
@@ -222,23 +221,23 @@
mLastPeriod = thisPeriod;
}
- private ArrayMap<String, PackageHistory> getUserHistoryLocked(int userId) {
+ private ArrayMap<String, PackageHistory> getUserHistory(int userId) {
ArrayMap<String, PackageHistory> userHistory = mIdleHistory.get(userId);
if (userHistory == null) {
userHistory = new ArrayMap<>();
mIdleHistory.put(userId, userHistory);
- readAppIdleTimesLocked(userId, userHistory);
+ readAppIdleTimes(userId, userHistory);
}
return userHistory;
}
- private PackageHistory getPackageHistoryLocked(ArrayMap<String, PackageHistory> userHistory,
+ private PackageHistory getPackageHistory(ArrayMap<String, PackageHistory> userHistory,
String packageName, long elapsedRealtime) {
PackageHistory packageHistory = userHistory.get(packageName);
if (packageHistory == null) {
packageHistory = new PackageHistory();
- packageHistory.lastUsedElapsedTime = getElapsedTimeLocked(elapsedRealtime);
- packageHistory.lastUsedScreenTime = getScreenOnTimeLocked(elapsedRealtime);
+ packageHistory.lastUsedElapsedTime = getElapsedTime(elapsedRealtime);
+ packageHistory.lastUsedScreenTime = getScreenOnTime(elapsedRealtime);
userHistory.put(packageName, packageHistory);
}
return packageHistory;
@@ -248,41 +247,41 @@
mIdleHistory.remove(userId);
}
- public boolean isIdleLocked(String packageName, int userId, long elapsedRealtime) {
- ArrayMap<String, PackageHistory> userHistory = getUserHistoryLocked(userId);
+ public boolean isIdle(String packageName, int userId, long elapsedRealtime) {
+ ArrayMap<String, PackageHistory> userHistory = getUserHistory(userId);
PackageHistory packageHistory =
- getPackageHistoryLocked(userHistory, packageName, elapsedRealtime);
+ getPackageHistory(userHistory, packageName, elapsedRealtime);
if (packageHistory == null) {
return false; // Default to not idle
} else {
- return hasPassedThresholdsLocked(packageHistory, elapsedRealtime);
+ return hasPassedThresholds(packageHistory, elapsedRealtime);
}
}
- private long getElapsedTimeLocked(long elapsedRealtime) {
+ private long getElapsedTime(long elapsedRealtime) {
return (elapsedRealtime - mElapsedSnapshot + mElapsedDuration);
}
- public void setIdleLocked(String packageName, int userId, boolean idle, long elapsedRealtime) {
- ArrayMap<String, PackageHistory> userHistory = getUserHistoryLocked(userId);
- PackageHistory packageHistory = getPackageHistoryLocked(userHistory, packageName,
+ public void setIdle(String packageName, int userId, boolean idle, long elapsedRealtime) {
+ ArrayMap<String, PackageHistory> userHistory = getUserHistory(userId);
+ PackageHistory packageHistory = getPackageHistory(userHistory, packageName,
elapsedRealtime);
- packageHistory.lastUsedElapsedTime = getElapsedTimeLocked(elapsedRealtime)
+ packageHistory.lastUsedElapsedTime = getElapsedTime(elapsedRealtime)
- mElapsedTimeThreshold;
- packageHistory.lastUsedScreenTime = getScreenOnTimeLocked(elapsedRealtime)
+ packageHistory.lastUsedScreenTime = getScreenOnTime(elapsedRealtime)
- (idle ? mScreenOnTimeThreshold : 0) - 1000 /* just a second more */;
}
- public void clearUsageLocked(String packageName, int userId) {
- ArrayMap<String, PackageHistory> userHistory = getUserHistoryLocked(userId);
+ public void clearUsage(String packageName, int userId) {
+ ArrayMap<String, PackageHistory> userHistory = getUserHistory(userId);
userHistory.remove(packageName);
}
- private boolean hasPassedThresholdsLocked(PackageHistory packageHistory, long elapsedRealtime) {
+ private boolean hasPassedThresholds(PackageHistory packageHistory, long elapsedRealtime) {
return (packageHistory.lastUsedScreenTime
- <= getScreenOnTimeLocked(elapsedRealtime) - mScreenOnTimeThreshold)
+ <= getScreenOnTime(elapsedRealtime) - mScreenOnTimeThreshold)
&& (packageHistory.lastUsedElapsedTime
- <= getElapsedTimeLocked(elapsedRealtime) - mElapsedTimeThreshold);
+ <= getElapsedTime(elapsedRealtime) - mElapsedTimeThreshold);
}
private File getUserFile(int userId) {
@@ -290,7 +289,7 @@
Integer.toString(userId)), APP_IDLE_FILENAME);
}
- private void readAppIdleTimesLocked(int userId, ArrayMap<String, PackageHistory> userHistory) {
+ private void readAppIdleTimes(int userId, ArrayMap<String, PackageHistory> userHistory) {
FileInputStream fis = null;
try {
AtomicFile appIdleFile = new AtomicFile(getUserFile(userId));
@@ -332,7 +331,7 @@
}
}
- public void writeAppIdleTimesLocked(int userId) {
+ public void writeAppIdleTimes(int userId) {
FileOutputStream fos = null;
AtomicFile appIdleFile = new AtomicFile(getUserFile(userId));
try {
@@ -346,7 +345,7 @@
xml.startTag(null, TAG_PACKAGES);
- ArrayMap<String,PackageHistory> userHistory = getUserHistoryLocked(userId);
+ ArrayMap<String,PackageHistory> userHistory = getUserHistory(userId);
final int N = userHistory.size();
for (int i = 0; i < N; i++) {
String packageName = userHistory.keyAt(i);
@@ -374,8 +373,8 @@
idpw.increaseIndent();
ArrayMap<String, PackageHistory> userHistory = mIdleHistory.get(userId);
final long elapsedRealtime = SystemClock.elapsedRealtime();
- final long totalElapsedTime = getElapsedTimeLocked(elapsedRealtime);
- final long screenOnTime = getScreenOnTimeLocked(elapsedRealtime);
+ final long totalElapsedTime = getElapsedTime(elapsedRealtime);
+ final long screenOnTime = getScreenOnTime(elapsedRealtime);
if (userHistory == null) return;
final int P = userHistory.size();
for (int p = 0; p < P; p++) {
@@ -386,15 +385,15 @@
TimeUtils.formatDuration(totalElapsedTime - packageHistory.lastUsedElapsedTime, idpw);
idpw.print(" lastUsedScreenOn=");
TimeUtils.formatDuration(screenOnTime - packageHistory.lastUsedScreenTime, idpw);
- idpw.print(" idle=" + (isIdleLocked(packageName, userId, elapsedRealtime) ? "y" : "n"));
+ idpw.print(" idle=" + (isIdle(packageName, userId, elapsedRealtime) ? "y" : "n"));
idpw.println();
}
idpw.println();
idpw.print("totalElapsedTime=");
- TimeUtils.formatDuration(getElapsedTimeLocked(elapsedRealtime), idpw);
+ TimeUtils.formatDuration(getElapsedTime(elapsedRealtime), idpw);
idpw.println();
idpw.print("totalScreenOnTime=");
- TimeUtils.formatDuration(getScreenOnTimeLocked(elapsedRealtime), idpw);
+ TimeUtils.formatDuration(getScreenOnTime(elapsedRealtime), idpw);
idpw.println();
idpw.decreaseIndent();
}
@@ -410,7 +409,7 @@
for (int i = 0; i < HISTORY_SIZE; i++) {
idpw.print(history[i] == 0 ? '.' : 'A');
}
- idpw.print(" idle=" + (isIdleLocked(packageName, userId, elapsedRealtime) ? "y" : "n"));
+ idpw.print(" idle=" + (isIdle(packageName, userId, elapsedRealtime) ? "y" : "n"));
idpw.print(" " + packageName);
idpw.println();
}
diff --git a/services/usage/java/com/android/server/usage/StorageStatsService.java b/services/usage/java/com/android/server/usage/StorageStatsService.java
index 632c045..ed1530a 100644
--- a/services/usage/java/com/android/server/usage/StorageStatsService.java
+++ b/services/usage/java/com/android/server/usage/StorageStatsService.java
@@ -30,6 +30,7 @@
import android.content.pm.UserInfo;
import android.os.Binder;
import android.os.Environment;
+import android.os.FileUtils;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
@@ -148,11 +149,10 @@
enforcePermission(Binder.getCallingUid(), callingPackage);
if (volumeUuid == StorageManager.UUID_PRIVATE_INTERNAL) {
- // TODO: round total size to nearest power of two
- return mStorage.getPrimaryStorageSize();
+ return FileUtils.roundStorageSize(mStorage.getPrimaryStorageSize());
} else {
final VolumeInfo vol = mStorage.findVolumeByUuid(volumeUuid);
- return vol.disk.size;
+ return FileUtils.roundStorageSize(vol.disk.size);
}
}
@@ -175,6 +175,43 @@
}
@Override
+ public StorageStats queryStatsForPackage(String volumeUuid, String packageName, int userId,
+ String callingPackage) {
+ enforcePermission(Binder.getCallingUid(), callingPackage);
+ if (userId != UserHandle.getCallingUserId()) {
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.INTERACT_ACROSS_USERS, TAG);
+ }
+
+ final ApplicationInfo appInfo;
+ try {
+ appInfo = mPackage.getApplicationInfoAsUser(packageName, 0, userId);
+ } catch (NameNotFoundException e) {
+ throw new IllegalStateException(e);
+ }
+
+ if (mPackage.getPackagesForUid(appInfo.uid).length == 1) {
+ // Only one package inside UID means we can fast-path
+ return queryStatsForUid(volumeUuid, appInfo.uid, callingPackage);
+ } else {
+ // Multiple packages means we need to go manual
+ final int appId = UserHandle.getUserId(appInfo.uid);
+ final String[] packageNames = new String[] { packageName };
+ final long[] ceDataInodes = new long[1];
+ final String[] codePaths = new String[] { appInfo.getCodePath() };
+
+ final PackageStats stats = new PackageStats(TAG);
+ try {
+ mInstaller.getAppSize(volumeUuid, packageNames, userId, 0,
+ appId, ceDataInodes, codePaths, stats);
+ } catch (InstallerException e) {
+ throw new IllegalStateException(e);
+ }
+ return translate(stats);
+ }
+ }
+
+ @Override
public StorageStats queryStatsForUid(String volumeUuid, int uid, String callingPackage) {
enforcePermission(Binder.getCallingUid(), callingPackage);
if (UserHandle.getUserId(uid) != UserHandle.getCallingUserId()) {
diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java
index 3c743b5..469a8f1 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsService.java
@@ -153,13 +153,17 @@
private volatile boolean mPendingOneTimeCheckIdleStates;
private boolean mSystemServicesReady = false;
- @GuardedBy("mLock")
+ private final Object mAppIdleLock = new Object();
+ @GuardedBy("mAppIdleLock")
private AppIdleHistory mAppIdleHistory;
+ @GuardedBy("mAppIdleLock")
private ArrayList<UsageStatsManagerInternal.AppIdleStateChangeListener>
mPackageAccessListeners = new ArrayList<>();
+ @GuardedBy("mAppIdleLock")
private boolean mHaveCarrierPrivilegedApps;
+ @GuardedBy("mAppIdleLock")
private List<String> mCarrierPrivilegedApps;
public UsageStatsService(Context context) {
@@ -206,6 +210,8 @@
synchronized (mLock) {
cleanUpRemovedUsersLocked();
+ }
+ synchronized (mAppIdleLock) {
mAppIdleHistory = new AppIdleHistory(SystemClock.elapsedRealtime());
}
@@ -234,8 +240,8 @@
mPowerManager = getContext().getSystemService(PowerManager.class);
mDisplayManager.registerDisplayListener(mDisplayListener, mHandler);
- synchronized (mLock) {
- mAppIdleHistory.updateDisplayLocked(isDisplayOn(), SystemClock.elapsedRealtime());
+ synchronized (mAppIdleLock) {
+ mAppIdleHistory.updateDisplay(isDisplayOn(), SystemClock.elapsedRealtime());
}
if (mPendingOneTimeCheckIdleStates) {
@@ -324,8 +330,8 @@
@Override public void onDisplayChanged(int displayId) {
if (displayId == Display.DEFAULT_DISPLAY) {
final boolean displayOn = isDisplayOn();
- synchronized (UsageStatsService.this.mLock) {
- mAppIdleHistory.updateDisplayLocked(displayOn, SystemClock.elapsedRealtime());
+ synchronized (UsageStatsService.this.mAppIdleLock) {
+ mAppIdleHistory.updateDisplay(displayOn, SystemClock.elapsedRealtime());
}
}
}
@@ -386,18 +392,20 @@
PackageManager.MATCH_DISABLED_COMPONENTS,
userId);
final int packageCount = packages.size();
- for (int i = 0; i < packageCount; i++) {
- final PackageInfo pi = packages.get(i);
- String packageName = pi.packageName;
- if (pi.applicationInfo != null && pi.applicationInfo.isSystemApp()) {
- mAppIdleHistory.reportUsageLocked(packageName, userId, elapsedRealtime);
+ synchronized (mAppIdleLock) {
+ for (int i = 0; i < packageCount; i++) {
+ final PackageInfo pi = packages.get(i);
+ String packageName = pi.packageName;
+ if (pi.applicationInfo != null && pi.applicationInfo.isSystemApp()) {
+ mAppIdleHistory.reportUsage(packageName, userId, elapsedRealtime);
+ }
}
}
}
void clearAppIdleForPackage(String packageName, int userId) {
- synchronized (mLock) {
- mAppIdleHistory.clearUsageLocked(packageName, userId);
+ synchronized (mAppIdleLock) {
+ mAppIdleHistory.clearUsage(packageName, userId);
}
}
@@ -429,7 +437,7 @@
}
void setChargingState(boolean charging) {
- synchronized (mLock) {
+ synchronized (mAppIdleLock) {
if (mCharging != charging) {
mCharging = charging;
postParoleStateChanged();
@@ -439,15 +447,16 @@
/** Paroled here means temporary pardon from being inactive */
void setAppIdleParoled(boolean paroled) {
- synchronized (mLock) {
+ synchronized (mAppIdleLock) {
+ final long now = System.currentTimeMillis();
if (mAppIdleTempParoled != paroled) {
mAppIdleTempParoled = paroled;
if (DEBUG) Slog.d(TAG, "Changing paroled to " + mAppIdleTempParoled);
if (paroled) {
postParoleEndTimeout();
} else {
- mLastAppIdleParoledTime = checkAndGetTimeLocked();
- postNextParoleTimeout();
+ mLastAppIdleParoledTime = now;
+ postNextParoleTimeout(now);
}
postParoleStateChanged();
}
@@ -455,19 +464,18 @@
}
boolean isParoledOrCharging() {
- synchronized (mLock) {
+ synchronized (mAppIdleLock) {
return mAppIdleTempParoled || mCharging;
}
}
- private void postNextParoleTimeout() {
+ private void postNextParoleTimeout(long now) {
if (DEBUG) Slog.d(TAG, "Posting MSG_CHECK_PAROLE_TIMEOUT");
mHandler.removeMessages(MSG_CHECK_PAROLE_TIMEOUT);
// Compute when the next parole needs to happen. We check more frequently than necessary
// since the message handler delays are based on elapsedRealTime and not wallclock time.
// The comparison is done in wallclock time.
- long timeLeft = (mLastAppIdleParoledTime + mAppIdleParoleIntervalMillis)
- - checkAndGetTimeLocked();
+ long timeLeft = (mLastAppIdleParoledTime + mAppIdleParoleIntervalMillis) - now;
if (timeLeft < 0) {
timeLeft = 0;
}
@@ -546,7 +554,7 @@
mHandler.sendMessage(mHandler.obtainMessage(MSG_INFORM_LISTENERS,
userId, isIdle ? 1 : 0, packageName));
if (isIdle) {
- synchronized (mLock) {
+ synchronized (mAppIdleLock) {
mAppIdleHistory.setIdle(packageName, userId, elapsedRealtime);
}
}
@@ -561,18 +569,23 @@
/** Check if it's been a while since last parole and let idle apps do some work */
void checkParoleTimeout() {
- synchronized (mLock) {
+ boolean setParoled = false;
+ synchronized (mAppIdleLock) {
+ final long now = System.currentTimeMillis();
if (!mAppIdleTempParoled) {
- final long timeSinceLastParole = checkAndGetTimeLocked() - mLastAppIdleParoledTime;
+ final long timeSinceLastParole = now - mLastAppIdleParoledTime;
if (timeSinceLastParole > mAppIdleParoleIntervalMillis) {
if (DEBUG) Slog.d(TAG, "Crossed default parole interval");
- setAppIdleParoled(true);
+ setParoled = true;
} else {
if (DEBUG) Slog.d(TAG, "Not long enough to go to parole");
- postNextParoleTimeout();
+ postNextParoleTimeout(now);
}
}
}
+ if (setParoled) {
+ setAppIdleParoled(true);
+ }
}
private void notifyBatteryStats(String packageName, int userId, boolean idle) {
@@ -593,17 +606,23 @@
void onDeviceIdleModeChanged() {
final boolean deviceIdle = mPowerManager.isDeviceIdleMode();
if (DEBUG) Slog.i(TAG, "DeviceIdleMode changed to " + deviceIdle);
- synchronized (mLock) {
- final long timeSinceLastParole = checkAndGetTimeLocked() - mLastAppIdleParoledTime;
+ boolean paroled = false;
+ synchronized (mAppIdleLock) {
+ final long timeSinceLastParole = System.currentTimeMillis() - mLastAppIdleParoledTime;
if (!deviceIdle
&& timeSinceLastParole >= mAppIdleParoleIntervalMillis) {
- if (DEBUG) Slog.i(TAG, "Bringing idle apps out of inactive state due to deviceIdleMode=false");
- setAppIdleParoled(true);
+ if (DEBUG) {
+ Slog.i(TAG, "Bringing idle apps out of inactive state due to deviceIdleMode=false");
+ }
+ paroled = true;
} else if (deviceIdle) {
if (DEBUG) Slog.i(TAG, "Device idle, back to prison");
- setAppIdleParoled(false);
+ paroled = false;
+ } else {
+ return;
}
}
+ setAppIdleParoled(paroled);
}
private static void deleteRecursively(File f) {
@@ -682,21 +701,24 @@
final UserUsageStatsService service =
getUserDataAndInitializeIfNeededLocked(userId, timeNow);
- // TODO: Ideally this should call isAppIdleFiltered() to avoid calling back
- // about apps that are on some kind of whitelist anyway.
- final boolean previouslyIdle = mAppIdleHistory.isIdleLocked(
- event.mPackage, userId, elapsedRealtime);
service.reportEvent(event);
- // Inform listeners if necessary
- if ((event.mEventType == Event.MOVE_TO_FOREGROUND
- || event.mEventType == Event.MOVE_TO_BACKGROUND
- || event.mEventType == Event.SYSTEM_INTERACTION
- || event.mEventType == Event.USER_INTERACTION)) {
- mAppIdleHistory.reportUsageLocked(event.mPackage, userId, elapsedRealtime);
- if (previouslyIdle) {
- mHandler.sendMessage(mHandler.obtainMessage(MSG_INFORM_LISTENERS, userId,
- /* idle = */ 0, event.mPackage));
- notifyBatteryStats(event.mPackage, userId, false);
+
+ synchronized (mAppIdleLock) {
+ // TODO: Ideally this should call isAppIdleFiltered() to avoid calling back
+ // about apps that are on some kind of whitelist anyway.
+ final boolean previouslyIdle = mAppIdleHistory.isIdle(
+ event.mPackage, userId, elapsedRealtime);
+ // Inform listeners if necessary
+ if ((event.mEventType == Event.MOVE_TO_FOREGROUND
+ || event.mEventType == Event.MOVE_TO_BACKGROUND
+ || event.mEventType == Event.SYSTEM_INTERACTION
+ || event.mEventType == Event.USER_INTERACTION)) {
+ mAppIdleHistory.reportUsage(event.mPackage, userId, elapsedRealtime);
+ if (previouslyIdle) {
+ mHandler.sendMessage(mHandler.obtainMessage(MSG_INFORM_LISTENERS, userId,
+ /* idle = */ 0, event.mPackage));
+ notifyBatteryStats(event.mPackage, userId, false);
+ }
}
}
}
@@ -716,7 +738,7 @@
continue;
}
if (!packageName.equals(providerPkgName)) {
- forceIdleState(packageName, userId, false);
+ setAppIdleAsync(packageName, false, userId);
}
} catch (NameNotFoundException e) {
// Shouldn't happen
@@ -728,25 +750,28 @@
* Forces the app's beginIdleTime and lastUsedTime to reflect idle or active. If idle,
* then it rolls back the beginIdleTime and lastUsedTime to a point in time that's behind
* the threshold for idle.
+ *
+ * This method is always called from the handler thread, so not much synchronization is
+ * required.
*/
void forceIdleState(String packageName, int userId, boolean idle) {
final int appId = getAppId(packageName);
if (appId < 0) return;
- synchronized (mLock) {
- final long elapsedRealtime = SystemClock.elapsedRealtime();
+ final long elapsedRealtime = SystemClock.elapsedRealtime();
- final boolean previouslyIdle = isAppIdleFiltered(packageName, appId,
- userId, elapsedRealtime);
- mAppIdleHistory.setIdleLocked(packageName, userId, idle, elapsedRealtime);
- final boolean stillIdle = isAppIdleFiltered(packageName, appId,
- userId, elapsedRealtime);
- // Inform listeners if necessary
- if (previouslyIdle != stillIdle) {
- mHandler.sendMessage(mHandler.obtainMessage(MSG_INFORM_LISTENERS, userId,
- /* idle = */ stillIdle ? 1 : 0, packageName));
- if (!stillIdle) {
- notifyBatteryStats(packageName, userId, idle);
- }
+ final boolean previouslyIdle = isAppIdleFiltered(packageName, appId,
+ userId, elapsedRealtime);
+ synchronized (mAppIdleLock) {
+ mAppIdleHistory.setIdle(packageName, userId, idle, elapsedRealtime);
+ }
+ final boolean stillIdle = isAppIdleFiltered(packageName, appId,
+ userId, elapsedRealtime);
+ // Inform listeners if necessary
+ if (previouslyIdle != stillIdle) {
+ mHandler.sendMessage(mHandler.obtainMessage(MSG_INFORM_LISTENERS, userId,
+ /* idle = */ stillIdle ? 1 : 0, packageName));
+ if (!stillIdle) {
+ notifyBatteryStats(packageName, userId, idle);
}
}
}
@@ -767,7 +792,9 @@
synchronized (mLock) {
Slog.i(TAG, "Removing user " + userId + " and all data.");
mUserState.remove(userId);
- mAppIdleHistory.onUserRemoved(userId);
+ synchronized (mAppIdleLock) {
+ mAppIdleHistory.onUserRemoved(userId);
+ }
cleanUpRemovedUsersLocked();
}
}
@@ -822,13 +849,13 @@
}
private boolean isAppIdleUnfiltered(String packageName, int userId, long elapsedRealtime) {
- synchronized (mLock) {
- return mAppIdleHistory.isIdleLocked(packageName, userId, elapsedRealtime);
+ synchronized (mAppIdleLock) {
+ return mAppIdleHistory.isIdle(packageName, userId, elapsedRealtime);
}
}
void addListener(AppIdleStateChangeListener listener) {
- synchronized (mLock) {
+ synchronized (mAppIdleLock) {
if (!mPackageAccessListeners.contains(listener)) {
mPackageAccessListeners.add(listener);
}
@@ -836,7 +863,7 @@
}
void removeListener(AppIdleStateChangeListener listener) {
- synchronized (mLock) {
+ synchronized (mAppIdleLock) {
mPackageAccessListeners.remove(listener);
}
}
@@ -988,7 +1015,7 @@
return res;
}
- void setAppIdle(String packageName, boolean idle, int userId) {
+ void setAppIdleAsync(String packageName, boolean idle, int userId) {
if (packageName == null) return;
mHandler.obtainMessage(MSG_FORCE_IDLE_STATE, userId, idle ? 1 : 0, packageName)
@@ -1012,9 +1039,9 @@
}
private boolean isCarrierApp(String packageName) {
- synchronized (mLock) {
+ synchronized (mAppIdleLock) {
if (!mHaveCarrierPrivilegedApps) {
- fetchCarrierPrivilegedAppsLocked();
+ fetchCarrierPrivilegedAppsLA();
}
if (mCarrierPrivilegedApps != null) {
return mCarrierPrivilegedApps.contains(packageName);
@@ -1027,13 +1054,14 @@
if (DEBUG) {
Slog.i(TAG, "Clearing carrier privileged apps list");
}
- synchronized (mLock) {
+ synchronized (mAppIdleLock) {
mHaveCarrierPrivilegedApps = false;
mCarrierPrivilegedApps = null; // Need to be refetched.
}
}
- private void fetchCarrierPrivilegedAppsLocked() {
+ @GuardedBy("mAppIdleLock")
+ private void fetchCarrierPrivilegedAppsLA() {
TelephonyManager telephonyManager =
getContext().getSystemService(TelephonyManager.class);
mCarrierPrivilegedApps = telephonyManager.getPackagesWithCarrierPrivileges();
@@ -1071,11 +1099,15 @@
for (int i = 0; i < userCount; i++) {
UserUsageStatsService service = mUserState.valueAt(i);
service.persistActiveStats();
- mAppIdleHistory.writeAppIdleTimesLocked(mUserState.keyAt(i));
+ synchronized (mAppIdleLock) {
+ mAppIdleHistory.writeAppIdleTimes(mUserState.keyAt(i));
+ }
}
// Persist elapsed and screen on time. If this fails for whatever reason, the apps will be
// considered not-idle, which is the safest outcome in such an event.
- mAppIdleHistory.writeAppIdleDurationsLocked();
+ synchronized (mAppIdleLock) {
+ mAppIdleHistory.writeAppIdleDurations();
+ }
mHandler.removeMessages(MSG_FLUSH_TO_DISK);
}
@@ -1100,20 +1132,26 @@
idpw.println();
if (args.length > 0) {
if ("history".equals(args[0])) {
- mAppIdleHistory.dumpHistory(idpw, mUserState.keyAt(i));
+ synchronized (mAppIdleLock) {
+ mAppIdleHistory.dumpHistory(idpw, mUserState.keyAt(i));
+ }
} else if ("flush".equals(args[0])) {
UsageStatsService.this.flushToDiskLocked();
pw.println("Flushed stats to disk");
}
}
}
- mAppIdleHistory.dump(idpw, mUserState.keyAt(i));
+ synchronized (mAppIdleLock) {
+ mAppIdleHistory.dump(idpw, mUserState.keyAt(i));
+ }
idpw.decreaseIndent();
}
pw.println();
- pw.println("Carrier privileged apps (have=" + mHaveCarrierPrivilegedApps
- + "): " + mCarrierPrivilegedApps);
+ synchronized (mAppIdleLock) {
+ pw.println("Carrier privileged apps (have=" + mHaveCarrierPrivilegedApps
+ + "): " + mCarrierPrivilegedApps);
+ }
pw.println();
pw.println("Settings:");
@@ -1252,7 +1290,7 @@
}
void updateSettings() {
- synchronized (mLock) {
+ synchronized (mAppIdleLock) {
// Look at global settings for this.
// TODO: Maybe apply different thresholds for different users.
try {
@@ -1384,7 +1422,7 @@
try {
userId = ActivityManager.getService().handleIncomingUser(
Binder.getCallingPid(), callingUid, userId, false, true,
- "setAppIdle", null);
+ "setAppInactive", null);
} catch (RemoteException re) {
throw re.rethrowFromSystemServer();
}
@@ -1394,7 +1432,7 @@
try {
final int appId = getAppId(packageName);
if (appId < 0) return;
- UsageStatsService.this.setAppIdle(packageName, idle, userId);
+ UsageStatsService.this.setAppIdleAsync(packageName, idle, userId);
} finally {
Binder.restoreCallingIdentity(token);
}
@@ -1586,21 +1624,25 @@
@Override
public byte[] getBackupPayload(int user, String key) {
// Check to ensure that only user 0's data is b/r for now
- if (user == UserHandle.USER_SYSTEM) {
- final UserUsageStatsService userStats =
- getUserDataAndInitializeIfNeededLocked(user, checkAndGetTimeLocked());
- return userStats.getBackupPayload(key);
- } else {
- return null;
+ synchronized (UsageStatsService.this.mLock) {
+ if (user == UserHandle.USER_SYSTEM) {
+ final UserUsageStatsService userStats =
+ getUserDataAndInitializeIfNeededLocked(user, checkAndGetTimeLocked());
+ return userStats.getBackupPayload(key);
+ } else {
+ return null;
+ }
}
}
@Override
public void applyRestoredPayload(int user, String key, byte[] payload) {
- if (user == UserHandle.USER_SYSTEM) {
- final UserUsageStatsService userStats =
- getUserDataAndInitializeIfNeededLocked(user, checkAndGetTimeLocked());
- userStats.applyRestoredPayload(key, payload);
+ synchronized (UsageStatsService.this.mLock) {
+ if (user == UserHandle.USER_SYSTEM) {
+ final UserUsageStatsService userStats =
+ getUserDataAndInitializeIfNeededLocked(user, checkAndGetTimeLocked());
+ userStats.applyRestoredPayload(key, payload);
+ }
}
}
diff --git a/services/usage/java/com/android/server/usage/UserUsageStatsService.java b/services/usage/java/com/android/server/usage/UserUsageStatsService.java
index d9f352c..8d335a5 100644
--- a/services/usage/java/com/android/server/usage/UserUsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UserUsageStatsService.java
@@ -529,7 +529,6 @@
pw.decreaseIndent();
pw.println();
- pw.increaseIndent();
pw.println("ChooserCounts");
pw.increaseIndent();
for (UsageStats usageStats : pkgStats.values()) {
@@ -553,6 +552,7 @@
}
pw.println();
}
+ pw.decreaseIndent();
pw.println("configurations");
pw.increaseIndent();
diff --git a/services/usb/java/com/android/server/usb/MtpNotificationManager.java b/services/usb/java/com/android/server/usb/MtpNotificationManager.java
index 5c46222..db7b385 100644
--- a/services/usb/java/com/android/server/usb/MtpNotificationManager.java
+++ b/services/usb/java/com/android/server/usb/MtpNotificationManager.java
@@ -20,7 +20,6 @@
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
-import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
@@ -32,6 +31,8 @@
import android.hardware.usb.UsbManager;
import android.os.UserHandle;
+import com.android.internal.notification.SystemNotificationChannels;
+
/**
* Manager for MTP storage notification.
*/
@@ -77,11 +78,12 @@
device.getProductName());
final String description = resources.getString(
com.android.internal.R.string.usb_mtp_launch_notification_description);
- final Notification.Builder builder = new Notification.Builder(mContext)
- .setContentTitle(title)
- .setContentText(description)
- .setSmallIcon(com.android.internal.R.drawable.stat_sys_data_usb)
- .setCategory(Notification.CATEGORY_SYSTEM);
+ final Notification.Builder builder =
+ new Notification.Builder(mContext, SystemNotificationChannels.USB)
+ .setContentTitle(title)
+ .setContentText(description)
+ .setSmallIcon(com.android.internal.R.drawable.stat_sys_data_usb)
+ .setCategory(Notification.CATEGORY_SYSTEM);
final Intent intent = new Intent(ACTION_OPEN_IN_APPS);
intent.putExtra(UsbManager.EXTRA_DEVICE, device);
diff --git a/services/usb/java/com/android/server/usb/UsbDeviceManager.java b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
index 07b4ca1..b1df0af 100644
--- a/services/usb/java/com/android/server/usb/UsbDeviceManager.java
+++ b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
@@ -50,6 +50,7 @@
import android.util.Slog;
import com.android.internal.annotations.GuardedBy;
+import com.android.internal.notification.SystemNotificationChannels;
import com.android.internal.os.SomeArgs;
import com.android.internal.util.IndentingPrintWriter;
import com.android.server.FgThread;
@@ -912,13 +913,13 @@
PendingIntent pi = PendingIntent.getActivityAsUser(mContext, 0,
intent, 0, null, UserHandle.CURRENT);
- Notification notification = new Notification.Builder(mContext)
+ Notification notification =
+ new Notification.Builder(mContext, SystemNotificationChannels.USB)
.setSmallIcon(com.android.internal.R.drawable.stat_sys_adb)
.setWhen(0)
.setOngoing(true)
.setTicker(title)
.setDefaults(0) // please be quiet
- .setPriority(Notification.PRIORITY_MIN)
.setColor(mContext.getColor(
com.android.internal.R.color.system_notification_accent_color))
.setContentTitle(title)
@@ -951,13 +952,13 @@
PendingIntent pi = PendingIntent.getActivityAsUser(mContext, 0,
intent, 0, null, UserHandle.CURRENT);
- Notification notification = new Notification.Builder(mContext)
+ Notification notification =
+ new Notification.Builder(mContext, SystemNotificationChannels.DEVELOPER)
.setSmallIcon(com.android.internal.R.drawable.stat_sys_adb)
.setWhen(0)
.setOngoing(true)
.setTicker(title)
.setDefaults(0) // please be quiet
- .setPriority(Notification.PRIORITY_DEFAULT)
.setColor(mContext.getColor(
com.android.internal.R.color.system_notification_accent_color))
.setContentTitle(title)
diff --git a/services/usb/java/com/android/server/usb/UsbPortManager.java b/services/usb/java/com/android/server/usb/UsbPortManager.java
index 4b8e4c8..bae7cdc 100644
--- a/services/usb/java/com/android/server/usb/UsbPortManager.java
+++ b/services/usb/java/com/android/server/usb/UsbPortManager.java
@@ -455,9 +455,9 @@
public void notifyRoleSwitchStatus(String portName, PortRole role, int retval) {
if (retval == Status.SUCCESS) {
- logAndPrint(Log.INFO, pw, portName + "role switch successful");
+ logAndPrint(Log.INFO, pw, portName + " role switch successful");
} else {
- logAndPrint(Log.ERROR, pw, portName + "role switch failed");
+ logAndPrint(Log.ERROR, pw, portName + " role switch failed");
}
}
};
@@ -498,11 +498,12 @@
mProxy.setCallback(mHALCallback);
mProxy.queryPortStatus();
} catch (NoSuchElementException e) {
- logAndPrint(Log.ERROR, pw, sSERVICENAME + "not found."
- + " Did the service failed to start ?");
+ logAndPrint(Log.ERROR, pw, sSERVICENAME + " not found."
+ + " Did the service fail to start?");
Thread.dumpStack();
} catch (RemoteException e) {
- logAndPrint(Log.ERROR, pw, sSERVICENAME + "connectToProxy: Service not responding");
+ logAndPrint(Log.ERROR, pw, sSERVICENAME
+ + " connectToProxy: Service not responding");
Thread.dumpStack();
}
}
diff --git a/telecomm/java/android/telecom/Call.java b/telecomm/java/android/telecom/Call.java
index 4295d40..3f7c908 100644
--- a/telecomm/java/android/telecom/Call.java
+++ b/telecomm/java/android/telecom/Call.java
@@ -878,6 +878,7 @@
* party, if it is active.
*/
public static final class RttCall {
+ /** @hide */
@Retention(RetentionPolicy.SOURCE)
@IntDef({RTT_MODE_INVALID, RTT_MODE_FULL, RTT_MODE_HCO, RTT_MODE_VCO})
public @interface RttAudioMode {}
diff --git a/telecomm/java/android/telecom/TelecomManager.java b/telecomm/java/android/telecom/TelecomManager.java
index 6807ef4..2e144f2 100644
--- a/telecomm/java/android/telecom/TelecomManager.java
+++ b/telecomm/java/android/telecom/TelecomManager.java
@@ -1130,18 +1130,22 @@
/**
* If there is a ringing incoming call, this method accepts the call on behalf of the user.
- * TODO: L-release - need to convert all invocation of ITelecmmService#answerRingingCall to use
- * this method (clockwork & gearhead).
+ *
* If the incoming call is a video call, the call will be answered with the same video state as
* the incoming call requests. This means, for example, that an incoming call requesting
* {@link VideoProfile#STATE_BIDIRECTIONAL} will be answered, accepting that state.
- * @hide
+ *
+ * Requires permission: {@link android.Manifest.permission#MODIFY_PHONE_STATE} or
+ * {@link android.Manifest.permission#ANSWER_PHONE_CALLS}
*/
- @SystemApi
+ //TODO: L-release - need to convert all invocation of ITelecmmService#answerRingingCall to use
+ // this method (clockwork & gearhead).
+ @RequiresPermission(anyOf =
+ {Manifest.permission.ANSWER_PHONE_CALLS, Manifest.permission.MODIFY_PHONE_STATE})
public void acceptRingingCall() {
try {
if (isServiceConnected()) {
- getTelecomService().acceptRingingCall();
+ getTelecomService().acceptRingingCall(mContext.getPackageName());
}
} catch (RemoteException e) {
Log.e(TAG, "Error calling ITelecomService#acceptRingingCall", e);
@@ -1152,14 +1156,18 @@
* If there is a ringing incoming call, this method accepts the call on behalf of the user,
* with the specified video state.
*
+ * Requires permission: {@link android.Manifest.permission#MODIFY_PHONE_STATE} or
+ * {@link android.Manifest.permission#ANSWER_PHONE_CALLS}
+ *
* @param videoState The desired video state to answer the call with.
- * @hide
*/
- @SystemApi
+ @RequiresPermission(anyOf =
+ {Manifest.permission.ANSWER_PHONE_CALLS, Manifest.permission.MODIFY_PHONE_STATE})
public void acceptRingingCall(int videoState) {
try {
if (isServiceConnected()) {
- getTelecomService().acceptRingingCallWithVideoState(videoState);
+ getTelecomService().acceptRingingCallWithVideoState(
+ mContext.getPackageName(), videoState);
}
} catch (RemoteException e) {
Log.e(TAG, "Error calling ITelecomService#acceptRingingCallWithVideoState", e);
diff --git a/telecomm/java/android/telecom/VideoProfile.java b/telecomm/java/android/telecom/VideoProfile.java
index 216603c..e0e3a08 100644
--- a/telecomm/java/android/telecom/VideoProfile.java
+++ b/telecomm/java/android/telecom/VideoProfile.java
@@ -235,7 +235,7 @@
StringBuilder sb = new StringBuilder();
sb.append("Audio");
- if (isAudioOnly(videoState)) {
+ if (videoState == STATE_AUDIO_ONLY) {
sb.append(" Only");
} else {
if (isTransmissionEnabled(videoState)) {
@@ -256,6 +256,9 @@
/**
* Indicates whether the video state is audio only.
+ * <p>
+ * Note: Considers only whether either both the {@link #STATE_RX_ENABLED} or
+ * {@link #STATE_TX_ENABLED} bits are off, but not {@link #STATE_PAUSED}.
*
* @param videoState The video state.
* @return {@code True} if the video state is audio only, {@code false} otherwise.
diff --git a/telecomm/java/com/android/internal/telecom/ITelecomService.aidl b/telecomm/java/com/android/internal/telecom/ITelecomService.aidl
index d9465dc..eb1cde3 100644
--- a/telecomm/java/com/android/internal/telecom/ITelecomService.aidl
+++ b/telecomm/java/com/android/internal/telecom/ITelecomService.aidl
@@ -182,12 +182,12 @@
/**
* @see TelecomServiceImpl#acceptRingingCall
*/
- void acceptRingingCall();
+ void acceptRingingCall(String callingPackage);
/**
* @see TelecomServiceImpl#acceptRingingCallWithVideoState(int)
*/
- void acceptRingingCallWithVideoState(int videoState);
+ void acceptRingingCallWithVideoState(String callingPackage, int videoState);
/**
* @see TelecomServiceImpl#cancelMissedCallsNotification
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 70df69c..632a1d6 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -942,7 +942,7 @@
/**
* Defines carrier-specific actions which act upon
- * android.intent.action.CARRIER_SIGNAL_REDIRECTED, used for customization of the
+ * com.android.internal.telephony.CARRIER_SIGNAL_REDIRECTED, used for customization of the
* default carrier app
* Format: "CARRIER_ACTION_IDX, ..."
* Where {@code CARRIER_ACTION_IDX} is an integer defined in
@@ -957,7 +957,7 @@
/**
* Defines carrier-specific actions which act upon
- * android.intent.action.CARRIER_SIGNAL_REQUEST_NETWORK_FAILED
+ * com.android.internal.telephony.CARRIER_SIGNAL_REQUEST_NETWORK_FAILED
* and configured signal args:
* {@link com.android.internal.telephony.TelephonyIntents#EXTRA_APN_TYPE_KEY apnType},
* {@link com.android.internal.telephony.TelephonyIntents#EXTRA_ERROR_CODE_KEY errorCode}
@@ -998,11 +998,11 @@
* @see com.android.internal.telephony.TelephonyIntents
* Example:
* <item>com.google.android.carrierAPK/.CarrierSignalReceiverA:
- * android.intent.action.CARRIER_SIGNAL_REDIRECTED,
- * android.intent.action.CARRIER_SIGNAL_PCO_VALUE
+ * com.android.internal.telephony.CARRIER_SIGNAL_REDIRECTED,
+ * com.android.internal.telephony.CARRIER_SIGNAL_PCO_VALUE
* </item>
* <item>com.google.android.carrierAPK/.CarrierSignalReceiverB:
- * android.intent.action.CARRIER_SIGNAL_PCO_VALUE
+ * com.android.internal.telephony.CARRIER_SIGNAL_PCO_VALUE
* </item>
* @hide
*/
@@ -1017,11 +1017,11 @@
* @see com.android.internal.telephony.TelephonyIntents
* Example:
* <item>com.google.android.carrierAPK/.CarrierSignalReceiverA:
- * android.intent.action.CARRIER_SIGNAL_REQUEST_NETWORK_FAILED,
- * android.intent.action.CARRIER_SIGNAL_PCO_VALUE
+ * com.android.internal.telephony.CARRIER_SIGNAL_REQUEST_NETWORK_FAILED,
+ * com.android.internal.telephony.CARRIER_SIGNAL_PCO_VALUE
* </item>
* <item>com.google.android.carrierAPK/.CarrierSignalReceiverB:
- * android.intent.action.CARRIER_SIGNAL_REQUEST_NETWORK_FAILED
+ * com.android.internal.telephony.CARRIER_SIGNAL_REQUEST_NETWORK_FAILED
* </item>
* @hide
*/
@@ -1282,6 +1282,14 @@
"support_3gpp_call_forwarding_while_roaming_bool";
/**
+ * When {@code true}, the user will be notified when they attempt to place an international call
+ * when the call is placed using wifi calling.
+ * @hide
+ */
+ public static final String KEY_NOTIFY_INTERNATIONAL_CALL_ON_WFC_BOOL =
+ "notify_international_call_on_wfc_bool";
+
+ /**
* Determine whether user edited tether APN (type dun) has effect
* {@code false} - Default. APN with dun type in telephony database has no effect.
*
@@ -1493,7 +1501,7 @@
sDefaults.putStringArray(KEY_CARRIER_APP_WAKE_SIGNAL_CONFIG_STRING_ARRAY,
new String[]{
"com.android.carrierdefaultapp/.CarrierDefaultBroadcastReceiver:" +
- "android.intent.action.CARRIER_SIGNAL_REDIRECTED"
+ "com.android.internal.telephony.CARRIER_SIGNAL_REDIRECTED"
});
sDefaults.putStringArray(KEY_CARRIER_APP_NO_WAKE_SIGNAL_CONFIG_STRING_ARRAY, null);
@@ -1529,6 +1537,7 @@
sDefaults.putStringArray(KEY_CARRIER_WIFI_STRING_ARRAY, null);
sDefaults.putInt(KEY_PREF_NETWORK_NOTIFICATION_DELAY_INT, -1);
sDefaults.putBoolean(KEY_SUPPORT_3GPP_CALL_FORWARDING_WHILE_ROAMING_BOOL, true);
+ sDefaults.putBoolean(KEY_NOTIFY_INTERNATIONAL_CALL_ON_WFC_BOOL, false);
sDefaults.putBoolean(KEY_EDITABLE_TETHER_APN_BOOL, false);
sDefaults.putStringArray(KEY_CALL_FORWARDING_BLOCKS_WHILE_ROAMING_STRING_ARRAY,
null);
diff --git a/telephony/java/android/telephony/PhoneNumberUtils.java b/telephony/java/android/telephony/PhoneNumberUtils.java
index 6f51c6e..a3e11c8 100644
--- a/telephony/java/android/telephony/PhoneNumberUtils.java
+++ b/telephony/java/android/telephony/PhoneNumberUtils.java
@@ -1140,6 +1140,8 @@
private static final String KOREA_ISO_COUNTRY_CODE = "KR";
+ private static final String JAPAN_ISO_COUNTRY_CODE = "JP";
+
/**
* Breaks the given number down and formats it according to the rules
* for the country the number is from.
@@ -1438,6 +1440,30 @@
}
/**
+ * Determines if a {@param phoneNumber} is international if dialed from
+ * {@param defaultCountryIso}.
+ *
+ * @param phoneNumber The phone number.
+ * @param defaultCountryIso The current country ISO.
+ * @return {@code true} if the number is international, {@code false} otherwise.
+ * @hide
+ */
+ public static boolean isInternationalNumber(String phoneNumber, String defaultCountryIso) {
+ // If it starts with # or * its not international.
+ if (phoneNumber.startsWith("#") || phoneNumber.startsWith("*")) {
+ return false;
+ }
+
+ PhoneNumberUtil util = PhoneNumberUtil.getInstance();
+ try {
+ PhoneNumber pn = util.parseAndKeepRawInput(phoneNumber, defaultCountryIso);
+ return pn.getCountryCode() != util.getCountryCodeForRegion(defaultCountryIso);
+ } catch (NumberParseException e) {
+ return false;
+ }
+ }
+
+ /**
* Format a phone number.
* <p>
* If the given number doesn't have the country code, the phone will be
@@ -1460,15 +1486,25 @@
String result = null;
try {
PhoneNumber pn = util.parseAndKeepRawInput(phoneNumber, defaultCountryIso);
- /**
- * Need to reformat any local Korean phone numbers (when the user is in Korea) with
- * country code to corresponding national format which would replace the leading
- * +82 with 0.
- */
- if (KOREA_ISO_COUNTRY_CODE.equals(defaultCountryIso) &&
+
+ if (KOREA_ISO_COUNTRY_CODE.equalsIgnoreCase(defaultCountryIso) &&
(pn.getCountryCode() == util.getCountryCodeForRegion(KOREA_ISO_COUNTRY_CODE)) &&
(pn.getCountryCodeSource() ==
PhoneNumber.CountryCodeSource.FROM_NUMBER_WITH_PLUS_SIGN)) {
+ /**
+ * Need to reformat any local Korean phone numbers (when the user is in Korea) with
+ * country code to corresponding national format which would replace the leading
+ * +82 with 0.
+ */
+ result = util.format(pn, PhoneNumberUtil.PhoneNumberFormat.NATIONAL);
+ } else if (JAPAN_ISO_COUNTRY_CODE.equalsIgnoreCase(defaultCountryIso) &&
+ pn.getCountryCode() == util.getCountryCodeForRegion(JAPAN_ISO_COUNTRY_CODE) &&
+ (pn.getCountryCodeSource() ==
+ PhoneNumber.CountryCodeSource.FROM_NUMBER_WITH_PLUS_SIGN)) {
+ /**
+ * Need to reformat Japanese phone numbers (when user is in Japan) with the national
+ * dialing format.
+ */
result = util.format(pn, PhoneNumberUtil.PhoneNumberFormat.NATIONAL);
} else {
result = util.formatInOriginalFormat(pn, defaultCountryIso);
diff --git a/telephony/java/android/telephony/PhoneStateListener.java b/telephony/java/android/telephony/PhoneStateListener.java
index dd03305..afff6d5 100644
--- a/telephony/java/android/telephony/PhoneStateListener.java
+++ b/telephony/java/android/telephony/PhoneStateListener.java
@@ -208,7 +208,9 @@
*
* @see #onOemHookRawEvent
* @hide
+ * @deprecated OEM needs a vendor-extension hal and their apps should use that instead
*/
+ @Deprecated
public static final int LISTEN_OEM_HOOK_RAW_EVENT = 0x00008000;
/**
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index a4235d7..81e87b3 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -819,6 +819,21 @@
public static final String EVENT_DOWNGRADE_DATA_DISABLED =
"android.telephony.event.EVENT_DOWNGRADE_DATA_DISABLED";
+ /**
+ * {@link android.telecom.Connection} event used to indicate that the InCall UI should notify
+ * the user when an international call is placed while on WFC only.
+ * <p>
+ * Used when the carrier config value
+ * {@link CarrierConfigManager#KEY_NOTIFY_INTERNATIONAL_CALL_ON_WFC_BOOL} is true, the device
+ * is on WFC (VoLTE not available) and an international number is dialed.
+ * <p>
+ * Sent via {@link android.telecom.Connection#sendConnectionEvent(String, Bundle)}.
+ * The {@link Bundle} parameter is expected to be null when this connection event is used.
+ * @hide
+ */
+ public static final String EVENT_NOTIFY_INTERNATIONAL_CALL_ON_WFC =
+ "android.telephony.event.EVENT_NOTIFY_INTERNATIONAL_CALL_ON_WFC";
+
/* Visual voicemail protocols */
/**
@@ -5229,7 +5244,9 @@
* 0 request was handled succesfully, but no response data
* positive value success, data length of response
* @hide
+ * @deprecated OEM needs a vendor-extension hal and their apps should use that instead
*/
+ @Deprecated
public int invokeOemRilRequestRaw(byte[] oemReq, byte[] oemResp) {
try {
ITelephony telephony = getITelephony();
diff --git a/telephony/java/android/telephony/ims/ImsService.java b/telephony/java/android/telephony/ims/ImsService.java
index fe8dbfb..f1f683c 100644
--- a/telephony/java/android/telephony/ims/ImsService.java
+++ b/telephony/java/android/telephony/ims/ImsService.java
@@ -18,6 +18,7 @@
import android.app.PendingIntent;
import android.content.Intent;
+import android.content.pm.PackageManager;
import android.os.IBinder;
import android.os.Message;
import android.os.RemoteException;
@@ -41,6 +42,10 @@
import com.android.ims.internal.IImsUt;
import com.android.internal.annotations.VisibleForTesting;
+import static android.Manifest.permission.MODIFY_PHONE_STATE;
+import static android.Manifest.permission.READ_PHONE_STATE;
+import static android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE;
+
/**
* Main ImsService implementation, which binds via the Telephony ImsResolver. Services that extend
* ImsService must register the service in their AndroidManifest to be detected by the framework.
@@ -94,6 +99,7 @@
public void createImsFeature(int slotId, int feature, IImsFeatureStatusCallback c)
throws RemoteException {
synchronized (mFeatures) {
+ enforceCallingOrSelfPermission(MODIFY_PHONE_STATE, "createImsFeature");
onCreateImsFeatureInternal(slotId, feature, c);
}
}
@@ -101,6 +107,7 @@
@Override
public void removeImsFeature(int slotId, int feature) throws RemoteException {
synchronized (mFeatures) {
+ enforceCallingOrSelfPermission(MODIFY_PHONE_STATE, "removeImsFeature");
onRemoveImsFeatureInternal(slotId, feature);
}
}
@@ -108,6 +115,7 @@
@Override
public int startSession(int slotId, int featureType, PendingIntent incomingCallIntent,
IImsRegistrationListener listener) throws RemoteException {
+ enforceCallingOrSelfPermission(MODIFY_PHONE_STATE, "startSession");
synchronized (mFeatures) {
MMTelFeature feature = resolveMMTelFeature(slotId, featureType);
if (feature != null) {
@@ -120,6 +128,7 @@
@Override
public void endSession(int slotId, int featureType, int sessionId) throws RemoteException {
synchronized (mFeatures) {
+ enforceCallingOrSelfPermission(MODIFY_PHONE_STATE, "endSession");
MMTelFeature feature = resolveMMTelFeature(slotId, featureType);
if (feature != null) {
feature.endSession(sessionId);
@@ -130,6 +139,7 @@
@Override
public boolean isConnected(int slotId, int featureType, int callSessionType, int callType)
throws RemoteException {
+ enforceReadPhoneStatePermission("isConnected");
synchronized (mFeatures) {
MMTelFeature feature = resolveMMTelFeature(slotId, featureType);
if (feature != null) {
@@ -141,6 +151,7 @@
@Override
public boolean isOpened(int slotId, int featureType) throws RemoteException {
+ enforceReadPhoneStatePermission("isOpened");
synchronized (mFeatures) {
MMTelFeature feature = resolveMMTelFeature(slotId, featureType);
if (feature != null) {
@@ -152,6 +163,7 @@
@Override
public int getFeatureStatus(int slotId, int featureType) throws RemoteException {
+ enforceReadPhoneStatePermission("getFeatureStatus");
int status = ImsFeature.STATE_NOT_AVAILABLE;
synchronized (mFeatures) {
SparseArray<ImsFeature> featureMap = mFeatures.get(slotId);
@@ -168,6 +180,7 @@
@Override
public void addRegistrationListener(int slotId, int featureType,
IImsRegistrationListener listener) throws RemoteException {
+ enforceReadPhoneStatePermission("addRegistrationListener");
synchronized (mFeatures) {
MMTelFeature feature = resolveMMTelFeature(slotId, featureType);
if (feature != null) {
@@ -179,6 +192,7 @@
@Override
public void removeRegistrationListener(int slotId, int featureType,
IImsRegistrationListener listener) throws RemoteException {
+ enforceReadPhoneStatePermission("removeRegistrationListener");
synchronized (mFeatures) {
MMTelFeature feature = resolveMMTelFeature(slotId, featureType);
if (feature != null) {
@@ -190,6 +204,7 @@
@Override
public ImsCallProfile createCallProfile(int slotId, int featureType, int sessionId,
int callSessionType, int callType) throws RemoteException {
+ enforceCallingOrSelfPermission(MODIFY_PHONE_STATE, "createCallProfile");
synchronized (mFeatures) {
MMTelFeature feature = resolveMMTelFeature(slotId, featureType);
if (feature != null) {
@@ -202,6 +217,7 @@
@Override
public IImsCallSession createCallSession(int slotId, int featureType, int sessionId,
ImsCallProfile profile, IImsCallSessionListener listener) throws RemoteException {
+ enforceCallingOrSelfPermission(MODIFY_PHONE_STATE, "createCallSession");
synchronized (mFeatures) {
MMTelFeature feature = resolveMMTelFeature(slotId, featureType);
if (feature != null) {
@@ -214,6 +230,7 @@
@Override
public IImsCallSession getPendingCallSession(int slotId, int featureType, int sessionId,
String callId) throws RemoteException {
+ enforceCallingOrSelfPermission(MODIFY_PHONE_STATE, "getPendingCallSession");
synchronized (mFeatures) {
MMTelFeature feature = resolveMMTelFeature(slotId, featureType);
if (feature != null) {
@@ -226,6 +243,7 @@
@Override
public IImsUt getUtInterface(int slotId, int featureType)
throws RemoteException {
+ enforceCallingOrSelfPermission(MODIFY_PHONE_STATE, "getUtInterface");
synchronized (mFeatures) {
MMTelFeature feature = resolveMMTelFeature(slotId, featureType);
if (feature != null) {
@@ -238,6 +256,7 @@
@Override
public IImsConfig getConfigInterface(int slotId, int featureType)
throws RemoteException {
+ enforceCallingOrSelfPermission(MODIFY_PHONE_STATE, "getConfigInterface");
synchronized (mFeatures) {
MMTelFeature feature = resolveMMTelFeature(slotId, featureType);
if (feature != null) {
@@ -249,6 +268,7 @@
@Override
public void turnOnIms(int slotId, int featureType) throws RemoteException {
+ enforceCallingOrSelfPermission(MODIFY_PHONE_STATE, "turnOnIms");
synchronized (mFeatures) {
MMTelFeature feature = resolveMMTelFeature(slotId, featureType);
if (feature != null) {
@@ -259,6 +279,7 @@
@Override
public void turnOffIms(int slotId, int featureType) throws RemoteException {
+ enforceCallingOrSelfPermission(MODIFY_PHONE_STATE, "turnOffIms");
synchronized (mFeatures) {
MMTelFeature feature = resolveMMTelFeature(slotId, featureType);
if (feature != null) {
@@ -270,6 +291,7 @@
@Override
public IImsEcbm getEcbmInterface(int slotId, int featureType)
throws RemoteException {
+ enforceCallingOrSelfPermission(MODIFY_PHONE_STATE, "getEcbmInterface");
synchronized (mFeatures) {
MMTelFeature feature = resolveMMTelFeature(slotId, featureType);
if (feature != null) {
@@ -282,6 +304,7 @@
@Override
public void setUiTTYMode(int slotId, int featureType, int uiTtyMode, Message onComplete)
throws RemoteException {
+ enforceCallingOrSelfPermission(MODIFY_PHONE_STATE, "setUiTTYMode");
synchronized (mFeatures) {
MMTelFeature feature = resolveMMTelFeature(slotId, featureType);
if (feature != null) {
@@ -293,6 +316,7 @@
@Override
public IImsMultiEndpoint getMultiEndpointInterface(int slotId, int featureType)
throws RemoteException {
+ enforceCallingOrSelfPermission(MODIFY_PHONE_STATE, "getMultiEndpointInterface");
synchronized (mFeatures) {
MMTelFeature feature = resolveMMTelFeature(slotId, featureType);
if (feature != null) {
@@ -329,6 +353,8 @@
}
ImsFeature f = makeImsFeature(slotId, featureType);
if (f != null) {
+ f.setContext(this);
+ f.setSlotId(slotId);
f.setImsFeatureStatusCallback(c);
featureMap.put(featureType, f);
}
@@ -412,6 +438,17 @@
}
/**
+ * Check for both READ_PHONE_STATE and READ_PRIVILEGED_PHONE_STATE. READ_PHONE_STATE is a
+ * public permission and READ_PRIVILEGED_PHONE_STATE is only granted to system apps.
+ */
+ private void enforceReadPhoneStatePermission(String fn) {
+ if (checkCallingOrSelfPermission(READ_PRIVILEGED_PHONE_STATE)
+ != PackageManager.PERMISSION_GRANTED) {
+ enforceCallingOrSelfPermission(READ_PHONE_STATE, fn);
+ }
+ }
+
+ /**
* @return An implementation of MMTelFeature that will be used by the system for MMTel
* functionality. Must be able to handle emergency calls at any time as well.
*/
diff --git a/telephony/java/android/telephony/ims/feature/ImsFeature.java b/telephony/java/android/telephony/ims/feature/ImsFeature.java
index 8d7d260..988dd58 100644
--- a/telephony/java/android/telephony/ims/feature/ImsFeature.java
+++ b/telephony/java/android/telephony/ims/feature/ImsFeature.java
@@ -17,7 +17,10 @@
package android.telephony.ims.feature;
import android.annotation.IntDef;
+import android.content.Context;
+import android.content.Intent;
import android.os.RemoteException;
+import android.telephony.SubscriptionManager;
import android.util.Log;
import com.android.ims.internal.IImsFeatureStatusCallback;
@@ -35,6 +38,32 @@
private static final String LOG_TAG = "ImsFeature";
+ /**
+ * Action to broadcast when ImsService is up.
+ * Internal use only.
+ * Only defined here separately compatibility purposes with the old ImsService.
+ * @hide
+ */
+ public static final String ACTION_IMS_SERVICE_UP =
+ "com.android.ims.IMS_SERVICE_UP";
+
+ /**
+ * Action to broadcast when ImsService is down.
+ * Internal use only.
+ * Only defined here separately for compatibility purposes with the old ImsService.
+ * @hide
+ */
+ public static final String ACTION_IMS_SERVICE_DOWN =
+ "com.android.ims.IMS_SERVICE_DOWN";
+
+ /**
+ * Part of the ACTION_IMS_SERVICE_UP or _DOWN intents.
+ * A long value; the phone ID corresponding to the IMS service coming up or down.
+ * Only defined here separately for compatibility purposes with the old ImsService.
+ * @hide
+ */
+ public static final String EXTRA_PHONE_ID = "android:phone_id";
+
// Invalid feature value
public static final int INVALID = -1;
// ImsFeatures that are defined in the Manifests. Ensure that these values match the previously
@@ -61,11 +90,21 @@
private List<INotifyFeatureRemoved> mRemovedListeners = new ArrayList<>();
private IImsFeatureStatusCallback mStatusCallback;
private @ImsState int mState = STATE_NOT_AVAILABLE;
+ private int mSlotId = SubscriptionManager.INVALID_SIM_SLOT_INDEX;
+ private Context mContext;
public interface INotifyFeatureRemoved {
void onFeatureRemoved(int slotId);
}
+ public void setContext(Context context) {
+ mContext = context;
+ }
+
+ public void setSlotId(int slotId) {
+ mSlotId = slotId;
+ }
+
public void addFeatureRemovedListener(INotifyFeatureRemoved listener) {
synchronized (mRemovedListeners) {
mRemovedListeners.add(listener);
@@ -118,6 +157,30 @@
Log.w(LOG_TAG, "Couldn't notify feature state: " + e.getMessage());
}
}
+ sendImsServiceIntent(state);
+ }
+
+ /**
+ * Provide backwards compatibility using deprecated service UP/DOWN intents.
+ */
+ private void sendImsServiceIntent(@ImsState int state) {
+ if(mContext == null || mSlotId == SubscriptionManager.INVALID_SIM_SLOT_INDEX) {
+ return;
+ }
+ Intent intent;
+ switch (state) {
+ case ImsFeature.STATE_NOT_AVAILABLE:
+ case ImsFeature.STATE_INITIALIZING:
+ intent = new Intent(ACTION_IMS_SERVICE_DOWN);
+ break;
+ case ImsFeature.STATE_READY:
+ intent = new Intent(ACTION_IMS_SERVICE_UP);
+ break;
+ default:
+ intent = new Intent(ACTION_IMS_SERVICE_DOWN);
+ }
+ intent.putExtra(EXTRA_PHONE_ID, mSlotId);
+ mContext.sendBroadcast(intent);
}
/**
diff --git a/telephony/java/android/telephony/ims/stub/ImsCallSessionImplBase.java b/telephony/java/android/telephony/ims/stub/ImsCallSessionImplBase.java
new file mode 100644
index 0000000..69b8acc
--- /dev/null
+++ b/telephony/java/android/telephony/ims/stub/ImsCallSessionImplBase.java
@@ -0,0 +1,348 @@
+/*
+ * Copyright (C) 2017 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.telephony.ims.stub;
+
+import android.os.Message;
+import android.os.RemoteException;
+
+import com.android.ims.ImsCallProfile;
+import com.android.ims.ImsStreamMediaProfile;
+import com.android.ims.internal.ImsCallSession;
+import com.android.ims.internal.IImsCallSession;
+import com.android.ims.internal.IImsCallSessionListener;
+import com.android.ims.internal.IImsVideoCallProvider;
+
+/**
+ * Base implementation of IImsCallSession, which implements stub versions of the methods in the
+ * IImsCallSession AIDL. Override the methods that your implementation of ImsCallSession supports.
+ *
+ * DO NOT remove or change the existing APIs, only add new ones to this Base implementation or you
+ * will break other implementations of ImsCallSession maintained by other ImsServices.
+ *
+ * @hide
+ */
+
+public class ImsCallSessionImplBase extends IImsCallSession.Stub {
+
+ /**
+ * Closes the object. This object is not usable after being closed.
+ */
+ @Override
+ public void close() throws RemoteException {
+
+ }
+
+ /**
+ * Gets the call ID of the session.
+ *
+ * @return the call ID
+ */
+ @Override
+ public String getCallId() throws RemoteException {
+ return null;
+ }
+
+ /**
+ * Gets the call profile that this session is associated with
+ *
+ * @return the {@link ImsCallProfile} that this session is associated with
+ */
+ @Override
+ public ImsCallProfile getCallProfile() throws RemoteException {
+ return null;
+ }
+
+ /**
+ * Gets the local call profile that this session is associated with
+ *
+ * @return the local {@link ImsCallProfile} that this session is associated with
+ */
+ @Override
+ public ImsCallProfile getLocalCallProfile() throws RemoteException {
+ return null;
+ }
+
+ /**
+ * Gets the remote call profile that this session is associated with
+ *
+ * @return the remote {@link ImsCallProfile} that this session is associated with
+ */
+ @Override
+ public ImsCallProfile getRemoteCallProfile() throws RemoteException {
+ return null;
+ }
+
+ /**
+ * Gets the value associated with the specified property of this session.
+ *
+ * @return the string value associated with the specified property
+ */
+ @Override
+ public String getProperty(String name) throws RemoteException {
+ return null;
+ }
+
+ /**
+ * Gets the session state.
+ * The value returned must be one of the states in {@link ImsCallSession.State}.
+ *
+ * @return the session state
+ */
+ @Override
+ public int getState() throws RemoteException {
+ return ImsCallSession.State.INVALID;
+ }
+
+ /**
+ * Checks if the session is in call.
+ *
+ * @return true if the session is in call, false otherwise
+ */
+ @Override
+ public boolean isInCall() throws RemoteException {
+ return false;
+ }
+
+ /**
+ * Sets the listener to listen to the session events. An {@link ImsCallSession}
+ * can only hold one listener at a time. Subsequent calls to this method
+ * override the previous listener.
+ *
+ * @param listener to listen to the session events of this object
+ */
+ @Override
+ public void setListener(IImsCallSessionListener listener) throws RemoteException {
+ }
+
+ /**
+ * Mutes or unmutes the mic for the active call.
+ *
+ * @param muted true if the call is muted, false otherwise
+ */
+ @Override
+ public void setMute(boolean muted) throws RemoteException {
+ }
+
+ /**
+ * Initiates an IMS call with the specified target and call profile.
+ * The session listener set in {@link #setListener} is called back upon defined session events.
+ * The method is only valid to call when the session state is in
+ * {@link ImsCallSession.State#IDLE}.
+ *
+ * @param callee dialed string to make the call to
+ * @param profile call profile to make the call with the specified service type,
+ * call type and media information
+ * @see {@link ImsCallSession.Listener#callSessionStarted},
+ * {@link ImsCallSession.Listener#callSessionStartFailed}
+ */
+ @Override
+ public void start(String callee, ImsCallProfile profile) throws RemoteException {
+ }
+
+ /**
+ * Initiates an IMS call with the specified participants and call profile.
+ * The session listener set in {@link #setListener} is called back upon defined session events.
+ * The method is only valid to call when the session state is in
+ * {@link ImsCallSession.State#IDLE}.
+ *
+ * @param participants participant list to initiate an IMS conference call
+ * @param profile call profile to make the call with the specified service type,
+ * call type and media information
+ * @see {@link ImsCallSession.Listener#callSessionStarted},
+ * {@link ImsCallSession.Listener#callSessionStartFailed}
+ */
+ @Override
+ public void startConference(String[] participants, ImsCallProfile profile)
+ throws RemoteException {
+ }
+
+ /**
+ * Accepts an incoming call or session update.
+ *
+ * @param callType call type specified in {@link ImsCallProfile} to be answered
+ * @param profile stream media profile {@link ImsStreamMediaProfile} to be answered
+ * @see {@link ImsCallSession.Listener#callSessionStarted}
+ */
+ @Override
+ public void accept(int callType, ImsStreamMediaProfile profile) throws RemoteException {
+ }
+
+ /**
+ * Rejects an incoming call or session update.
+ *
+ * @param reason reason code to reject an incoming call, defined in
+ * com.android.ims.ImsReasonInfo
+ * {@link ImsCallSession.Listener#callSessionStartFailed}
+ */
+ @Override
+ public void reject(int reason) throws RemoteException {
+ }
+
+ /**
+ * Terminates a call.
+ *
+ * @param reason reason code to terminate a call, defined in
+ * com.android.ims.ImsReasonInfo
+ *
+ * @see {@link ImsCallSession.Listener#callSessionTerminated}
+ */
+ @Override
+ public void terminate(int reason) throws RemoteException {
+ }
+
+ /**
+ * Puts a call on hold. When it succeeds, {@link ImsCallSession.Listener#callSessionHeld} is
+ * called.
+ *
+ * @param profile stream media profile {@link ImsStreamMediaProfile} to hold the call
+ * @see {@link ImsCallSession.Listener#callSessionHeld},
+ * {@link ImsCallSession.Listener#callSessionHoldFailed}
+ */
+ @Override
+ public void hold(ImsStreamMediaProfile profile) throws RemoteException {
+ }
+
+ /**
+ * Continues a call that's on hold. When it succeeds,
+ * {@link ImsCallSession.Listener#callSessionResumed} is called.
+ *
+ * @param profile stream media profile with {@link ImsStreamMediaProfile} to resume the call
+ * @see {@link ImsCallSession.Listener#callSessionResumed},
+ * {@link ImsCallSession.Listener#callSessionResumeFailed}
+ */
+ @Override
+ public void resume(ImsStreamMediaProfile profile) throws RemoteException {
+ }
+
+ /**
+ * Merges the active & hold call. When the merge starts,
+ * {@link ImsCallSession.Listener#callSessionMergeStarted} is called.
+ * {@link ImsCallSession.Listener#callSessionMergeComplete} is called if the merge is
+ * successful, and {@link ImsCallSession.Listener#callSessionMergeFailed} is called if the merge
+ * fails.
+ *
+ * @see {@link ImsCallSession.Listener#callSessionMergeStarted},
+ * {@link ImsCallSession.Listener#callSessionMergeComplete},
+ * {@link ImsCallSession.Listener#callSessionMergeFailed}
+ */
+ @Override
+ public void merge() throws RemoteException {
+ }
+
+ /**
+ * Updates the current call's properties (ex. call mode change: video upgrade / downgrade).
+ *
+ * @param callType call type specified in {@link ImsCallProfile} to be updated
+ * @param profile stream media profile {@link ImsStreamMediaProfile} to be updated
+ * @see {@link ImsCallSession.Listener#callSessionUpdated},
+ * {@link ImsCallSession.Listener#callSessionUpdateFailed}
+ */
+ @Override
+ public void update(int callType, ImsStreamMediaProfile profile) throws RemoteException {
+ }
+
+ /**
+ * Extends this call to the conference call with the specified recipients.
+ *
+ * @param participants participant list to be invited to the conference call after extending the
+ * call
+ * @see {@link ImsCallSession.Listener#callSessionConferenceExtended},
+ * {@link ImsCallSession.Listener#callSessionConferenceExtendFailed}
+ */
+ @Override
+ public void extendToConference(String[] participants) throws RemoteException {
+ }
+
+ /**
+ * Requests the conference server to invite an additional participants to the conference.
+ *
+ * @param participants participant list to be invited to the conference call
+ * @see {@link ImsCallSession.Listener#callSessionInviteParticipantsRequestDelivered},
+ * {@link ImsCallSession.Listener#callSessionInviteParticipantsRequestFailed}
+ */
+ @Override
+ public void inviteParticipants(String[] participants) throws RemoteException {
+ }
+
+ /**
+ * Requests the conference server to remove the specified participants from the conference.
+ *
+ * @param participants participant list to be removed from the conference call
+ * @see {@link ImsCallSession.Listener#callSessionRemoveParticipantsRequestDelivered},
+ * {@link ImsCallSession.Listener#callSessionRemoveParticipantsRequestFailed}
+ */
+ @Override
+ public void removeParticipants(String[] participants) throws RemoteException {
+ }
+
+ /**
+ * Sends a DTMF code. According to <a href="http://tools.ietf.org/html/rfc2833">RFC 2833</a>,
+ * event 0 ~ 9 maps to decimal value 0 ~ 9, '*' to 10, '#' to 11, event 'A' ~ 'D' to 12 ~ 15,
+ * and event flash to 16. Currently, event flash is not supported.
+ *
+ * @param c the DTMF to send. '0' ~ '9', 'A' ~ 'D', '*', '#' are valid inputs.
+ */
+ @Override
+ public void sendDtmf(char c, Message result) throws RemoteException {
+ }
+
+ /**
+ * Start a DTMF code. According to <a href="http://tools.ietf.org/html/rfc2833">RFC 2833</a>,
+ * event 0 ~ 9 maps to decimal value 0 ~ 9, '*' to 10, '#' to 11, event 'A' ~ 'D' to 12 ~ 15,
+ * and event flash to 16. Currently, event flash is not supported.
+ *
+ * @param c the DTMF to send. '0' ~ '9', 'A' ~ 'D', '*', '#' are valid inputs.
+ */
+ @Override
+ public void startDtmf(char c) throws RemoteException {
+ }
+
+ /**
+ * Stop a DTMF code.
+ */
+ @Override
+ public void stopDtmf() throws RemoteException {
+ }
+
+ /**
+ * Sends an USSD message.
+ *
+ * @param ussdMessage USSD message to send
+ */
+ @Override
+ public void sendUssd(String ussdMessage) throws RemoteException {
+ }
+
+ /**
+ * Returns a binder for the video call provider implementation contained within the IMS service
+ * process. This binder is used by the VideoCallProvider subclass in Telephony which
+ * intermediates between the propriety implementation and Telecomm/InCall.
+ */
+ @Override
+ public IImsVideoCallProvider getVideoCallProvider() throws RemoteException {
+ return null;
+ }
+
+ /**
+ * Determines if the current session is multiparty.
+ * @return {@code True} if the session is multiparty.
+ */
+ @Override
+ public boolean isMultiparty() throws RemoteException {
+ return false;
+ }
+}
diff --git a/telephony/java/android/telephony/ims/stub/ImsCallSessionListenerImplBase.java b/telephony/java/android/telephony/ims/stub/ImsCallSessionListenerImplBase.java
new file mode 100644
index 0000000..46f8f80
--- /dev/null
+++ b/telephony/java/android/telephony/ims/stub/ImsCallSessionListenerImplBase.java
@@ -0,0 +1,251 @@
+/*
+ * Copyright (C) 2017 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.telephony.ims.stub;
+
+import com.android.ims.ImsCallProfile;
+import com.android.ims.ImsConferenceState;
+import com.android.ims.ImsReasonInfo;
+import com.android.ims.ImsStreamMediaProfile;
+import com.android.ims.ImsSuppServiceNotification;
+import com.android.ims.internal.IImsCallSession;
+import com.android.ims.internal.IImsCallSessionListener;
+
+/**
+ * Base implementation of ImsCallSessionListenerBase, which implements stub versions of the methods
+ * in the IImsCallSessionListener AIDL. Override the methods that your implementation of
+ * ImsCallSessionListener supports.
+ *
+ * DO NOT remove or change the existing APIs, only add new ones to this Base implementation or you
+ * will break other implementations of ImsCallSessionListener maintained by other ImsServices.
+ *
+ * @hide
+ */
+public class ImsCallSessionListenerImplBase extends IImsCallSessionListener.Stub {
+ /**
+ * Notifies the result of the basic session operation (setup / terminate).
+ */
+ @Override
+ public void callSessionProgressing(IImsCallSession session, ImsStreamMediaProfile profile) {
+ // no-op
+ }
+
+ @Override
+ public void callSessionStarted(IImsCallSession session, ImsCallProfile profile) {
+ // no-op
+ }
+
+ @Override
+ public void callSessionStartFailed(IImsCallSession session, ImsReasonInfo reasonInfo) {
+ // no-op
+ }
+
+ @Override
+ public void callSessionTerminated(IImsCallSession session, ImsReasonInfo reasonInfo) {
+ // no-op
+ }
+
+ /**
+ * Notifies the result of the call hold/resume operation.
+ */
+ @Override
+ public void callSessionHeld(IImsCallSession session, ImsCallProfile profile) {
+ // no-op
+ }
+
+ @Override
+ public void callSessionHoldFailed(IImsCallSession session, ImsReasonInfo reasonInfo) {
+ // no-op
+ }
+
+ @Override
+ public void callSessionHoldReceived(IImsCallSession session, ImsCallProfile profile) {
+ // no-op
+ }
+
+ @Override
+ public void callSessionResumed(IImsCallSession session, ImsCallProfile profile) {
+ // no-op
+ }
+
+ @Override
+ public void callSessionResumeFailed(IImsCallSession session, ImsReasonInfo reasonInfo) {
+ // no-op
+ }
+
+ @Override
+ public void callSessionResumeReceived(IImsCallSession session, ImsCallProfile profile) {
+ // no-op
+ }
+
+ /**
+ * Notifies the result of call merge operation.
+ */
+ @Override
+ public void callSessionMergeStarted(IImsCallSession session, IImsCallSession newSession,
+ ImsCallProfile profile) {
+ // no-op
+ }
+
+ @Override
+ public void callSessionMergeComplete(IImsCallSession session) {
+ // no-op
+ }
+
+ @Override
+ public void callSessionMergeFailed(IImsCallSession session, ImsReasonInfo reasonInfo) {
+ // no-op
+ }
+
+ /**
+ * Notifies the result of call upgrade / downgrade or any other call
+ * updates.
+ */
+ @Override
+ public void callSessionUpdated(IImsCallSession session, ImsCallProfile profile) {
+ // no-op
+ }
+
+ @Override
+ public void callSessionUpdateFailed(IImsCallSession session, ImsReasonInfo reasonInfo) {
+ // no-op
+ }
+
+ @Override
+ public void callSessionUpdateReceived(IImsCallSession session, ImsCallProfile profile) {
+ // no-op
+ }
+
+ /**
+ * Notifies the result of conference extension.
+ */
+ @Override
+ public void callSessionConferenceExtended(IImsCallSession session, IImsCallSession newSession,
+ ImsCallProfile profile) {
+ // no-op
+ }
+
+ @Override
+ public void callSessionConferenceExtendFailed(IImsCallSession session,
+ ImsReasonInfo reasonInfo) {
+ // no-op
+ }
+
+ @Override
+ public void callSessionConferenceExtendReceived(IImsCallSession session,
+ IImsCallSession newSession,
+ ImsCallProfile profile) {
+ // no-op
+ }
+
+ /**
+ * Notifies the result of the participant invitation / removal to/from the
+ * conference session.
+ */
+ @Override
+ public void callSessionInviteParticipantsRequestDelivered(IImsCallSession session) {
+ // no-op
+ }
+
+ @Override
+ public void callSessionInviteParticipantsRequestFailed(IImsCallSession session,
+ ImsReasonInfo reasonInfo) {
+ // no-op
+ }
+
+ @Override
+ public void callSessionRemoveParticipantsRequestDelivered(IImsCallSession session) {
+ // no-op
+ }
+
+ @Override
+ public void callSessionRemoveParticipantsRequestFailed(IImsCallSession session,
+ ImsReasonInfo reasonInfo) {
+ // no-op
+ }
+
+ /**
+ * Notifies the changes of the conference info. the conference session.
+ */
+ @Override
+ public void callSessionConferenceStateUpdated(IImsCallSession session,
+ ImsConferenceState state) {
+ // no-op
+ }
+
+ /**
+ * Notifies the incoming USSD message.
+ */
+ @Override
+ public void callSessionUssdMessageReceived(IImsCallSession session, int mode,
+ String ussdMessage) {
+ // no-op
+ }
+
+ /**
+ * Notifies of handover information for this call
+ */
+ @Override
+ public void callSessionHandover(IImsCallSession session, int srcAccessTech,
+ int targetAccessTech,
+ ImsReasonInfo reasonInfo) {
+ // no-op
+ }
+
+ @Override
+ public void callSessionHandoverFailed(IImsCallSession session, int srcAccessTech,
+ int targetAccessTech,
+ ImsReasonInfo reasonInfo) {
+ // no-op
+ }
+
+ /**
+ * Notifies the TTY mode change by remote party.
+ *
+ * @param mode one of the following: -
+ * {@link com.android.internal.telephony.Phone#TTY_MODE_OFF} -
+ * {@link com.android.internal.telephony.Phone#TTY_MODE_FULL} -
+ * {@link com.android.internal.telephony.Phone#TTY_MODE_HCO} -
+ * {@link com.android.internal.telephony.Phone#TTY_MODE_VCO}
+ */
+ @Override
+ public void callSessionTtyModeReceived(IImsCallSession session, int mode) {
+ // no-op
+ }
+
+ /**
+ * Notifies of a change to the multiparty state for this
+ * {@code ImsCallSession}.
+ *
+ * @param session The call session.
+ * @param isMultiParty {@code true} if the session became multiparty,
+ * {@code false} otherwise.
+ */
+ @Override
+ public void callSessionMultipartyStateChanged(IImsCallSession session, boolean isMultiParty) {
+ // no-op
+ }
+
+ /**
+ * Notifies the supplementary service information for the current session.
+ */
+ @Override
+ public void callSessionSuppServiceReceived(IImsCallSession session,
+ ImsSuppServiceNotification suppSrvNotification) {
+ // no-op
+ }
+}
+
diff --git a/telephony/java/android/telephony/ims/stub/ImsConfigImplBase.java b/telephony/java/android/telephony/ims/stub/ImsConfigImplBase.java
new file mode 100644
index 0000000..5a4db99
--- /dev/null
+++ b/telephony/java/android/telephony/ims/stub/ImsConfigImplBase.java
@@ -0,0 +1,150 @@
+/*
+ * Copyright (C) 2017 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.telephony.ims.stub;
+
+import android.os.RemoteException;
+
+import com.android.ims.ImsConfig;
+import com.android.ims.ImsConfigListener;
+import com.android.ims.internal.IImsConfig;
+
+/**
+ * Base implementation of ImsConfig, which implements stub versions of the methods
+ * in the IImsConfig AIDL. Override the methods that your implementation of ImsConfig supports.
+ *
+ * DO NOT remove or change the existing APIs, only add new ones to this Base implementation or you
+ * will break other implementations of ImsConfig maintained by other ImsServices.
+ *
+ * Provides APIs to get/set the IMS service feature/capability/parameters.
+ * The config items include:
+ * 1) Items provisioned by the operator.
+ * 2) Items configured by user. Mainly service feature class.
+ *
+ * @hide
+ */
+
+public class ImsConfigImplBase extends IImsConfig.Stub {
+
+ /**
+ * Gets the value for ims service/capabilities parameters from the provisioned
+ * value storage. Synchronous blocking call.
+ *
+ * @param item, as defined in com.android.ims.ImsConfig#ConfigConstants.
+ * @return value in Integer format.
+ */
+ @Override
+ public int getProvisionedValue(int item) throws RemoteException {
+ return -1;
+ }
+
+ /**
+ * Gets the value for ims service/capabilities parameters from the provisioned
+ * value storage. Synchronous blocking call.
+ *
+ * @param item, as defined in com.android.ims.ImsConfig#ConfigConstants.
+ * @return value in String format.
+ */
+ @Override
+ public String getProvisionedStringValue(int item) throws RemoteException {
+ return null;
+ }
+
+ /**
+ * Sets the value for IMS service/capabilities parameters by the operator device
+ * management entity. It sets the config item value in the provisioned storage
+ * from which the master value is derived. Synchronous blocking call.
+ *
+ * @param item, as defined in com.android.ims.ImsConfig#ConfigConstants.
+ * @param value in Integer format.
+ * @return as defined in com.android.ims.ImsConfig#OperationStatusConstants.
+ */
+ @Override
+ public int setProvisionedValue(int item, int value) throws RemoteException {
+ return ImsConfig.OperationStatusConstants.FAILED;
+ }
+
+ /**
+ * Sets the value for IMS service/capabilities parameters by the operator device
+ * management entity. It sets the config item value in the provisioned storage
+ * from which the master value is derived. Synchronous blocking call.
+ *
+ * @param item as defined in com.android.ims.ImsConfig#ConfigConstants.
+ * @param value in String format.
+ * @return as defined in com.android.ims.ImsConfig#OperationStatusConstants.
+ */
+ @Override
+ public int setProvisionedStringValue(int item, String value) throws RemoteException {
+ return ImsConfig.OperationStatusConstants.FAILED;
+ }
+
+ /**
+ * Gets the value of the specified IMS feature item for specified network type.
+ * This operation gets the feature config value from the master storage (i.e. final
+ * value). Asynchronous non-blocking call.
+ *
+ * @param feature as defined in com.android.ims.ImsConfig#FeatureConstants.
+ * @param network as defined in android.telephony.TelephonyManager#NETWORK_TYPE_XXX.
+ * @param listener feature value returned asynchronously through listener.
+ */
+ @Override
+ public void getFeatureValue(int feature, int network, ImsConfigListener listener)
+ throws RemoteException {
+ }
+
+ /**
+ * Sets the value for IMS feature item for specified network type.
+ * This operation stores the user setting in setting db from which master db
+ * is derived.
+ *
+ * @param feature as defined in com.android.ims.ImsConfig#FeatureConstants.
+ * @param network as defined in android.telephony.TelephonyManager#NETWORK_TYPE_XXX.
+ * @param value as defined in com.android.ims.ImsConfig#FeatureValueConstants.
+ * @param listener, provided if caller needs to be notified for set result.
+ */
+ @Override
+ public void setFeatureValue(int feature, int network, int value, ImsConfigListener listener)
+ throws RemoteException {
+ }
+
+ /**
+ * Gets the value for IMS VoLTE provisioned.
+ * This should be the same as the operator provisioned value if applies.
+ */
+ @Override
+ public boolean getVolteProvisioned() throws RemoteException {
+ return false;
+ }
+
+ /**
+ * Gets the value for IMS feature item video quality.
+ *
+ * @param listener Video quality value returned asynchronously through listener.
+ */
+ @Override
+ public void getVideoQuality(ImsConfigListener listener) throws RemoteException {
+ }
+
+ /**
+ * Sets the value for IMS feature item video quality.
+ *
+ * @param quality, defines the value of video quality.
+ * @param listener, provided if caller needs to be notified for set result.
+ */
+ @Override
+ public void setVideoQuality(int quality, ImsConfigListener listener) throws RemoteException {
+ }
+}
diff --git a/telephony/java/android/telephony/ims/stub/ImsEcbmImplBase.java b/telephony/java/android/telephony/ims/stub/ImsEcbmImplBase.java
new file mode 100644
index 0000000..89f95ff
--- /dev/null
+++ b/telephony/java/android/telephony/ims/stub/ImsEcbmImplBase.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2017 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.telephony.ims.stub;
+
+import android.os.RemoteException;
+
+import com.android.ims.internal.IImsEcbm;
+import com.android.ims.internal.IImsEcbmListener;
+
+/**
+ * Base implementation of ImsEcbm, which implements stub versions of the methods
+ * in the IImsEcbm AIDL. Override the methods that your implementation of ImsEcbm supports.
+ *
+ * DO NOT remove or change the existing APIs, only add new ones to this Base implementation or you
+ * will break other implementations of ImsEcbm maintained by other ImsServices.
+ *
+ * @hide
+ */
+
+public class ImsEcbmImplBase extends IImsEcbm.Stub {
+
+ /**
+ * Sets the listener.
+ */
+ @Override
+ public void setListener(IImsEcbmListener listener) throws RemoteException {
+
+ }
+
+ /**
+ * Requests Modem to come out of ECBM mode
+ */
+ @Override
+ public void exitEmergencyCallbackMode() throws RemoteException {
+
+ }
+}
diff --git a/telephony/java/android/telephony/ims/stub/ImsMultiEndpointImplBase.java b/telephony/java/android/telephony/ims/stub/ImsMultiEndpointImplBase.java
new file mode 100644
index 0000000..05da9da
--- /dev/null
+++ b/telephony/java/android/telephony/ims/stub/ImsMultiEndpointImplBase.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2017 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.telephony.ims.stub;
+
+import android.os.RemoteException;
+
+import com.android.ims.internal.IImsExternalCallStateListener;
+import com.android.ims.internal.IImsMultiEndpoint;
+
+/**
+ * Base implementation of ImsMultiEndpoint, which implements stub versions of the methods
+ * in the IImsMultiEndpoint AIDL. Override the methods that your implementation of
+ * ImsMultiEndpoint supports.
+ *
+ * DO NOT remove or change the existing APIs, only add new ones to this Base implementation or you
+ * will break other implementations of ImsMultiEndpoint maintained by other ImsServices.
+ *
+ * @hide
+ */
+
+public class ImsMultiEndpointImplBase extends IImsMultiEndpoint.Stub {
+
+ /**
+ * Sets the listener.
+ */
+ @Override
+ public void setListener(IImsExternalCallStateListener listener) throws RemoteException {
+
+ }
+
+ /**
+ * Query API to get the latest Dialog Event Package information
+ * Should be invoked only after setListener is done
+ */
+ @Override
+ public void requestImsExternalCallStateInfo() throws RemoteException {
+
+ }
+}
diff --git a/telephony/java/android/telephony/ims/stub/ImsStreamMediaSessionImplBase.java b/telephony/java/android/telephony/ims/stub/ImsStreamMediaSessionImplBase.java
new file mode 100644
index 0000000..92f1a01
--- /dev/null
+++ b/telephony/java/android/telephony/ims/stub/ImsStreamMediaSessionImplBase.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2017 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.telephony.ims.stub;
+
+import android.os.RemoteException;
+
+import com.android.ims.internal.IImsStreamMediaSession;
+
+/**
+ * Base implementation of ImsStreamMediaSession, which implements stub versions of the methods
+ * in the IImsStreamMediaSession AIDL. Override the methods that your implementation of
+ * ImsStreamMediaSession supports.
+ *
+ * DO NOT remove or change the existing APIs, only add new ones to this Base implementation or you
+ * will break other implementations of ImsStreamMediaSession maintained by other ImsServices.
+ *
+ * @hide
+ */
+
+public class ImsStreamMediaSessionImplBase extends IImsStreamMediaSession.Stub {
+
+ @Override
+ public void close() throws RemoteException {
+
+ }
+}
diff --git a/telephony/java/android/telephony/ims/stub/ImsUtImplBase.java b/telephony/java/android/telephony/ims/stub/ImsUtImplBase.java
new file mode 100644
index 0000000..dc74094
--- /dev/null
+++ b/telephony/java/android/telephony/ims/stub/ImsUtImplBase.java
@@ -0,0 +1,174 @@
+/*
+ * Copyright (C) 2017 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.telephony.ims.stub;
+
+import android.os.Bundle;
+import android.os.RemoteException;
+
+import com.android.ims.internal.IImsUt;
+import com.android.ims.internal.IImsUtListener;
+
+/**
+ * Base implementation of ImsUt, which implements stub versions of the methods
+ * in the IImsUt AIDL. Override the methods that your implementation of ImsUt supports.
+ *
+ * DO NOT remove or change the existing APIs, only add new ones to this Base implementation or you
+ * will break other implementations of ImsUt maintained by other ImsServices.
+ *
+ * Provides the Ut interface interworking to get/set the supplementary service configuration.
+ *
+ * @hide
+ */
+
+public class ImsUtImplBase extends IImsUt.Stub {
+
+ /**
+ * Closes the object. This object is not usable after being closed.
+ */
+ @Override
+ public void close() throws RemoteException {
+
+ }
+
+ /**
+ * Retrieves the configuration of the call barring.
+ */
+ @Override
+ public int queryCallBarring(int cbType) throws RemoteException {
+ return -1;
+ }
+
+ /**
+ * Retrieves the configuration of the call forward.
+ */
+ @Override
+ public int queryCallForward(int condition, String number) throws RemoteException {
+ return -1;
+ }
+
+ /**
+ * Retrieves the configuration of the call waiting.
+ */
+ @Override
+ public int queryCallWaiting() throws RemoteException {
+ return -1;
+ }
+
+ /**
+ * Retrieves the default CLIR setting.
+ */
+ @Override
+ public int queryCLIR() throws RemoteException {
+ return -1;
+ }
+
+ /**
+ * Retrieves the CLIP call setting.
+ */
+ @Override
+ public int queryCLIP() throws RemoteException {
+ return -1;
+ }
+
+ /**
+ * Retrieves the COLR call setting.
+ */
+ @Override
+ public int queryCOLR() throws RemoteException {
+ return -1;
+ }
+
+ /**
+ * Retrieves the COLP call setting.
+ */
+ @Override
+ public int queryCOLP() throws RemoteException {
+ return -1;
+ }
+
+ /**
+ * Updates or retrieves the supplementary service configuration.
+ */
+ @Override
+ public int transact(Bundle ssInfo) throws RemoteException {
+ return -1;
+ }
+
+ /**
+ * Updates the configuration of the call barring.
+ */
+ @Override
+ public int updateCallBarring(int cbType, int action, String[] barrList) throws RemoteException {
+ return -1;
+ }
+
+ /**
+ * Updates the configuration of the call forward.
+ */
+ @Override
+ public int updateCallForward(int action, int condition, String number, int serviceClass,
+ int timeSeconds) throws RemoteException {
+ return 0;
+ }
+
+ /**
+ * Updates the configuration of the call waiting.
+ */
+ @Override
+ public int updateCallWaiting(boolean enable, int serviceClass) throws RemoteException {
+ return -1;
+ }
+
+ /**
+ * Updates the configuration of the CLIR supplementary service.
+ */
+ @Override
+ public int updateCLIR(int clirMode) throws RemoteException {
+ return -1;
+ }
+
+ /**
+ * Updates the configuration of the CLIP supplementary service.
+ */
+ @Override
+ public int updateCLIP(boolean enable) throws RemoteException {
+ return -1;
+ }
+
+ /**
+ * Updates the configuration of the COLR supplementary service.
+ */
+ @Override
+ public int updateCOLR(int presentation) throws RemoteException {
+ return -1;
+ }
+
+ /**
+ * Updates the configuration of the COLP supplementary service.
+ */
+ @Override
+ public int updateCOLP(boolean enable) throws RemoteException {
+ return -1;
+ }
+
+ /**
+ * Sets the listener.
+ */
+ @Override
+ public void setListener(IImsUtListener listener) throws RemoteException {
+ }
+}
diff --git a/telephony/java/android/telephony/ims/stub/ImsUtListenerImplBase.java b/telephony/java/android/telephony/ims/stub/ImsUtListenerImplBase.java
new file mode 100644
index 0000000..b371efb
--- /dev/null
+++ b/telephony/java/android/telephony/ims/stub/ImsUtListenerImplBase.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2017 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.telephony.ims.stub;
+
+import android.os.Bundle;
+import android.os.RemoteException;
+
+import com.android.ims.ImsCallForwardInfo;
+import com.android.ims.ImsReasonInfo;
+import com.android.ims.ImsSsInfo;
+import com.android.ims.internal.IImsUt;
+import com.android.ims.internal.IImsUtListener;
+
+/**
+ * Base implementation of ImsUtListener, which implements stub versions of the methods
+ * in the IImsUtListener AIDL. Override the methods that your implementation of
+ * ImsUtListener supports.
+ *
+ * DO NOT remove or change the existing APIs, only add new ones to this Base implementation or you
+ * will break other implementations of ImsUtListener maintained by other ImsServices.
+ *
+ * @hide
+ */
+
+public class ImsUtListenerImplBase extends IImsUtListener.Stub {
+
+ /**
+ * Notifies the result of the supplementary service configuration udpate.
+ */
+ @Override
+ public void utConfigurationUpdated(IImsUt ut, int id) throws RemoteException {
+ }
+
+ @Override
+ public void utConfigurationUpdateFailed(IImsUt ut, int id, ImsReasonInfo error)
+ throws RemoteException {
+ }
+
+ /**
+ * Notifies the result of the supplementary service configuration query.
+ */
+ @Override
+ public void utConfigurationQueried(IImsUt ut, int id, Bundle ssInfo) throws RemoteException {
+ }
+
+ @Override
+ public void utConfigurationQueryFailed(IImsUt ut, int id, ImsReasonInfo error)
+ throws RemoteException {
+ }
+
+ /**
+ * Notifies the status of the call barring supplementary service.
+ */
+ @Override
+ public void utConfigurationCallBarringQueried(IImsUt ut, int id, ImsSsInfo[] cbInfo)
+ throws RemoteException {
+ }
+
+ /**
+ * Notifies the status of the call forwarding supplementary service.
+ */
+ @Override
+ public void utConfigurationCallForwardQueried(IImsUt ut, int id, ImsCallForwardInfo[] cfInfo)
+ throws RemoteException {
+ }
+
+ /**
+ * Notifies the status of the call waiting supplementary service.
+ */
+ @Override
+ public void utConfigurationCallWaitingQueried(IImsUt ut, int id, ImsSsInfo[] cwInfo)
+ throws RemoteException {
+ }
+}
diff --git a/telephony/java/com/android/ims/ImsConfig.java b/telephony/java/com/android/ims/ImsConfig.java
new file mode 100644
index 0000000..cd076b1
--- /dev/null
+++ b/telephony/java/com/android/ims/ImsConfig.java
@@ -0,0 +1,694 @@
+/*
+ * Copyright (C) 2017 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.ims;
+
+import android.content.Context;
+import android.os.RemoteException;
+import android.telephony.Rlog;
+
+import com.android.ims.internal.IImsConfig;
+
+/**
+ * Provides APIs to get/set the IMS service feature/capability/parameters.
+ * The config items include:
+ * 1) Items provisioned by the operator.
+ * 2) Items configured by user. Mainly service feature class.
+ *
+ * @hide
+ */
+public class ImsConfig {
+ private static final String TAG = "ImsConfig";
+ private boolean DBG = true;
+ private final IImsConfig miConfig;
+ private Context mContext;
+
+ /**
+ * Broadcast action: the feature enable status was changed
+ *
+ * @hide
+ */
+ public static final String ACTION_IMS_FEATURE_CHANGED =
+ "com.android.intent.action.IMS_FEATURE_CHANGED";
+
+ /**
+ * Broadcast action: the configuration was changed
+ *
+ * @hide
+ */
+ public static final String ACTION_IMS_CONFIG_CHANGED =
+ "com.android.intent.action.IMS_CONFIG_CHANGED";
+
+ /**
+ * Extra parameter "item" of intent ACTION_IMS_FEATURE_CHANGED and ACTION_IMS_CONFIG_CHANGED.
+ * It is the value of FeatureConstants or ConfigConstants.
+ *
+ * @hide
+ */
+ public static final String EXTRA_CHANGED_ITEM = "item";
+
+ /**
+ * Extra parameter "value" of intent ACTION_IMS_FEATURE_CHANGED and ACTION_IMS_CONFIG_CHANGED.
+ * It is the new value of "item".
+ *
+ * @hide
+ */
+ public static final String EXTRA_NEW_VALUE = "value";
+
+ /**
+ * Defines IMS service/capability feature constants.
+ */
+ public static class FeatureConstants {
+ public static final int FEATURE_TYPE_UNKNOWN = -1;
+
+ /**
+ * FEATURE_TYPE_VOLTE supports features defined in 3GPP and
+ * GSMA IR.92 over LTE.
+ */
+ public static final int FEATURE_TYPE_VOICE_OVER_LTE = 0;
+
+ /**
+ * FEATURE_TYPE_LVC supports features defined in 3GPP and
+ * GSMA IR.94 over LTE.
+ */
+ public static final int FEATURE_TYPE_VIDEO_OVER_LTE = 1;
+
+ /**
+ * FEATURE_TYPE_VOICE_OVER_WIFI supports features defined in 3GPP and
+ * GSMA IR.92 over WiFi.
+ */
+ public static final int FEATURE_TYPE_VOICE_OVER_WIFI = 2;
+
+ /**
+ * FEATURE_TYPE_VIDEO_OVER_WIFI supports features defined in 3GPP and
+ * GSMA IR.94 over WiFi.
+ */
+ public static final int FEATURE_TYPE_VIDEO_OVER_WIFI = 3;
+
+ /**
+ * FEATURE_TYPE_UT supports features defined in 3GPP and
+ * GSMA IR.92 over LTE.
+ */
+ public static final int FEATURE_TYPE_UT_OVER_LTE = 4;
+
+ /**
+ * FEATURE_TYPE_UT_OVER_WIFI supports features defined in 3GPP and
+ * GSMA IR.92 over WiFi.
+ */
+ public static final int FEATURE_TYPE_UT_OVER_WIFI = 5;
+ }
+
+ /**
+ * Defines IMS service/capability parameters.
+ */
+ public static class ConfigConstants {
+
+ // Define IMS config items
+ public static final int CONFIG_START = 0;
+
+ // Define operator provisioned config items
+ public static final int PROVISIONED_CONFIG_START = CONFIG_START;
+
+ /**
+ * AMR CODEC Mode Value set, 0-7 in comma separated sequence.
+ * Value is in String format.
+ */
+ public static final int VOCODER_AMRMODESET = CONFIG_START;
+
+ /**
+ * Wide Band AMR CODEC Mode Value set,0-7 in comma separated sequence.
+ * Value is in String format.
+ */
+ public static final int VOCODER_AMRWBMODESET = 1;
+
+ /**
+ * SIP Session Timer value (seconds).
+ * Value is in Integer format.
+ */
+ public static final int SIP_SESSION_TIMER = 2;
+
+ /**
+ * Minimum SIP Session Expiration Timer in (seconds).
+ * Value is in Integer format.
+ */
+ public static final int MIN_SE = 3;
+
+ /**
+ * SIP_INVITE cancellation time out value (in milliseconds). Integer format.
+ * Value is in Integer format.
+ */
+ public static final int CANCELLATION_TIMER = 4;
+
+ /**
+ * Delay time when an iRAT transition from eHRPD/HRPD/1xRTT to LTE.
+ * Value is in Integer format.
+ */
+ public static final int TDELAY = 5;
+
+ /**
+ * Silent redial status of Enabled (True), or Disabled (False).
+ * Value is in Integer format.
+ */
+ public static final int SILENT_REDIAL_ENABLE = 6;
+
+ /**
+ * SIP T1 timer value in milliseconds. See RFC 3261 for define.
+ * Value is in Integer format.
+ */
+ public static final int SIP_T1_TIMER = 7;
+
+ /**
+ * SIP T2 timer value in milliseconds. See RFC 3261 for define.
+ * Value is in Integer format.
+ */
+ public static final int SIP_T2_TIMER = 8;
+
+ /**
+ * SIP TF timer value in milliseconds. See RFC 3261 for define.
+ * Value is in Integer format.
+ */
+ public static final int SIP_TF_TIMER = 9;
+
+ /**
+ * VoLTE status for VLT/s status of Enabled (1), or Disabled (0).
+ * Value is in Integer format.
+ */
+ public static final int VLT_SETTING_ENABLED = 10;
+
+ /**
+ * VoLTE status for LVC/s status of Enabled (1), or Disabled (0).
+ * Value is in Integer format.
+ */
+ public static final int LVC_SETTING_ENABLED = 11;
+ /**
+ * Domain Name for the device to populate the request URI for REGISTRATION.
+ * Value is in String format.
+ */
+ public static final int DOMAIN_NAME = 12;
+ /**
+ * Device Outgoing SMS based on either 3GPP or 3GPP2 standards.
+ * Value is in Integer format. 3GPP2(0), 3GPP(1)
+ */
+ public static final int SMS_FORMAT = 13;
+ /**
+ * Turns IMS ON/OFF on the device.
+ * Value is in Integer format. ON (1), OFF(0).
+ */
+ public static final int SMS_OVER_IP = 14;
+ /**
+ * Requested expiration for Published Online availability.
+ * Value is in Integer format.
+ */
+ public static final int PUBLISH_TIMER = 15;
+ /**
+ * Requested expiration for Published Offline availability.
+ * Value is in Integer format.
+ */
+ public static final int PUBLISH_TIMER_EXTENDED = 16;
+ /**
+ *
+ * Value is in Integer format.
+ */
+ public static final int CAPABILITY_DISCOVERY_ENABLED = 17;
+ /**
+ * Period of time the capability information of the contact is cached on handset.
+ * Value is in Integer format.
+ */
+ public static final int CAPABILITIES_CACHE_EXPIRATION = 18;
+ /**
+ * Peiod of time the availability information of a contact is cached on device.
+ * Value is in Integer format.
+ */
+ public static final int AVAILABILITY_CACHE_EXPIRATION = 19;
+ /**
+ * Interval between successive capabilities polling.
+ * Value is in Integer format.
+ */
+ public static final int CAPABILITIES_POLL_INTERVAL = 20;
+ /**
+ * Minimum time between two published messages from the device.
+ * Value is in Integer format.
+ */
+ public static final int SOURCE_THROTTLE_PUBLISH = 21;
+ /**
+ * The Maximum number of MDNs contained in one Request Contained List.
+ * Value is in Integer format.
+ */
+ public static final int MAX_NUMENTRIES_IN_RCL = 22;
+ /**
+ * Expiration timer for subscription of a Request Contained List, used in capability
+ * polling.
+ * Value is in Integer format.
+ */
+ public static final int CAPAB_POLL_LIST_SUB_EXP = 23;
+ /**
+ * Applies compression to LIST Subscription.
+ * Value is in Integer format. Enable (1), Disable(0).
+ */
+ public static final int GZIP_FLAG = 24;
+ /**
+ * VOLTE Status for EAB/s status of Enabled (1), or Disabled (0).
+ * Value is in Integer format.
+ */
+ public static final int EAB_SETTING_ENABLED = 25;
+ /**
+ * Wi-Fi calling roaming status.
+ * Value is in Integer format. ON (1), OFF(0).
+ */
+ public static final int VOICE_OVER_WIFI_ROAMING = 26;
+ /**
+ * Wi-Fi calling modem - WfcModeFeatureValueConstants.
+ * Value is in Integer format.
+ */
+ public static final int VOICE_OVER_WIFI_MODE = 27;
+ /**
+ * VOLTE Status for voice over wifi status of Enabled (1), or Disabled (0).
+ * Value is in Integer format.
+ */
+ public static final int VOICE_OVER_WIFI_SETTING_ENABLED = 28;
+ /**
+ * Mobile data enabled.
+ * Value is in Integer format. On (1), OFF(0).
+ */
+ public static final int MOBILE_DATA_ENABLED = 29;
+ /**
+ * VoLTE user opted in status.
+ * Value is in Integer format. Opted-in (1) Opted-out (0).
+ */
+ public static final int VOLTE_USER_OPT_IN_STATUS = 30;
+ /**
+ * Proxy for Call Session Control Function(P-CSCF) address for Local-BreakOut(LBO).
+ * Value is in String format.
+ */
+ public static final int LBO_PCSCF_ADDRESS = 31;
+ /**
+ * Keep Alive Enabled for SIP.
+ * Value is in Integer format. On(1), OFF(0).
+ */
+ public static final int KEEP_ALIVE_ENABLED = 32;
+ /**
+ * Registration retry Base Time value in seconds.
+ * Value is in Integer format.
+ */
+ public static final int REGISTRATION_RETRY_BASE_TIME_SEC = 33;
+ /**
+ * Registration retry Max Time value in seconds.
+ * Value is in Integer format.
+ */
+ public static final int REGISTRATION_RETRY_MAX_TIME_SEC = 34;
+ /**
+ * Smallest RTP port for speech codec.
+ * Value is in integer format.
+ */
+ public static final int SPEECH_START_PORT = 35;
+ /**
+ * Largest RTP port for speech code.
+ * Value is in Integer format.
+ */
+ public static final int SPEECH_END_PORT = 36;
+ /**
+ * SIP Timer A's value in milliseconds. Timer A is the INVITE request
+ * retransmit interval, for UDP only.
+ * Value is in Integer format.
+ */
+ public static final int SIP_INVITE_REQ_RETX_INTERVAL_MSEC = 37;
+ /**
+ * SIP Timer B's value in milliseconds. Timer B is the wait time for
+ * INVITE message to be acknowledged.
+ * Value is in Integer format.
+ */
+ public static final int SIP_INVITE_RSP_WAIT_TIME_MSEC = 38;
+ /**
+ * SIP Timer D's value in milliseconds. Timer D is the wait time for
+ * response retransmits of the invite client transactions.
+ * Value is in Integer format.
+ */
+ public static final int SIP_INVITE_RSP_RETX_WAIT_TIME_MSEC = 39;
+ /**
+ * SIP Timer E's value in milliseconds. Timer E is the value Non-INVITE
+ * request retransmit interval, for UDP only.
+ * Value is in Integer format.
+ */
+ public static final int SIP_NON_INVITE_REQ_RETX_INTERVAL_MSEC = 40;
+ /**
+ * SIP Timer F's value in milliseconds. Timer F is the Non-INVITE transaction
+ * timeout timer.
+ * Value is in Integer format.
+ */
+ public static final int SIP_NON_INVITE_TXN_TIMEOUT_TIMER_MSEC = 41;
+ /**
+ * SIP Timer G's value in milliseconds. Timer G is the value of INVITE response
+ * retransmit interval.
+ * Value is in Integer format.
+ */
+ public static final int SIP_INVITE_RSP_RETX_INTERVAL_MSEC = 42;
+ /**
+ * SIP Timer H's value in milliseconds. Timer H is the value of wait time for
+ * ACK receipt.
+ * Value is in Integer format.
+ */
+ public static final int SIP_ACK_RECEIPT_WAIT_TIME_MSEC = 43;
+ /**
+ * SIP Timer I's value in milliseconds. Timer I is the value of wait time for
+ * ACK retransmits.
+ * Value is in Integer format.
+ */
+ public static final int SIP_ACK_RETX_WAIT_TIME_MSEC = 44;
+ /**
+ * SIP Timer J's value in milliseconds. Timer J is the value of wait time for
+ * non-invite request retransmission.
+ * Value is in Integer format.
+ */
+ public static final int SIP_NON_INVITE_REQ_RETX_WAIT_TIME_MSEC = 45;
+ /**
+ * SIP Timer K's value in milliseconds. Timer K is the value of wait time for
+ * non-invite response retransmits.
+ * Value is in Integer format.
+ */
+ public static final int SIP_NON_INVITE_RSP_RETX_WAIT_TIME_MSEC = 46;
+ /**
+ * AMR WB octet aligned dynamic payload type.
+ * Value is in Integer format.
+ */
+ public static final int AMR_WB_OCTET_ALIGNED_PT = 47;
+ /**
+ * AMR WB bandwidth efficient payload type.
+ * Value is in Integer format.
+ */
+ public static final int AMR_WB_BANDWIDTH_EFFICIENT_PT = 48;
+ /**
+ * AMR octet aligned dynamic payload type.
+ * Value is in Integer format.
+ */
+ public static final int AMR_OCTET_ALIGNED_PT = 49;
+ /**
+ * AMR bandwidth efficient payload type.
+ * Value is in Integer format.
+ */
+ public static final int AMR_BANDWIDTH_EFFICIENT_PT = 50;
+ /**
+ * DTMF WB payload type.
+ * Value is in Integer format.
+ */
+ public static final int DTMF_WB_PT = 51;
+ /**
+ * DTMF NB payload type.
+ * Value is in Integer format.
+ */
+ public static final int DTMF_NB_PT = 52;
+ /**
+ * AMR Default encoding mode.
+ * Value is in Integer format.
+ */
+ public static final int AMR_DEFAULT_MODE = 53;
+ /**
+ * SMS Public Service Identity.
+ * Value is in String format.
+ */
+ public static final int SMS_PSI = 54;
+ /**
+ * Video Quality - VideoQualityFeatureValuesConstants.
+ * Value is in Integer format.
+ */
+ public static final int VIDEO_QUALITY = 55;
+ /**
+ * LTE threshold.
+ * Handover from LTE to WiFi if LTE < THLTE1 and WiFi >= VOWT_A.
+ */
+ public static final int TH_LTE1 = 56;
+ /**
+ * LTE threshold.
+ * Handover from WiFi to LTE if LTE >= THLTE3 or (WiFi < VOWT_B and LTE >= THLTE2).
+ */
+ public static final int TH_LTE2 = 57;
+ /**
+ * LTE threshold.
+ * Handover from WiFi to LTE if LTE >= THLTE3 or (WiFi < VOWT_B and LTE >= THLTE2).
+ */
+ public static final int TH_LTE3 = 58;
+ /**
+ * 1x threshold.
+ * Handover from 1x to WiFi if 1x < TH1x
+ */
+ public static final int TH_1x = 59;
+ /**
+ * WiFi threshold.
+ * Handover from LTE to WiFi if LTE < THLTE1 and WiFi >= VOWT_A.
+ */
+ public static final int VOWT_A = 60;
+ /**
+ * WiFi threshold.
+ * Handover from WiFi to LTE if LTE >= THLTE3 or (WiFi < VOWT_B and LTE >= THLTE2).
+ */
+ public static final int VOWT_B = 61;
+ /**
+ * LTE ePDG timer.
+ * Device shall not handover back to LTE until the T_ePDG_LTE timer expires.
+ */
+ public static final int T_EPDG_LTE = 62;
+ /**
+ * WiFi ePDG timer.
+ * Device shall not handover back to WiFi until the T_ePDG_WiFi timer expires.
+ */
+ public static final int T_EPDG_WIFI = 63;
+ /**
+ * 1x ePDG timer.
+ * Device shall not re-register on 1x until the T_ePDG_1x timer expires.
+ */
+ public static final int T_EPDG_1X = 64;
+ /**
+ * MultiEndpoint status: Enabled (1), or Disabled (0).
+ * Value is in Integer format.
+ */
+ public static final int VICE_SETTING_ENABLED = 65;
+
+ // Expand the operator config items as needed here, need to change
+ // PROVISIONED_CONFIG_END after that.
+ public static final int PROVISIONED_CONFIG_END = VICE_SETTING_ENABLED;
+
+ // Expand the operator config items as needed here.
+ }
+
+ /**
+ * Defines IMS set operation status.
+ */
+ public static class OperationStatusConstants {
+ public static final int UNKNOWN = -1;
+ public static final int SUCCESS = 0;
+ public static final int FAILED = 1;
+ public static final int UNSUPPORTED_CAUSE_NONE = 2;
+ public static final int UNSUPPORTED_CAUSE_RAT = 3;
+ public static final int UNSUPPORTED_CAUSE_DISABLED = 4;
+ }
+
+ /**
+ * Defines IMS get operation values.
+ */
+ public static class OperationValuesConstants {
+ /**
+ * Values related to Video Quality
+ */
+ public static final int VIDEO_QUALITY_UNKNOWN = -1;
+ public static final int VIDEO_QUALITY_LOW = 0;
+ public static final int VIDEO_QUALITY_HIGH = 1;
+ }
+
+ /**
+ * Defines IMS video quality feature value.
+ */
+ public static class VideoQualityFeatureValuesConstants {
+ public static final int LOW = 0;
+ public static final int HIGH = 1;
+ }
+
+ /**
+ * Defines IMS feature value.
+ */
+ public static class FeatureValueConstants {
+ public static final int OFF = 0;
+ public static final int ON = 1;
+ }
+
+ /**
+ * Defines IMS feature value.
+ */
+ public static class WfcModeFeatureValueConstants {
+ public static final int WIFI_ONLY = 0;
+ public static final int CELLULAR_PREFERRED = 1;
+ public static final int WIFI_PREFERRED = 2;
+ }
+
+ public ImsConfig(IImsConfig iconfig, Context context) {
+ if (DBG) Rlog.d(TAG, "ImsConfig creates");
+ miConfig = iconfig;
+ mContext = context;
+ }
+
+ /**
+ * Gets the provisioned value for IMS service/capabilities parameters used by IMS stack.
+ * This function should not be called from the mainthread as it could block the
+ * mainthread.
+ *
+ * @param item, as defined in com.android.ims.ImsConfig#ConfigConstants.
+ * @return the value in Integer format.
+ *
+ * @throws ImsException if calling the IMS service results in an error.
+ */
+ public int getProvisionedValue(int item) throws ImsException {
+ int ret = 0;
+ try {
+ ret = miConfig.getProvisionedValue(item);
+ } catch (RemoteException e) {
+ throw new ImsException("getValue()", e,
+ ImsReasonInfo.CODE_LOCAL_SERVICE_UNAVAILABLE);
+ }
+ if (DBG) Rlog.d(TAG, "getProvisionedValue(): item = " + item + ", ret =" + ret);
+
+ return ret;
+ }
+
+ /**
+ * Gets the provisioned value for IMS service/capabilities parameters used by IMS stack.
+ * This function should not be called from the mainthread as it could block the
+ * mainthread.
+ *
+ * @param item, as defined in com.android.ims.ImsConfig#ConfigConstants.
+ * @return value in String format.
+ *
+ * @throws ImsException if calling the IMS service results in an error.
+ */
+ public String getProvisionedStringValue(int item) throws ImsException {
+ String ret = "Unknown";
+ try {
+ ret = miConfig.getProvisionedStringValue(item);
+ } catch (RemoteException e) {
+ throw new ImsException("getProvisionedStringValue()", e,
+ ImsReasonInfo.CODE_LOCAL_SERVICE_UNAVAILABLE);
+ }
+ if (DBG) Rlog.d(TAG, "getProvisionedStringValue(): item = " + item + ", ret =" + ret);
+
+ return ret;
+ }
+
+ /**
+ * Sets the value for IMS service/capabilities parameters by
+ * the operator device management entity.
+ * This function should not be called from main thread as it could block
+ * mainthread.
+ *
+ * @param item, as defined in com.android.ims.ImsConfig#ConfigConstants.
+ * @param value in Integer format.
+ * @return as defined in com.android.ims.ImsConfig#OperationStatusConstants
+ *
+ * @throws ImsException if calling the IMS service results in an error.
+ */
+ public int setProvisionedValue(int item, int value)
+ throws ImsException {
+ int ret = OperationStatusConstants.UNKNOWN;
+ if (DBG) {
+ Rlog.d(TAG, "setProvisionedValue(): item = " + item +
+ "value = " + value);
+ }
+ try {
+ ret = miConfig.setProvisionedValue(item, value);
+ } catch (RemoteException e) {
+ throw new ImsException("setProvisionedValue()", e,
+ ImsReasonInfo.CODE_LOCAL_SERVICE_UNAVAILABLE);
+ }
+ if (DBG) {
+ Rlog.d(TAG, "setProvisionedValue(): item = " + item +
+ " value = " + value + " ret = " + ret);
+ }
+ return ret;
+ }
+
+ /**
+ * Sets the value for IMS service/capabilities parameters by
+ * the operator device management entity.
+ * This function should not be called from main thread as it could block
+ * mainthread.
+ *
+ * @param item, as defined in com.android.ims.ImsConfig#ConfigConstants.
+ * @param value in String format.
+ * @return as defined in com.android.ims.ImsConfig#OperationStatusConstants
+ *
+ * @throws ImsException if calling the IMS service results in an error.
+ */
+ public int setProvisionedStringValue(int item, String value)
+ throws ImsException {
+ int ret = OperationStatusConstants.UNKNOWN;
+ try {
+ ret = miConfig.setProvisionedStringValue(item, value);
+ } catch (RemoteException e) {
+ throw new ImsException("setProvisionedStringValue()", e,
+ ImsReasonInfo.CODE_LOCAL_SERVICE_UNAVAILABLE);
+ }
+ if (DBG) {
+ Rlog.d(TAG, "setProvisionedStringValue(): item = " + item +
+ ", value =" + value);
+ }
+ return ret;
+ }
+
+ /**
+ * Gets the value for IMS feature item for specified network type.
+ *
+ * @param feature, defined as in FeatureConstants.
+ * @param network, defined as in android.telephony.TelephonyManager#NETWORK_TYPE_XXX.
+ * @param listener, provided to be notified for the feature on/off status.
+ * @return void
+ *
+ * @throws ImsException if calling the IMS service results in an error.
+ */
+ public void getFeatureValue(int feature, int network,
+ ImsConfigListener listener) throws ImsException {
+ if (DBG) {
+ Rlog.d(TAG, "getFeatureValue: feature = " + feature + ", network =" + network +
+ ", listener =" + listener);
+ }
+ try {
+ miConfig.getFeatureValue(feature, network, listener);
+ } catch (RemoteException e) {
+ throw new ImsException("getFeatureValue()", e,
+ ImsReasonInfo.CODE_LOCAL_SERVICE_UNAVAILABLE);
+ }
+ }
+
+ /**
+ * Sets the value for IMS feature item for specified network type.
+ *
+ * @param feature, as defined in FeatureConstants.
+ * @param network, as defined in android.telephony.TelephonyManager#NETWORK_TYPE_XXX.
+ * @param value, as defined in FeatureValueConstants.
+ * @param listener, provided if caller needs to be notified for set result.
+ * @return void
+ *
+ * @throws ImsException if calling the IMS service results in an error.
+ */
+ public void setFeatureValue(int feature, int network, int value,
+ ImsConfigListener listener) throws ImsException {
+ if (DBG) {
+ Rlog.d(TAG, "setFeatureValue: feature = " + feature + ", network =" + network +
+ ", value =" + value + ", listener =" + listener);
+ }
+ try {
+ miConfig.setFeatureValue(feature, network, value, listener);
+ } catch (RemoteException e) {
+ throw new ImsException("setFeatureValue()", e,
+ ImsReasonInfo.CODE_LOCAL_SERVICE_UNAVAILABLE);
+ }
+ }
+}
diff --git a/telephony/java/com/android/ims/ImsException.java b/telephony/java/com/android/ims/ImsException.java
new file mode 100644
index 0000000..74b20f4
--- /dev/null
+++ b/telephony/java/com/android/ims/ImsException.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2013 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.ims;
+
+/**
+ * This class defines a general IMS-related exception.
+ *
+ * @hide
+ */
+public class ImsException extends Exception {
+
+ /**
+ * Refer to CODE_LOCAL_* in {@link ImsReasonInfo}
+ */
+ private int mCode;
+
+ public ImsException() {
+ }
+
+ public ImsException(String message, int code) {
+ super(message + ", code = " + code);
+ mCode = code;
+ }
+
+ public ImsException(String message, Throwable cause, int code) {
+ super(message, cause);
+ mCode = code;
+ }
+
+ /**
+ * Gets the detailed exception code when ImsException is throwed
+ *
+ * @return the exception code in {@link ImsReasonInfo}
+ */
+ public int getCode() {
+ return mCode;
+ }
+}
diff --git a/telephony/java/com/android/ims/ImsReasonInfo.java b/telephony/java/com/android/ims/ImsReasonInfo.java
index c71808c..e4f380f 100644
--- a/telephony/java/com/android/ims/ImsReasonInfo.java
+++ b/telephony/java/com/android/ims/ImsReasonInfo.java
@@ -313,6 +313,12 @@
public static final int CODE_WIFI_LOST = 1407;
/**
+ * Indicates the registration attempt on IWLAN failed due to IKEv2 authetication failure
+ * during tunnel establishment.
+ */
+ public static final int CODE_IKEV2_AUTH_FAILURE = 1408;
+
+ /**
* Network string error messages.
* mExtraMessage may have these values.
*/
diff --git a/telephony/java/com/android/ims/ImsUtInterface.java b/telephony/java/com/android/ims/ImsUtInterface.java
new file mode 100644
index 0000000..5984e78
--- /dev/null
+++ b/telephony/java/com/android/ims/ImsUtInterface.java
@@ -0,0 +1,179 @@
+/*
+ * Copyright (c) 2013 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.ims;
+
+import android.os.Message;
+
+/**
+ * Provides APIs for the supplementary service settings using IMS (Ut interface).
+ * It is created from 3GPP TS 24.623 (XCAP(XML Configuration Access Protocol)
+ * over the Ut interface for manipulating supplementary services).
+ *
+ * @hide
+ */
+public interface ImsUtInterface {
+ /**
+ * Actions
+ * @hide
+ */
+ public static final int ACTION_DEACTIVATION = 0;
+ public static final int ACTION_ACTIVATION = 1;
+ public static final int ACTION_REGISTRATION = 3;
+ public static final int ACTION_ERASURE = 4;
+ public static final int ACTION_INTERROGATION = 5;
+
+ /**
+ * OIR (Originating Identification Restriction, 3GPP TS 24.607)
+ * OIP (Originating Identification Presentation, 3GPP TS 24.607)
+ * TIR (Terminating Identification Restriction, 3GPP TS 24.608)
+ * TIP (Terminating Identification Presentation, 3GPP TS 24.608)
+ */
+ public static final int OIR_DEFAULT = 0; // "user subscription default value"
+ public static final int OIR_PRESENTATION_RESTRICTED = 1;
+ public static final int OIR_PRESENTATION_NOT_RESTRICTED = 2;
+
+ /**
+ * CW (Communication Waiting, 3GPP TS 24.615)
+ */
+
+ /**
+ * CDIV (Communication Diversion, 3GPP TS 24.604)
+ * actions: target, no reply timer
+ */
+ public static final int CDIV_CF_UNCONDITIONAL = 0;
+ public static final int CDIV_CF_BUSY = 1;
+ public static final int CDIV_CF_NO_REPLY = 2;
+ public static final int CDIV_CF_NOT_REACHABLE = 3;
+ // For CS service code: 002
+ public static final int CDIV_CF_ALL = 4;
+ // For CS service code: 004
+ public static final int CDIV_CF_ALL_CONDITIONAL = 5;
+ // It's only supported in the IMS service (CS does not define it).
+ // IR.92 recommends that an UE activates both the CFNRc and the CFNL
+ // (CDIV using condition not-registered) to the same target.
+ public static final int CDIV_CF_NOT_LOGGED_IN = 6;
+
+ /**
+ * CB (Communication Barring, 3GPP TS 24.611)
+ */
+ // Barring of All Incoming Calls
+ public static final int CB_BAIC = 1;
+ // Barring of All Outgoing Calls
+ public static final int CB_BAOC = 2;
+ // Barring of Outgoing International Calls
+ public static final int CB_BOIC = 3;
+ // Barring of Outgoing International Calls - excluding Home Country
+ public static final int CB_BOIC_EXHC = 4;
+ // Barring of Incoming Calls - when roaming
+ public static final int CB_BIC_WR = 5;
+ // Barring of Anonymous Communication Rejection (ACR) - a particular case of ICB service
+ public static final int CB_BIC_ACR = 6;
+ // Barring of All Calls
+ public static final int CB_BA_ALL = 7;
+ // Barring of Outgoing Services (Service Code 333 - 3GPP TS 22.030 Table B-1)
+ public static final int CB_BA_MO = 8;
+ // Barring of Incoming Services (Service Code 353 - 3GPP TS 22.030 Table B-1)
+ public static final int CB_BA_MT = 9;
+ // Barring of Specific Incoming calls
+ public static final int CB_BS_MT = 10;
+
+ /**
+ * Invalid result value.
+ */
+ public static final int INVALID = (-1);
+
+
+
+ /**
+ * Operations for the supplementary service configuration
+ */
+
+ /**
+ * Retrieves the configuration of the call barring.
+ * The return value of ((AsyncResult)result.obj) is an array of {@link ImsSsInfo}.
+ */
+ public void queryCallBarring(int cbType, Message result);
+
+ /**
+ * Retrieves the configuration of the call forward.
+ * The return value of ((AsyncResult)result.obj) is an array of {@link ImsCallForwardInfo}.
+ */
+ public void queryCallForward(int condition, String number, Message result);
+
+ /**
+ * Retrieves the configuration of the call waiting.
+ * The return value of ((AsyncResult)result.obj) is an array of {@link ImsSsInfo}.
+ */
+ public void queryCallWaiting(Message result);
+
+ /**
+ * Retrieves the default CLIR setting.
+ */
+ public void queryCLIR(Message result);
+
+ /**
+ * Retrieves the CLIP call setting.
+ */
+ public void queryCLIP(Message result);
+
+ /**
+ * Retrieves the COLR call setting.
+ */
+ public void queryCOLR(Message result);
+
+ /**
+ * Retrieves the COLP call setting.
+ */
+ public void queryCOLP(Message result);
+
+ /**
+ * Modifies the configuration of the call barring.
+ */
+ public void updateCallBarring(int cbType, int action,
+ Message result, String[] barrList);
+
+ /**
+ * Modifies the configuration of the call forward.
+ */
+ public void updateCallForward(int action, int condition, String number,
+ int serviceClass, int timeSeconds, Message result);
+
+ /**
+ * Modifies the configuration of the call waiting.
+ */
+ public void updateCallWaiting(boolean enable, int serviceClass, Message result);
+
+ /**
+ * Updates the configuration of the CLIR supplementary service.
+ */
+ public void updateCLIR(int clirMode, Message result);
+
+ /**
+ * Updates the configuration of the CLIP supplementary service.
+ */
+ public void updateCLIP(boolean enable, Message result);
+
+ /**
+ * Updates the configuration of the COLR supplementary service.
+ */
+ public void updateCOLR(int presentation, Message result);
+
+ /**
+ * Updates the configuration of the COLP supplementary service.
+ */
+ public void updateCOLP(boolean enable, Message result);
+}
diff --git a/telephony/java/com/android/ims/internal/IImsServiceFeatureListener.aidl b/telephony/java/com/android/ims/internal/IImsServiceFeatureListener.aidl
index 82a13dc..df10700 100644
--- a/telephony/java/com/android/ims/internal/IImsServiceFeatureListener.aidl
+++ b/telephony/java/com/android/ims/internal/IImsServiceFeatureListener.aidl
@@ -17,7 +17,8 @@
package com.android.ims.internal;
/**
-* Interface from ImsResolver to ImsServiceProxy in ImsManager.
+ * Interface from ImsResolver to ImsServiceProxy in ImsManager.
+ * Callback to ImsManager when a feature changes in the ImsServiceController.
* {@hide}
*/
oneway interface IImsServiceFeatureListener {
diff --git a/telephony/java/com/android/ims/internal/ImsCallSession.java b/telephony/java/com/android/ims/internal/ImsCallSession.java
new file mode 100644
index 0000000..8196b23
--- /dev/null
+++ b/telephony/java/com/android/ims/internal/ImsCallSession.java
@@ -0,0 +1,1290 @@
+/*
+ * Copyright (c) 2013 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.ims.internal;
+
+import android.os.Message;
+import android.os.RemoteException;
+
+import java.util.Objects;
+
+import android.telephony.ims.stub.ImsCallSessionListenerImplBase;
+import android.util.Log;
+import com.android.ims.ImsCallProfile;
+import com.android.ims.ImsConferenceState;
+import com.android.ims.ImsReasonInfo;
+import com.android.ims.ImsStreamMediaProfile;
+import com.android.ims.ImsSuppServiceNotification;
+
+/**
+ * Provides the call initiation/termination, and media exchange between two IMS endpoints.
+ * It directly communicates with IMS service which implements the IMS protocol behavior.
+ *
+ * @hide
+ */
+public class ImsCallSession {
+ private static final String TAG = "ImsCallSession";
+
+ /**
+ * Defines IMS call session state.
+ */
+ public static class State {
+ public static final int IDLE = 0;
+ public static final int INITIATED = 1;
+ public static final int NEGOTIATING = 2;
+ public static final int ESTABLISHING = 3;
+ public static final int ESTABLISHED = 4;
+
+ public static final int RENEGOTIATING = 5;
+ public static final int REESTABLISHING = 6;
+
+ public static final int TERMINATING = 7;
+ public static final int TERMINATED = 8;
+
+ public static final int INVALID = (-1);
+
+ /**
+ * Converts the state to string.
+ */
+ public static String toString(int state) {
+ switch (state) {
+ case IDLE:
+ return "IDLE";
+ case INITIATED:
+ return "INITIATED";
+ case NEGOTIATING:
+ return "NEGOTIATING";
+ case ESTABLISHING:
+ return "ESTABLISHING";
+ case ESTABLISHED:
+ return "ESTABLISHED";
+ case RENEGOTIATING:
+ return "RENEGOTIATING";
+ case REESTABLISHING:
+ return "REESTABLISHING";
+ case TERMINATING:
+ return "TERMINATING";
+ case TERMINATED:
+ return "TERMINATED";
+ default:
+ return "UNKNOWN";
+ }
+ }
+
+ private State() {
+ }
+ }
+
+ /**
+ * Listener for events relating to an IMS session, such as when a session is being
+ * recieved ("on ringing") or a call is outgoing ("on calling").
+ * <p>Many of these events are also received by {@link ImsCall.Listener}.</p>
+ */
+ public static class Listener {
+ /**
+ * Called when a request is sent out to initiate a new session
+ * and 1xx response is received from the network.
+ *
+ * @param session the session object that carries out the IMS session
+ */
+ public void callSessionProgressing(ImsCallSession session,
+ ImsStreamMediaProfile profile) {
+ // no-op
+ }
+
+ /**
+ * Called when the session is established.
+ *
+ * @param session the session object that carries out the IMS session
+ */
+ public void callSessionStarted(ImsCallSession session,
+ ImsCallProfile profile) {
+ // no-op
+ }
+
+ /**
+ * Called when the session establishment is failed.
+ *
+ * @param session the session object that carries out the IMS session
+ * @param reasonInfo detailed reason of the session establishment failure
+ */
+ public void callSessionStartFailed(ImsCallSession session,
+ ImsReasonInfo reasonInfo) {
+ }
+
+ /**
+ * Called when the session is terminated.
+ *
+ * @param session the session object that carries out the IMS session
+ * @param reasonInfo detailed reason of the session termination
+ */
+ public void callSessionTerminated(ImsCallSession session,
+ ImsReasonInfo reasonInfo) {
+ }
+
+ /**
+ * Called when the session is in hold.
+ *
+ * @param session the session object that carries out the IMS session
+ */
+ public void callSessionHeld(ImsCallSession session,
+ ImsCallProfile profile) {
+ }
+
+ /**
+ * Called when the session hold is failed.
+ *
+ * @param session the session object that carries out the IMS session
+ * @param reasonInfo detailed reason of the session hold failure
+ */
+ public void callSessionHoldFailed(ImsCallSession session,
+ ImsReasonInfo reasonInfo) {
+ }
+
+ /**
+ * Called when the session hold is received from the remote user.
+ *
+ * @param session the session object that carries out the IMS session
+ */
+ public void callSessionHoldReceived(ImsCallSession session,
+ ImsCallProfile profile) {
+ }
+
+ /**
+ * Called when the session resume is done.
+ *
+ * @param session the session object that carries out the IMS session
+ */
+ public void callSessionResumed(ImsCallSession session,
+ ImsCallProfile profile) {
+ }
+
+ /**
+ * Called when the session resume is failed.
+ *
+ * @param session the session object that carries out the IMS session
+ * @param reasonInfo detailed reason of the session resume failure
+ */
+ public void callSessionResumeFailed(ImsCallSession session,
+ ImsReasonInfo reasonInfo) {
+ }
+
+ /**
+ * Called when the session resume is received from the remote user.
+ *
+ * @param session the session object that carries out the IMS session
+ */
+ public void callSessionResumeReceived(ImsCallSession session,
+ ImsCallProfile profile) {
+ }
+
+ /**
+ * Called when the session merge has been started. At this point, the {@code newSession}
+ * represents the session which has been initiated to the IMS conference server for the
+ * new merged conference.
+ *
+ * @param session the session object that carries out the IMS session
+ * @param newSession the session object that is merged with an active & hold session
+ */
+ public void callSessionMergeStarted(ImsCallSession session,
+ ImsCallSession newSession, ImsCallProfile profile) {
+ }
+
+ /**
+ * Called when the session merge is successful and the merged session is active.
+ *
+ * @param session the session object that carries out the IMS session
+ */
+ public void callSessionMergeComplete(ImsCallSession session) {
+ }
+
+ /**
+ * Called when the session merge has failed.
+ *
+ * @param session the session object that carries out the IMS session
+ * @param reasonInfo detailed reason of the call merge failure
+ */
+ public void callSessionMergeFailed(ImsCallSession session,
+ ImsReasonInfo reasonInfo) {
+ }
+
+ /**
+ * Called when the session is updated (except for hold/unhold).
+ *
+ * @param session the session object that carries out the IMS session
+ */
+ public void callSessionUpdated(ImsCallSession session,
+ ImsCallProfile profile) {
+ }
+
+ /**
+ * Called when the session update is failed.
+ *
+ * @param session the session object that carries out the IMS session
+ * @param reasonInfo detailed reason of the session update failure
+ */
+ public void callSessionUpdateFailed(ImsCallSession session,
+ ImsReasonInfo reasonInfo) {
+ }
+
+ /**
+ * Called when the session update is received from the remote user.
+ *
+ * @param session the session object that carries out the IMS session
+ */
+ public void callSessionUpdateReceived(ImsCallSession session,
+ ImsCallProfile profile) {
+ // no-op
+ }
+
+ /**
+ * Called when the session is extended to the conference session.
+ *
+ * @param session the session object that carries out the IMS session
+ * @param newSession the session object that is extended to the conference
+ * from the active session
+ */
+ public void callSessionConferenceExtended(ImsCallSession session,
+ ImsCallSession newSession, ImsCallProfile profile) {
+ }
+
+ /**
+ * Called when the conference extension is failed.
+ *
+ * @param session the session object that carries out the IMS session
+ * @param reasonInfo detailed reason of the conference extension failure
+ */
+ public void callSessionConferenceExtendFailed(ImsCallSession session,
+ ImsReasonInfo reasonInfo) {
+ }
+
+ /**
+ * Called when the conference extension is received from the remote user.
+ *
+ * @param session the session object that carries out the IMS session
+ */
+ public void callSessionConferenceExtendReceived(ImsCallSession session,
+ ImsCallSession newSession, ImsCallProfile profile) {
+ // no-op
+ }
+
+ /**
+ * Called when the invitation request of the participants is delivered to the conference
+ * server.
+ *
+ * @param session the session object that carries out the IMS session
+ */
+ public void callSessionInviteParticipantsRequestDelivered(ImsCallSession session) {
+ // no-op
+ }
+
+ /**
+ * Called when the invitation request of the participants is failed.
+ *
+ * @param session the session object that carries out the IMS session
+ * @param reasonInfo detailed reason of the conference invitation failure
+ */
+ public void callSessionInviteParticipantsRequestFailed(ImsCallSession session,
+ ImsReasonInfo reasonInfo) {
+ // no-op
+ }
+
+ /**
+ * Called when the removal request of the participants is delivered to the conference
+ * server.
+ *
+ * @param session the session object that carries out the IMS session
+ */
+ public void callSessionRemoveParticipantsRequestDelivered(ImsCallSession session) {
+ // no-op
+ }
+
+ /**
+ * Called when the removal request of the participants is failed.
+ *
+ * @param session the session object that carries out the IMS session
+ * @param reasonInfo detailed reason of the conference removal failure
+ */
+ public void callSessionRemoveParticipantsRequestFailed(ImsCallSession session,
+ ImsReasonInfo reasonInfo) {
+ // no-op
+ }
+
+ /**
+ * Called when the conference state is updated.
+ *
+ * @param session the session object that carries out the IMS session
+ */
+ public void callSessionConferenceStateUpdated(ImsCallSession session,
+ ImsConferenceState state) {
+ // no-op
+ }
+
+ /**
+ * Called when the USSD message is received from the network.
+ *
+ * @param mode mode of the USSD message (REQUEST / NOTIFY)
+ * @param ussdMessage USSD message
+ */
+ public void callSessionUssdMessageReceived(ImsCallSession session,
+ int mode, String ussdMessage) {
+ // no-op
+ }
+
+ /**
+ * Called when session access technology changes
+ *
+ * @param session IMS session object
+ * @param srcAccessTech original access technology
+ * @param targetAccessTech new access technology
+ * @param reasonInfo
+ */
+ public void callSessionHandover(ImsCallSession session,
+ int srcAccessTech, int targetAccessTech,
+ ImsReasonInfo reasonInfo) {
+ // no-op
+ }
+
+ /**
+ * Called when session access technology change fails
+ *
+ * @param session IMS session object
+ * @param srcAccessTech original access technology
+ * @param targetAccessTech new access technology
+ * @param reasonInfo handover failure reason
+ */
+ public void callSessionHandoverFailed(ImsCallSession session,
+ int srcAccessTech, int targetAccessTech,
+ ImsReasonInfo reasonInfo) {
+ // no-op
+ }
+
+ /**
+ * Called when TTY mode of remote party changed
+ *
+ * @param session IMS session object
+ * @param mode TTY mode of remote party
+ */
+ public void callSessionTtyModeReceived(ImsCallSession session,
+ int mode) {
+ // no-op
+ }
+
+ /**
+ * Notifies of a change to the multiparty state for this {@code ImsCallSession}.
+ *
+ * @param session The call session.
+ * @param isMultiParty {@code true} if the session became multiparty, {@code false}
+ * otherwise.
+ */
+ public void callSessionMultipartyStateChanged(ImsCallSession session,
+ boolean isMultiParty) {
+ // no-op
+ }
+
+ /**
+ * Called when the session supplementary service is received
+ *
+ * @param session the session object that carries out the IMS session
+ */
+ public void callSessionSuppServiceReceived(ImsCallSession session,
+ ImsSuppServiceNotification suppServiceInfo) {
+ }
+ }
+
+ private final IImsCallSession miSession;
+ private boolean mClosed = false;
+ private Listener mListener;
+
+ public ImsCallSession(IImsCallSession iSession) {
+ miSession = iSession;
+
+ if (iSession != null) {
+ try {
+ iSession.setListener(new IImsCallSessionListenerProxy());
+ } catch (RemoteException e) {
+ }
+ } else {
+ mClosed = true;
+ }
+ }
+
+ public ImsCallSession(IImsCallSession iSession, Listener listener) {
+ this(iSession);
+ setListener(listener);
+ }
+
+ /**
+ * Closes this object. This object is not usable after being closed.
+ */
+ public synchronized void close() {
+ if (mClosed) {
+ return;
+ }
+
+ try {
+ miSession.close();
+ mClosed = true;
+ } catch (RemoteException e) {
+ }
+ }
+
+ /**
+ * Gets the call ID of the session.
+ *
+ * @return the call ID
+ */
+ public String getCallId() {
+ if (mClosed) {
+ return null;
+ }
+
+ try {
+ return miSession.getCallId();
+ } catch (RemoteException e) {
+ return null;
+ }
+ }
+
+ /**
+ * Gets the call profile that this session is associated with
+ *
+ * @return the call profile that this session is associated with
+ */
+ public ImsCallProfile getCallProfile() {
+ if (mClosed) {
+ return null;
+ }
+
+ try {
+ return miSession.getCallProfile();
+ } catch (RemoteException e) {
+ return null;
+ }
+ }
+
+ /**
+ * Gets the local call profile that this session is associated with
+ *
+ * @return the local call profile that this session is associated with
+ */
+ public ImsCallProfile getLocalCallProfile() {
+ if (mClosed) {
+ return null;
+ }
+
+ try {
+ return miSession.getLocalCallProfile();
+ } catch (RemoteException e) {
+ return null;
+ }
+ }
+
+ /**
+ * Gets the remote call profile that this session is associated with
+ *
+ * @return the remote call profile that this session is associated with
+ */
+ public ImsCallProfile getRemoteCallProfile() {
+ if (mClosed) {
+ return null;
+ }
+
+ try {
+ return miSession.getRemoteCallProfile();
+ } catch (RemoteException e) {
+ return null;
+ }
+ }
+
+ /**
+ * Gets the video call provider for the session.
+ *
+ * @return The video call provider.
+ */
+ public IImsVideoCallProvider getVideoCallProvider() {
+ if (mClosed) {
+ return null;
+ }
+
+ try {
+ return miSession.getVideoCallProvider();
+ } catch (RemoteException e) {
+ return null;
+ }
+ }
+
+ /**
+ * Gets the value associated with the specified property of this session.
+ *
+ * @return the string value associated with the specified property
+ */
+ public String getProperty(String name) {
+ if (mClosed) {
+ return null;
+ }
+
+ try {
+ return miSession.getProperty(name);
+ } catch (RemoteException e) {
+ return null;
+ }
+ }
+
+ /**
+ * Gets the session state.
+ * The value returned must be one of the states in {@link State}.
+ *
+ * @return the session state
+ */
+ public int getState() {
+ if (mClosed) {
+ return State.INVALID;
+ }
+
+ try {
+ return miSession.getState();
+ } catch (RemoteException e) {
+ return State.INVALID;
+ }
+ }
+
+ /**
+ * Determines if the {@link ImsCallSession} is currently alive (e.g. not in a terminated or
+ * closed state).
+ *
+ * @return {@code True} if the session is alive.
+ */
+ public boolean isAlive() {
+ if (mClosed) {
+ return false;
+ }
+
+ int state = getState();
+ switch (state) {
+ case State.IDLE:
+ case State.INITIATED:
+ case State.NEGOTIATING:
+ case State.ESTABLISHING:
+ case State.ESTABLISHED:
+ case State.RENEGOTIATING:
+ case State.REESTABLISHING:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ /**
+ * Gets the native IMS call session.
+ * @hide
+ */
+ public IImsCallSession getSession() {
+ return miSession;
+ }
+
+ /**
+ * Checks if the session is in call.
+ *
+ * @return true if the session is in call
+ */
+ public boolean isInCall() {
+ if (mClosed) {
+ return false;
+ }
+
+ try {
+ return miSession.isInCall();
+ } catch (RemoteException e) {
+ return false;
+ }
+ }
+
+ /**
+ * Sets the listener to listen to the session events. A {@link ImsCallSession}
+ * can only hold one listener at a time. Subsequent calls to this method
+ * override the previous listener.
+ *
+ * @param listener to listen to the session events of this object
+ */
+ public void setListener(Listener listener) {
+ mListener = listener;
+ }
+
+ /**
+ * Mutes or unmutes the mic for the active call.
+ *
+ * @param muted true if the call is muted, false otherwise
+ */
+ public void setMute(boolean muted) {
+ if (mClosed) {
+ return;
+ }
+
+ try {
+ miSession.setMute(muted);
+ } catch (RemoteException e) {
+ }
+ }
+
+ /**
+ * Initiates an IMS call with the specified target and call profile.
+ * The session listener is called back upon defined session events.
+ * The method is only valid to call when the session state is in
+ * {@link ImsCallSession.State#IDLE}.
+ *
+ * @param callee dialed string to make the call to
+ * @param profile call profile to make the call with the specified service type,
+ * call type and media information
+ * @see Listener#callSessionStarted, Listener#callSessionStartFailed
+ */
+ public void start(String callee, ImsCallProfile profile) {
+ if (mClosed) {
+ return;
+ }
+
+ try {
+ miSession.start(callee, profile);
+ } catch (RemoteException e) {
+ }
+ }
+
+ /**
+ * Initiates an IMS conference call with the specified target and call profile.
+ * The session listener is called back upon defined session events.
+ * The method is only valid to call when the session state is in
+ * {@link ImsCallSession.State#IDLE}.
+ *
+ * @param participants participant list to initiate an IMS conference call
+ * @param profile call profile to make the call with the specified service type,
+ * call type and media information
+ * @see Listener#callSessionStarted, Listener#callSessionStartFailed
+ */
+ public void start(String[] participants, ImsCallProfile profile) {
+ if (mClosed) {
+ return;
+ }
+
+ try {
+ miSession.startConference(participants, profile);
+ } catch (RemoteException e) {
+ }
+ }
+
+ /**
+ * Accepts an incoming call or session update.
+ *
+ * @param callType call type specified in {@link ImsCallProfile} to be answered
+ * @param profile stream media profile {@link ImsStreamMediaProfile} to be answered
+ * @see Listener#callSessionStarted
+ */
+ public void accept(int callType, ImsStreamMediaProfile profile) {
+ if (mClosed) {
+ return;
+ }
+
+ try {
+ miSession.accept(callType, profile);
+ } catch (RemoteException e) {
+ }
+ }
+
+ /**
+ * Rejects an incoming call or session update.
+ *
+ * @param reason reason code to reject an incoming call
+ * @see Listener#callSessionStartFailed
+ */
+ public void reject(int reason) {
+ if (mClosed) {
+ return;
+ }
+
+ try {
+ miSession.reject(reason);
+ } catch (RemoteException e) {
+ }
+ }
+
+ /**
+ * Terminates a call.
+ *
+ * @see Listener#callSessionTerminated
+ */
+ public void terminate(int reason) {
+ if (mClosed) {
+ return;
+ }
+
+ try {
+ miSession.terminate(reason);
+ } catch (RemoteException e) {
+ }
+ }
+
+ /**
+ * Puts a call on hold. When it succeeds, {@link Listener#callSessionHeld} is called.
+ *
+ * @param profile stream media profile {@link ImsStreamMediaProfile} to hold the call
+ * @see Listener#callSessionHeld, Listener#callSessionHoldFailed
+ */
+ public void hold(ImsStreamMediaProfile profile) {
+ if (mClosed) {
+ return;
+ }
+
+ try {
+ miSession.hold(profile);
+ } catch (RemoteException e) {
+ }
+ }
+
+ /**
+ * Continues a call that's on hold. When it succeeds,
+ * {@link Listener#callSessionResumed} is called.
+ *
+ * @param profile stream media profile {@link ImsStreamMediaProfile} to resume the call
+ * @see Listener#callSessionResumed, Listener#callSessionResumeFailed
+ */
+ public void resume(ImsStreamMediaProfile profile) {
+ if (mClosed) {
+ return;
+ }
+
+ try {
+ miSession.resume(profile);
+ } catch (RemoteException e) {
+ }
+ }
+
+ /**
+ * Merges the active & hold call. When it succeeds,
+ * {@link Listener#callSessionMergeStarted} is called.
+ *
+ * @see Listener#callSessionMergeStarted , Listener#callSessionMergeFailed
+ */
+ public void merge() {
+ if (mClosed) {
+ return;
+ }
+
+ try {
+ miSession.merge();
+ } catch (RemoteException e) {
+ }
+ }
+
+ /**
+ * Updates the current call's properties (ex. call mode change: video upgrade / downgrade).
+ *
+ * @param callType call type specified in {@link ImsCallProfile} to be updated
+ * @param profile stream media profile {@link ImsStreamMediaProfile} to be updated
+ * @see Listener#callSessionUpdated, Listener#callSessionUpdateFailed
+ */
+ public void update(int callType, ImsStreamMediaProfile profile) {
+ if (mClosed) {
+ return;
+ }
+
+ try {
+ miSession.update(callType, profile);
+ } catch (RemoteException e) {
+ }
+ }
+
+ /**
+ * Extends this call to the conference call with the specified recipients.
+ *
+ * @param participants list to be invited to the conference call after extending the call
+ * @see Listener#callSessionConferenceExtended
+ * @see Listener#callSessionConferenceExtendFailed
+ */
+ public void extendToConference(String[] participants) {
+ if (mClosed) {
+ return;
+ }
+
+ try {
+ miSession.extendToConference(participants);
+ } catch (RemoteException e) {
+ }
+ }
+
+ /**
+ * Requests the conference server to invite an additional participants to the conference.
+ *
+ * @param participants list to be invited to the conference call
+ * @see Listener#callSessionInviteParticipantsRequestDelivered
+ * @see Listener#callSessionInviteParticipantsRequestFailed
+ */
+ public void inviteParticipants(String[] participants) {
+ if (mClosed) {
+ return;
+ }
+
+ try {
+ miSession.inviteParticipants(participants);
+ } catch (RemoteException e) {
+ }
+ }
+
+ /**
+ * Requests the conference server to remove the specified participants from the conference.
+ *
+ * @param participants participant list to be removed from the conference call
+ * @see Listener#callSessionRemoveParticipantsRequestDelivered
+ * @see Listener#callSessionRemoveParticipantsRequestFailed
+ */
+ public void removeParticipants(String[] participants) {
+ if (mClosed) {
+ return;
+ }
+
+ try {
+ miSession.removeParticipants(participants);
+ } catch (RemoteException e) {
+ }
+ }
+
+
+ /**
+ * Sends a DTMF code. According to <a href="http://tools.ietf.org/html/rfc2833">RFC 2833</a>,
+ * event 0 ~ 9 maps to decimal value 0 ~ 9, '*' to 10, '#' to 11, event 'A' ~ 'D' to 12 ~ 15,
+ * and event flash to 16. Currently, event flash is not supported.
+ *
+ * @param c the DTMF to send. '0' ~ '9', 'A' ~ 'D', '*', '#' are valid inputs.
+ */
+ public void sendDtmf(char c, Message result) {
+ if (mClosed) {
+ return;
+ }
+
+ try {
+ miSession.sendDtmf(c, result);
+ } catch (RemoteException e) {
+ }
+ }
+
+ /**
+ * Starts a DTMF code. According to <a href="http://tools.ietf.org/html/rfc2833">RFC 2833</a>,
+ * event 0 ~ 9 maps to decimal value 0 ~ 9, '*' to 10, '#' to 11, event 'A' ~ 'D' to 12 ~ 15,
+ * and event flash to 16. Currently, event flash is not supported.
+ *
+ * @param c the DTMF to send. '0' ~ '9', 'A' ~ 'D', '*', '#' are valid inputs.
+ */
+ public void startDtmf(char c) {
+ if (mClosed) {
+ return;
+ }
+
+ try {
+ miSession.startDtmf(c);
+ } catch (RemoteException e) {
+ }
+ }
+
+ /**
+ * Stops a DTMF code.
+ */
+ public void stopDtmf() {
+ if (mClosed) {
+ return;
+ }
+
+ try {
+ miSession.stopDtmf();
+ } catch (RemoteException e) {
+ }
+ }
+
+ /**
+ * Sends an USSD message.
+ *
+ * @param ussdMessage USSD message to send
+ */
+ public void sendUssd(String ussdMessage) {
+ if (mClosed) {
+ return;
+ }
+
+ try {
+ miSession.sendUssd(ussdMessage);
+ } catch (RemoteException e) {
+ }
+ }
+
+ /**
+ * Determines if the session is multiparty.
+ *
+ * @return {@code True} if the session is multiparty.
+ */
+ public boolean isMultiparty() {
+ if (mClosed) {
+ return false;
+ }
+
+ try {
+ return miSession.isMultiparty();
+ } catch (RemoteException e) {
+ return false;
+ }
+ }
+
+ /**
+ * A listener type for receiving notification on IMS call session events.
+ * When an event is generated for an {@link IImsCallSession},
+ * the application is notified by having one of the methods called on
+ * the {@link IImsCallSessionListener}.
+ */
+ private class IImsCallSessionListenerProxy extends ImsCallSessionListenerImplBase {
+ /**
+ * Notifies the result of the basic session operation (setup / terminate).
+ */
+ @Override
+ public void callSessionProgressing(IImsCallSession session,
+ ImsStreamMediaProfile profile) {
+ if (mListener != null) {
+ mListener.callSessionProgressing(ImsCallSession.this, profile);
+ }
+ }
+
+ @Override
+ public void callSessionStarted(IImsCallSession session,
+ ImsCallProfile profile) {
+ if (mListener != null) {
+ mListener.callSessionStarted(ImsCallSession.this, profile);
+ }
+ }
+
+ @Override
+ public void callSessionStartFailed(IImsCallSession session,
+ ImsReasonInfo reasonInfo) {
+ if (mListener != null) {
+ mListener.callSessionStartFailed(ImsCallSession.this, reasonInfo);
+ }
+ }
+
+ @Override
+ public void callSessionTerminated(IImsCallSession session,
+ ImsReasonInfo reasonInfo) {
+ if (mListener != null) {
+ mListener.callSessionTerminated(ImsCallSession.this, reasonInfo);
+ }
+ }
+
+ /**
+ * Notifies the result of the call hold/resume operation.
+ */
+ @Override
+ public void callSessionHeld(IImsCallSession session,
+ ImsCallProfile profile) {
+ if (mListener != null) {
+ mListener.callSessionHeld(ImsCallSession.this, profile);
+ }
+ }
+
+ @Override
+ public void callSessionHoldFailed(IImsCallSession session,
+ ImsReasonInfo reasonInfo) {
+ if (mListener != null) {
+ mListener.callSessionHoldFailed(ImsCallSession.this, reasonInfo);
+ }
+ }
+
+ @Override
+ public void callSessionHoldReceived(IImsCallSession session,
+ ImsCallProfile profile) {
+ if (mListener != null) {
+ mListener.callSessionHoldReceived(ImsCallSession.this, profile);
+ }
+ }
+
+ @Override
+ public void callSessionResumed(IImsCallSession session,
+ ImsCallProfile profile) {
+ if (mListener != null) {
+ mListener.callSessionResumed(ImsCallSession.this, profile);
+ }
+ }
+
+ @Override
+ public void callSessionResumeFailed(IImsCallSession session,
+ ImsReasonInfo reasonInfo) {
+ if (mListener != null) {
+ mListener.callSessionResumeFailed(ImsCallSession.this, reasonInfo);
+ }
+ }
+
+ @Override
+ public void callSessionResumeReceived(IImsCallSession session,
+ ImsCallProfile profile) {
+ if (mListener != null) {
+ mListener.callSessionResumeReceived(ImsCallSession.this, profile);
+ }
+ }
+
+ /**
+ * Notifies the start of a call merge operation.
+ *
+ * @param session The call session.
+ * @param newSession The merged call session.
+ * @param profile The call profile.
+ */
+ @Override
+ public void callSessionMergeStarted(IImsCallSession session,
+ IImsCallSession newSession, ImsCallProfile profile) {
+ // This callback can be used for future use to add additional
+ // functionality that may be needed between conference start and complete
+ Log.d(TAG, "callSessionMergeStarted");
+ }
+
+ /**
+ * Notifies the successful completion of a call merge operation.
+ *
+ * @param newSession The call session.
+ */
+ @Override
+ public void callSessionMergeComplete(IImsCallSession newSession) {
+ if (mListener != null) {
+ if (newSession != null) {
+ // Check if the active session is the same session that was
+ // active before the merge request was sent.
+ ImsCallSession validActiveSession = ImsCallSession.this;
+ try {
+ if (!Objects.equals(miSession.getCallId(), newSession.getCallId())) {
+ // New session created after conference
+ validActiveSession = new ImsCallSession(newSession);
+ }
+ } catch (RemoteException rex) {
+ Log.e(TAG, "callSessionMergeComplete: exception for getCallId!");
+ }
+ mListener.callSessionMergeComplete(validActiveSession);
+ } else {
+ // Session already exists. Hence no need to pass
+ mListener.callSessionMergeComplete(null);
+ }
+ }
+ }
+
+ /**
+ * Notifies of a failure to perform a call merge operation.
+ *
+ * @param session The call session.
+ * @param reasonInfo The merge failure reason.
+ */
+ @Override
+ public void callSessionMergeFailed(IImsCallSession session,
+ ImsReasonInfo reasonInfo) {
+ if (mListener != null) {
+ mListener.callSessionMergeFailed(ImsCallSession.this, reasonInfo);
+ }
+ }
+
+ /**
+ * Notifies the result of call upgrade / downgrade or any other call updates.
+ */
+ @Override
+ public void callSessionUpdated(IImsCallSession session,
+ ImsCallProfile profile) {
+ if (mListener != null) {
+ mListener.callSessionUpdated(ImsCallSession.this, profile);
+ }
+ }
+
+ @Override
+ public void callSessionUpdateFailed(IImsCallSession session,
+ ImsReasonInfo reasonInfo) {
+ if (mListener != null) {
+ mListener.callSessionUpdateFailed(ImsCallSession.this, reasonInfo);
+ }
+ }
+
+ @Override
+ public void callSessionUpdateReceived(IImsCallSession session,
+ ImsCallProfile profile) {
+ if (mListener != null) {
+ mListener.callSessionUpdateReceived(ImsCallSession.this, profile);
+ }
+ }
+
+ /**
+ * Notifies the result of conference extension.
+ */
+ @Override
+ public void callSessionConferenceExtended(IImsCallSession session,
+ IImsCallSession newSession, ImsCallProfile profile) {
+ if (mListener != null) {
+ mListener.callSessionConferenceExtended(ImsCallSession.this,
+ new ImsCallSession(newSession), profile);
+ }
+ }
+
+ @Override
+ public void callSessionConferenceExtendFailed(IImsCallSession session,
+ ImsReasonInfo reasonInfo) {
+ if (mListener != null) {
+ mListener.callSessionConferenceExtendFailed(ImsCallSession.this, reasonInfo);
+ }
+ }
+
+ @Override
+ public void callSessionConferenceExtendReceived(IImsCallSession session,
+ IImsCallSession newSession, ImsCallProfile profile) {
+ if (mListener != null) {
+ mListener.callSessionConferenceExtendReceived(ImsCallSession.this,
+ new ImsCallSession(newSession), profile);
+ }
+ }
+
+ /**
+ * Notifies the result of the participant invitation / removal to/from
+ * the conference session.
+ */
+ @Override
+ public void callSessionInviteParticipantsRequestDelivered(IImsCallSession session) {
+ if (mListener != null) {
+ mListener.callSessionInviteParticipantsRequestDelivered(ImsCallSession.this);
+ }
+ }
+
+ @Override
+ public void callSessionInviteParticipantsRequestFailed(IImsCallSession session,
+ ImsReasonInfo reasonInfo) {
+ if (mListener != null) {
+ mListener.callSessionInviteParticipantsRequestFailed(ImsCallSession.this,
+ reasonInfo);
+ }
+ }
+
+ @Override
+ public void callSessionRemoveParticipantsRequestDelivered(IImsCallSession session) {
+ if (mListener != null) {
+ mListener.callSessionRemoveParticipantsRequestDelivered(ImsCallSession.this);
+ }
+ }
+
+ @Override
+ public void callSessionRemoveParticipantsRequestFailed(IImsCallSession session,
+ ImsReasonInfo reasonInfo) {
+ if (mListener != null) {
+ mListener.callSessionRemoveParticipantsRequestFailed(ImsCallSession.this,
+ reasonInfo);
+ }
+ }
+
+ /**
+ * Notifies the changes of the conference info. in the conference session.
+ */
+ @Override
+ public void callSessionConferenceStateUpdated(IImsCallSession session,
+ ImsConferenceState state) {
+ if (mListener != null) {
+ mListener.callSessionConferenceStateUpdated(ImsCallSession.this, state);
+ }
+ }
+
+ /**
+ * Notifies the incoming USSD message.
+ */
+ @Override
+ public void callSessionUssdMessageReceived(IImsCallSession session,
+ int mode, String ussdMessage) {
+ if (mListener != null) {
+ mListener.callSessionUssdMessageReceived(ImsCallSession.this, mode, ussdMessage);
+ }
+ }
+
+ /**
+ * Notifies of handover information for this call
+ */
+ @Override
+ public void callSessionHandover(IImsCallSession session,
+ int srcAccessTech, int targetAccessTech,
+ ImsReasonInfo reasonInfo) {
+ if (mListener != null) {
+ mListener.callSessionHandover(ImsCallSession.this, srcAccessTech,
+ targetAccessTech, reasonInfo);
+ }
+ }
+
+ /**
+ * Notifies of handover failure info for this call
+ */
+ @Override
+ public void callSessionHandoverFailed(IImsCallSession session,
+ int srcAccessTech, int targetAccessTech,
+ ImsReasonInfo reasonInfo) {
+ if (mListener != null) {
+ mListener.callSessionHandoverFailed(ImsCallSession.this, srcAccessTech,
+ targetAccessTech, reasonInfo);
+ }
+ }
+
+ /**
+ * Notifies the TTY mode received from remote party.
+ */
+ @Override
+ public void callSessionTtyModeReceived(IImsCallSession session,
+ int mode) {
+ if (mListener != null) {
+ mListener.callSessionTtyModeReceived(ImsCallSession.this, mode);
+ }
+ }
+
+ /**
+ * Notifies of a change to the multiparty state for this {@code ImsCallSession}.
+ *
+ * @param session The call session.
+ * @param isMultiParty {@code true} if the session became multiparty, {@code false}
+ * otherwise.
+ */
+ public void callSessionMultipartyStateChanged(IImsCallSession session,
+ boolean isMultiParty) {
+
+ if (mListener != null) {
+ mListener.callSessionMultipartyStateChanged(ImsCallSession.this, isMultiParty);
+ }
+ }
+
+ @Override
+ public void callSessionSuppServiceReceived(IImsCallSession session,
+ ImsSuppServiceNotification suppServiceInfo ) {
+ if (mListener != null) {
+ mListener.callSessionSuppServiceReceived(ImsCallSession.this, suppServiceInfo);
+ }
+ }
+
+ }
+
+ /**
+ * Provides a string representation of the {@link ImsCallSession}. Primarily intended for
+ * use in log statements.
+ *
+ * @return String representation of session.
+ */
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ sb.append("[ImsCallSession objId:");
+ sb.append(System.identityHashCode(this));
+ sb.append(" state:");
+ sb.append(State.toString(getState()));
+ sb.append(" callId:");
+ sb.append(getCallId());
+ sb.append("]");
+ return sb.toString();
+ }
+}
diff --git a/telephony/java/com/android/ims/internal/ImsVideoCallProvider.java b/telephony/java/com/android/ims/internal/ImsVideoCallProvider.java
new file mode 100644
index 0000000..432dc39
--- /dev/null
+++ b/telephony/java/com/android/ims/internal/ImsVideoCallProvider.java
@@ -0,0 +1,294 @@
+/*
+ * Copyright (C) 2017 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.ims.internal;
+
+import android.net.Uri;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.os.RemoteException;
+import android.telecom.Connection;
+import android.telecom.VideoProfile;
+import android.telecom.VideoProfile.CameraCapabilities;
+import android.view.Surface;
+
+import com.android.internal.os.SomeArgs;
+
+/**
+ * @hide
+ */
+public abstract class ImsVideoCallProvider {
+ private static final int MSG_SET_CALLBACK = 1;
+ private static final int MSG_SET_CAMERA = 2;
+ private static final int MSG_SET_PREVIEW_SURFACE = 3;
+ private static final int MSG_SET_DISPLAY_SURFACE = 4;
+ private static final int MSG_SET_DEVICE_ORIENTATION = 5;
+ private static final int MSG_SET_ZOOM = 6;
+ private static final int MSG_SEND_SESSION_MODIFY_REQUEST = 7;
+ private static final int MSG_SEND_SESSION_MODIFY_RESPONSE = 8;
+ private static final int MSG_REQUEST_CAMERA_CAPABILITIES = 9;
+ private static final int MSG_REQUEST_CALL_DATA_USAGE = 10;
+ private static final int MSG_SET_PAUSE_IMAGE = 11;
+
+ private final ImsVideoCallProviderBinder mBinder;
+
+ private IImsVideoCallCallback mCallback;
+
+ /**
+ * Default handler used to consolidate binder method calls onto a single thread.
+ */
+ private final Handler mProviderHandler = new Handler(Looper.getMainLooper()) {
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case MSG_SET_CALLBACK:
+ mCallback = (IImsVideoCallCallback) msg.obj;
+ break;
+ case MSG_SET_CAMERA:
+ {
+ SomeArgs args = (SomeArgs) msg.obj;
+ try {
+ onSetCamera((String) args.arg1);
+ onSetCamera((String) args.arg1, args.argi1);
+ } finally {
+ args.recycle();
+ }
+ break;
+ }
+ case MSG_SET_PREVIEW_SURFACE:
+ onSetPreviewSurface((Surface) msg.obj);
+ break;
+ case MSG_SET_DISPLAY_SURFACE:
+ onSetDisplaySurface((Surface) msg.obj);
+ break;
+ case MSG_SET_DEVICE_ORIENTATION:
+ onSetDeviceOrientation(msg.arg1);
+ break;
+ case MSG_SET_ZOOM:
+ onSetZoom((Float) msg.obj);
+ break;
+ case MSG_SEND_SESSION_MODIFY_REQUEST: {
+ SomeArgs args = (SomeArgs) msg.obj;
+ try {
+ VideoProfile fromProfile = (VideoProfile) args.arg1;
+ VideoProfile toProfile = (VideoProfile) args.arg2;
+
+ onSendSessionModifyRequest(fromProfile, toProfile);
+ } finally {
+ args.recycle();
+ }
+ break;
+ }
+ case MSG_SEND_SESSION_MODIFY_RESPONSE:
+ onSendSessionModifyResponse((VideoProfile) msg.obj);
+ break;
+ case MSG_REQUEST_CAMERA_CAPABILITIES:
+ onRequestCameraCapabilities();
+ break;
+ case MSG_REQUEST_CALL_DATA_USAGE:
+ onRequestCallDataUsage();
+ break;
+ case MSG_SET_PAUSE_IMAGE:
+ onSetPauseImage((Uri) msg.obj);
+ break;
+ default:
+ break;
+ }
+ }
+ };
+
+ /**
+ * IImsVideoCallProvider stub implementation.
+ */
+ private final class ImsVideoCallProviderBinder extends IImsVideoCallProvider.Stub {
+ public void setCallback(IImsVideoCallCallback callback) {
+ mProviderHandler.obtainMessage(MSG_SET_CALLBACK, callback).sendToTarget();
+ }
+
+ public void setCamera(String cameraId, int uid) {
+ SomeArgs args = SomeArgs.obtain();
+ args.arg1 = cameraId;
+ args.argi1 = uid;
+ mProviderHandler.obtainMessage(MSG_SET_CAMERA, args).sendToTarget();
+ }
+
+ public void setPreviewSurface(Surface surface) {
+ mProviderHandler.obtainMessage(MSG_SET_PREVIEW_SURFACE, surface).sendToTarget();
+ }
+
+ public void setDisplaySurface(Surface surface) {
+ mProviderHandler.obtainMessage(MSG_SET_DISPLAY_SURFACE, surface).sendToTarget();
+ }
+
+ public void setDeviceOrientation(int rotation) {
+ mProviderHandler.obtainMessage(MSG_SET_DEVICE_ORIENTATION, rotation, 0).sendToTarget();
+ }
+
+ public void setZoom(float value) {
+ mProviderHandler.obtainMessage(MSG_SET_ZOOM, value).sendToTarget();
+ }
+
+ public void sendSessionModifyRequest(VideoProfile fromProfile, VideoProfile toProfile) {
+ SomeArgs args = SomeArgs.obtain();
+ args.arg1 = fromProfile;
+ args.arg2 = toProfile;
+ mProviderHandler.obtainMessage(MSG_SEND_SESSION_MODIFY_REQUEST, args).sendToTarget();
+ }
+
+ public void sendSessionModifyResponse(VideoProfile responseProfile) {
+ mProviderHandler.obtainMessage(
+ MSG_SEND_SESSION_MODIFY_RESPONSE, responseProfile).sendToTarget();
+ }
+
+ public void requestCameraCapabilities() {
+ mProviderHandler.obtainMessage(MSG_REQUEST_CAMERA_CAPABILITIES).sendToTarget();
+ }
+
+ public void requestCallDataUsage() {
+ mProviderHandler.obtainMessage(MSG_REQUEST_CALL_DATA_USAGE).sendToTarget();
+ }
+
+ public void setPauseImage(Uri uri) {
+ mProviderHandler.obtainMessage(MSG_SET_PAUSE_IMAGE, uri).sendToTarget();
+ }
+ }
+
+ public ImsVideoCallProvider() {
+ mBinder = new ImsVideoCallProviderBinder();
+ }
+
+ /**
+ * Returns binder object which can be used across IPC methods.
+ */
+ public final IImsVideoCallProvider getInterface() {
+ return mBinder;
+ }
+
+ /** @see Connection.VideoProvider#onSetCamera */
+ public abstract void onSetCamera(String cameraId);
+
+ /**
+ * Similar to {@link #onSetCamera(String)}, except includes the UID of the calling process which
+ * the IMS service uses when opening the camera. This ensures camera permissions are verified
+ * by the camera service.
+ *
+ * @param cameraId The id of the camera to be opened.
+ * @param uid The uid of the caller, used when opening the camera for permission verification.
+ * @see Connection.VideoProvider#onSetCamera
+ */
+ public void onSetCamera(String cameraId, int uid) {
+ }
+
+ /** @see Connection.VideoProvider#onSetPreviewSurface */
+ public abstract void onSetPreviewSurface(Surface surface);
+
+ /** @see Connection.VideoProvider#onSetDisplaySurface */
+ public abstract void onSetDisplaySurface(Surface surface);
+
+ /** @see Connection.VideoProvider#onSetDeviceOrientation */
+ public abstract void onSetDeviceOrientation(int rotation);
+
+ /** @see Connection.VideoProvider#onSetZoom */
+ public abstract void onSetZoom(float value);
+
+ /** @see Connection.VideoProvider#onSendSessionModifyRequest */
+ public abstract void onSendSessionModifyRequest(VideoProfile fromProfile,
+ VideoProfile toProfile);
+
+ /** @see Connection.VideoProvider#onSendSessionModifyResponse */
+ public abstract void onSendSessionModifyResponse(VideoProfile responseProfile);
+
+ /** @see Connection.VideoProvider#onRequestCameraCapabilities */
+ public abstract void onRequestCameraCapabilities();
+
+ /** @see Connection.VideoProvider#onRequestCallDataUsage */
+ public abstract void onRequestCallDataUsage();
+
+ /** @see Connection.VideoProvider#onSetPauseImage */
+ public abstract void onSetPauseImage(Uri uri);
+
+ /** @see Connection.VideoProvider#receiveSessionModifyRequest */
+ public void receiveSessionModifyRequest(VideoProfile VideoProfile) {
+ if (mCallback != null) {
+ try {
+ mCallback.receiveSessionModifyRequest(VideoProfile);
+ } catch (RemoteException ignored) {
+ }
+ }
+ }
+
+ /** @see Connection.VideoProvider#receiveSessionModifyResponse */
+ public void receiveSessionModifyResponse(
+ int status, VideoProfile requestedProfile, VideoProfile responseProfile) {
+ if (mCallback != null) {
+ try {
+ mCallback.receiveSessionModifyResponse(status, requestedProfile, responseProfile);
+ } catch (RemoteException ignored) {
+ }
+ }
+ }
+
+ /** @see Connection.VideoProvider#handleCallSessionEvent */
+ public void handleCallSessionEvent(int event) {
+ if (mCallback != null) {
+ try {
+ mCallback.handleCallSessionEvent(event);
+ } catch (RemoteException ignored) {
+ }
+ }
+ }
+
+ /** @see Connection.VideoProvider#changePeerDimensions */
+ public void changePeerDimensions(int width, int height) {
+ if (mCallback != null) {
+ try {
+ mCallback.changePeerDimensions(width, height);
+ } catch (RemoteException ignored) {
+ }
+ }
+ }
+
+ /** @see Connection.VideoProvider#changeCallDataUsage */
+ public void changeCallDataUsage(long dataUsage) {
+ if (mCallback != null) {
+ try {
+ mCallback.changeCallDataUsage(dataUsage);
+ } catch (RemoteException ignored) {
+ }
+ }
+ }
+
+ /** @see Connection.VideoProvider#changeCameraCapabilities */
+ public void changeCameraCapabilities(CameraCapabilities CameraCapabilities) {
+ if (mCallback != null) {
+ try {
+ mCallback.changeCameraCapabilities(CameraCapabilities);
+ } catch (RemoteException ignored) {
+ }
+ }
+ }
+
+ /** @see Connection.VideoProvider#changeVideoQuality */
+ public void changeVideoQuality(int videoQuality) {
+ if (mCallback != null) {
+ try {
+ mCallback.changeVideoQuality(videoQuality);
+ } catch (RemoteException ignored) {
+ }
+ }
+ }
+}
diff --git a/telephony/java/com/android/internal/telephony/TelephonyIntents.java b/telephony/java/com/android/internal/telephony/TelephonyIntents.java
index 7fd511f..bcaac6e 100644
--- a/telephony/java/com/android/internal/telephony/TelephonyIntents.java
+++ b/telephony/java/com/android/internal/telephony/TelephonyIntents.java
@@ -264,22 +264,13 @@
= "android.intent.action.ACTION_SHOW_NOTICE_ECM_BLOCK_OTHERS";
/**
- * Activity Action: Start this activity to invoke the carrier setup app.
- * The carrier app must be signed using a certificate that matches the UICC access rules.
- *
- * <p class="note">Callers of this should hold the android.permission.INVOKE_CARRIER_SETUP
- * permission.</p>
- */
- public static final String ACTION_CARRIER_SETUP = "android.intent.action.ACTION_CARRIER_SETUP";
-
- /**
* <p>Broadcast Action: Indicates that the action is forbidden by network.
* <p class="note">
* This is for the OEM applications to understand about possible provisioning issues.
* Used in OMA-DM applications.
*/
public static final String ACTION_FORBIDDEN_NO_SERVICE_AUTHORIZATION
- = "android.intent.action.ACTION_FORBIDDEN_NO_SERVICE_AUTHORIZATION";
+ = "com.android.internal.intent.action.ACTION_FORBIDDEN_NO_SERVICE_AUTHORIZATION";
/**
* Broadcast Action: A "secret code" has been entered in the dialer. Secret codes are
@@ -411,7 +402,7 @@
* <p class="note">This is a protected intent that can only be sent by the system.</p>
*/
public static final String ACTION_CARRIER_SIGNAL_REDIRECTED =
- "android.intent.action.CARRIER_SIGNAL_REDIRECTED";
+ "com.android.internal.telephony.CARRIER_SIGNAL_REDIRECTED";
/**
* <p>Broadcast Action: when data connections setup fails.
* intended for sim/account status checks and only sent to the specified carrier app
@@ -424,7 +415,7 @@
* <p class="note">This is a protected intent that can only be sent by the system. </p>
*/
public static final String ACTION_CARRIER_SIGNAL_REQUEST_NETWORK_FAILED =
- "android.intent.action.CARRIER_SIGNAL_REQUEST_NETWORK_FAILED";
+ "com.android.internal.telephony.CARRIER_SIGNAL_REQUEST_NETWORK_FAILED";
/**
* <p>Broadcast Action: when pco value is available.
@@ -441,7 +432,7 @@
* <p class="note">This is a protected intent that can only be sent by the system. </p>
*/
public static final String ACTION_CARRIER_SIGNAL_PCO_VALUE =
- "android.intent.action.CARRIER_SIGNAL_PCO_VALUE";
+ "com.android.internal.telephony.CARRIER_SIGNAL_PCO_VALUE";
// CARRIER_SIGNAL_ACTION extra keys
public static final String EXTRA_REDIRECTION_URL_KEY = "redirectionUrl";
diff --git a/test-runner/src/android/test/suitebuilder/TestMethod.java b/test-runner/src/android/test/suitebuilder/TestMethod.java
index 08568d5..ae1db5e 100644
--- a/test-runner/src/android/test/suitebuilder/TestMethod.java
+++ b/test-runner/src/android/test/suitebuilder/TestMethod.java
@@ -26,7 +26,11 @@
/**
* Represents a test to be run. Can be constructed without instantiating the TestCase or even
* loading the class.
+ *
+ * @deprecated New tests should be written using the
+ * <a href="{@docRoot}tools/testing-support-library/index.html">Android Testing Support Library</a>.
*/
+@Deprecated
public class TestMethod {
private final String enclosingClassname;
diff --git a/test-runner/src/android/test/suitebuilder/TestSuiteBuilder.java b/test-runner/src/android/test/suitebuilder/TestSuiteBuilder.java
index 8c89489..3b920cf 100644
--- a/test-runner/src/android/test/suitebuilder/TestSuiteBuilder.java
+++ b/test-runner/src/android/test/suitebuilder/TestSuiteBuilder.java
@@ -38,7 +38,11 @@
/**
* Build suites based on a combination of included packages, excluded packages,
* and predicates that must be satisfied.
+ *
+ * @deprecated New tests should be written using the
+ * <a href="{@docRoot}tools/testing-support-library/index.html">Android Testing Support Library</a>.
*/
+@Deprecated
public class TestSuiteBuilder {
private Context context;
@@ -223,7 +227,11 @@
/**
* A special {@link junit.framework.TestCase} used to indicate a failure during the build()
* step.
+ *
+ * @deprecated New tests should be written using the
+ * <a href="{@docRoot}tools/testing-support-library/index.html">Android Testing Support Library</a>.
*/
+ @Deprecated
public static class FailedToCreateTests extends TestCase {
private final Exception exception;
diff --git a/tests/SoundTriggerTestApp/res/layout/main.xml b/tests/SoundTriggerTestApp/res/layout/main.xml
index 0fd8b12..2c6c8d7 100644
--- a/tests/SoundTriggerTestApp/res/layout/main.xml
+++ b/tests/SoundTriggerTestApp/res/layout/main.xml
@@ -87,6 +87,7 @@
android:text="@string/capture"
android:id="@+id/caputre_check_box"
android:layout_gravity="center_horizontal"
+ android:onClick="onCaptureAudioCheckboxClicked"
android:padding="20dp" />
<Button
@@ -94,6 +95,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/play_capture"
+ android:onClick="onPlayCapturedAudioButtonClicked"
android:padding="20dp"
android:enabled="false" />
</LinearLayout>
diff --git a/tests/StatusBar/src/com/android/statusbartest/NotificationTestList.java b/tests/StatusBar/src/com/android/statusbartest/NotificationTestList.java
index 56aad23..9b1a9f2 100644
--- a/tests/StatusBar/src/com/android/statusbartest/NotificationTestList.java
+++ b/tests/StatusBar/src/com/android/statusbartest/NotificationTestList.java
@@ -297,6 +297,7 @@
Notification n = new Notification.Builder(NotificationTestList.this)
.setSmallIcon(R.drawable.icon2)
.setContentTitle("Low priority")
+ .setTimeout(60000)
.setLights(0xff0000ff, 1, 0)
.setPriority(Notification.PRIORITY_LOW)
.build();
diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java
index eeaf26f..c05045e 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -369,6 +369,11 @@
connect(false);
}
+ public void suspend() {
+ mNetworkInfo.setDetailedState(DetailedState.SUSPENDED, null, null);
+ mNetworkAgent.sendNetworkInfo(mNetworkInfo);
+ }
+
public void disconnect() {
mNetworkInfo.setDetailedState(DetailedState.DISCONNECTED, null, null);
mNetworkAgent.sendNetworkInfo(mNetworkInfo);
@@ -1054,6 +1059,7 @@
AVAILABLE,
NETWORK_CAPABILITIES,
LINK_PROPERTIES,
+ SUSPENDED,
LOSING,
LOST,
UNAVAILABLE
@@ -1067,7 +1073,7 @@
state = s; network = n; arg = o;
}
public String toString() {
- return String.format("%s (%s)", state, network);
+ return String.format("%s (%s) (%s)", state, network, arg);
}
@Override
public boolean equals(Object o) {
@@ -1105,11 +1111,26 @@
}
@Override
+ public void onCapabilitiesChanged(Network network, NetworkCapabilities netCap) {
+ setLastCallback(CallbackState.NETWORK_CAPABILITIES, network, netCap);
+ }
+
+ @Override
+ public void onLinkPropertiesChanged(Network network, LinkProperties linkProp) {
+ setLastCallback(CallbackState.LINK_PROPERTIES, network, linkProp);
+ }
+
+ @Override
public void onUnavailable() {
setLastCallback(CallbackState.UNAVAILABLE, null, null);
}
@Override
+ public void onNetworkSuspended(Network network) {
+ setLastCallback(CallbackState.SUSPENDED, network, null);
+ }
+
+ @Override
public void onLosing(Network network, int maxMsToLive) {
setLastCallback(CallbackState.LOSING, network, maxMsToLive /* autoboxed int */);
}
@@ -1132,11 +1153,12 @@
return cb;
}
- void expectCallback(CallbackState state, MockNetworkAgent mockAgent, int timeoutMs) {
- CallbackInfo expected = new CallbackInfo(
- state, (mockAgent != null) ? mockAgent.getNetwork() : null, 0);
+ CallbackInfo expectCallback(CallbackState state, MockNetworkAgent agent, int timeoutMs) {
+ final Network expectedNetwork = (agent != null) ? agent.getNetwork() : null;
+ CallbackInfo expected = new CallbackInfo(state, expectedNetwork, 0);
CallbackInfo actual = nextCallback(timeoutMs);
assertEquals("Unexpected callback:", expected, actual);
+
if (state == CallbackState.LOSING) {
String msg = String.format(
"Invalid linger time value %d, must be between %d and %d",
@@ -1144,10 +1166,50 @@
int maxMsToLive = (Integer) actual.arg;
assertTrue(msg, 0 <= maxMsToLive && maxMsToLive <= TEST_LINGER_DELAY_MS);
}
+
+ return actual;
}
- void expectCallback(CallbackState state, MockNetworkAgent mockAgent) {
- expectCallback(state, mockAgent, TIMEOUT_MS);
+ CallbackInfo expectCallback(CallbackState state, MockNetworkAgent agent) {
+ return expectCallback(state, agent, TIMEOUT_MS);
+ }
+
+ void expectAvailableCallbacks(MockNetworkAgent agent, boolean expectSuspended, int timeoutMs) {
+ expectCallback(CallbackState.AVAILABLE, agent, timeoutMs);
+
+ final boolean HAS_DATASYNC_ON_AVAILABLE = false;
+ if (HAS_DATASYNC_ON_AVAILABLE) {
+ if (expectSuspended) {
+ expectCallback(CallbackState.SUSPENDED, agent, timeoutMs);
+ }
+ expectCallback(CallbackState.NETWORK_CAPABILITIES, agent, timeoutMs);
+ expectCallback(CallbackState.LINK_PROPERTIES, agent, timeoutMs);
+ }
+ }
+
+ void expectAvailableCallbacks(MockNetworkAgent agent) {
+ expectAvailableCallbacks(agent, false, TIMEOUT_MS);
+ }
+
+ void expectAvailableAndSuspendedCallbacks(MockNetworkAgent agent) {
+ expectAvailableCallbacks(agent, true, TIMEOUT_MS);
+ }
+
+ void expectAvailableAndValidatedCallbacks(MockNetworkAgent agent) {
+ expectAvailableCallbacks(agent, true, TIMEOUT_MS);
+ expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, agent);
+ }
+
+ void expectCapabilitiesWith(int capability, MockNetworkAgent agent) {
+ CallbackInfo cbi = expectCallback(CallbackState.NETWORK_CAPABILITIES, agent);
+ NetworkCapabilities nc = (NetworkCapabilities) cbi.arg;
+ assertTrue(nc.hasCapability(capability));
+ }
+
+ void expectCapabilitiesWithout(int capability, MockNetworkAgent agent) {
+ CallbackInfo cbi = expectCallback(CallbackState.NETWORK_CAPABILITIES, agent);
+ NetworkCapabilities nc = (NetworkCapabilities) cbi.arg;
+ assertFalse(nc.hasCapability(capability));
}
void assertNoCallback() {
@@ -1184,8 +1246,8 @@
ConditionVariable cv = waitForConnectivityBroadcasts(1);
mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
mCellNetworkAgent.connect(false);
- genericNetworkCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
- cellNetworkCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
+ genericNetworkCallback.expectAvailableCallbacks(mCellNetworkAgent);
+ cellNetworkCallback.expectAvailableCallbacks(mCellNetworkAgent);
assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork());
waitFor(cv);
assertNoCallbacks(genericNetworkCallback, wifiNetworkCallback, cellNetworkCallback);
@@ -1199,8 +1261,8 @@
cv = waitForConnectivityBroadcasts(2);
mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
mWiFiNetworkAgent.connect(false);
- genericNetworkCallback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent);
- wifiNetworkCallback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent);
+ genericNetworkCallback.expectAvailableCallbacks(mWiFiNetworkAgent);
+ wifiNetworkCallback.expectAvailableCallbacks(mWiFiNetworkAgent);
assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
waitFor(cv);
assertNoCallbacks(genericNetworkCallback, wifiNetworkCallback, cellNetworkCallback);
@@ -1223,8 +1285,8 @@
// Test validated networks
mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
mCellNetworkAgent.connect(true);
- genericNetworkCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
- cellNetworkCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
+ genericNetworkCallback.expectAvailableAndValidatedCallbacks(mCellNetworkAgent);
+ cellNetworkCallback.expectAvailableAndValidatedCallbacks(mCellNetworkAgent);
assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork());
assertNoCallbacks(genericNetworkCallback, wifiNetworkCallback, cellNetworkCallback);
@@ -1236,9 +1298,10 @@
mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
mWiFiNetworkAgent.connect(true);
- genericNetworkCallback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent);
+ genericNetworkCallback.expectAvailableCallbacks(mWiFiNetworkAgent);
genericNetworkCallback.expectCallback(CallbackState.LOSING, mCellNetworkAgent);
- wifiNetworkCallback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent);
+ genericNetworkCallback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
+ wifiNetworkCallback.expectAvailableAndValidatedCallbacks(mWiFiNetworkAgent);
cellNetworkCallback.expectCallback(CallbackState.LOSING, mCellNetworkAgent);
assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
assertNoCallbacks(genericNetworkCallback, wifiNetworkCallback, cellNetworkCallback);
@@ -1274,28 +1337,32 @@
mEthernetNetworkAgent.addCapability(NET_CAPABILITY_NOT_METERED);
mCellNetworkAgent.connect(true);
- callback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
- defaultCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
+ callback.expectAvailableAndValidatedCallbacks(mCellNetworkAgent);
+ defaultCallback.expectAvailableAndValidatedCallbacks(mCellNetworkAgent);
assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork());
mWiFiNetworkAgent.connect(true);
// We get AVAILABLE on wifi when wifi connects and satisfies our unmetered request.
// We then get LOSING when wifi validates and cell is outscored.
- callback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent);
+ callback.expectAvailableCallbacks(mWiFiNetworkAgent);
+ // TODO: Investigate sending validated before losing.
callback.expectCallback(CallbackState.LOSING, mCellNetworkAgent);
- defaultCallback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent);
+ callback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
+ defaultCallback.expectAvailableAndValidatedCallbacks(mWiFiNetworkAgent);
assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
mEthernetNetworkAgent.connect(true);
- callback.expectCallback(CallbackState.AVAILABLE, mEthernetNetworkAgent);
+ callback.expectAvailableCallbacks(mEthernetNetworkAgent);
+ // TODO: Investigate sending validated before losing.
callback.expectCallback(CallbackState.LOSING, mWiFiNetworkAgent);
- defaultCallback.expectCallback(CallbackState.AVAILABLE, mEthernetNetworkAgent);
+ callback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mEthernetNetworkAgent);
+ defaultCallback.expectAvailableAndValidatedCallbacks(mEthernetNetworkAgent);
assertEquals(mEthernetNetworkAgent.getNetwork(), mCm.getActiveNetwork());
mEthernetNetworkAgent.disconnect();
callback.expectCallback(CallbackState.LOST, mEthernetNetworkAgent);
defaultCallback.expectCallback(CallbackState.LOST, mEthernetNetworkAgent);
- defaultCallback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent);
+ defaultCallback.expectAvailableCallbacks(mWiFiNetworkAgent);
for (int i = 0; i < 4; i++) {
MockNetworkAgent oldNetwork, newNetwork;
@@ -1312,7 +1379,7 @@
callback.expectCallback(CallbackState.LOSING, oldNetwork);
// TODO: should we send an AVAILABLE callback to newNetwork, to indicate that it is no
// longer lingering?
- defaultCallback.expectCallback(CallbackState.AVAILABLE, newNetwork);
+ defaultCallback.expectAvailableCallbacks(newNetwork);
assertEquals(newNetwork.getNetwork(), mCm.getActiveNetwork());
}
assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
@@ -1320,17 +1387,19 @@
// Verify that if a network no longer satisfies a request, we send LOST and not LOSING, even
// if the network is still up.
mWiFiNetworkAgent.removeCapability(NET_CAPABILITY_NOT_METERED);
+ // We expect a notification about the capabilities change, and nothing else.
+ defaultCallback.expectCapabilitiesWithout(NET_CAPABILITY_NOT_METERED, mWiFiNetworkAgent);
+ defaultCallback.assertNoCallback();
callback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
// Wifi no longer satisfies our listen, which is for an unmetered network.
// But because its score is 55, it's still up (and the default network).
- defaultCallback.assertNoCallback();
assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
// Disconnect our test networks.
mWiFiNetworkAgent.disconnect();
defaultCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
- defaultCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
+ defaultCallback.expectAvailableCallbacks(mCellNetworkAgent);
mCellNetworkAgent.disconnect();
defaultCallback.expectCallback(CallbackState.LOST, mCellNetworkAgent);
@@ -1346,22 +1415,22 @@
mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
mCellNetworkAgent.connect(false); // Score: 10
- callback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
- defaultCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
+ callback.expectAvailableCallbacks(mCellNetworkAgent);
+ defaultCallback.expectAvailableCallbacks(mCellNetworkAgent);
assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork());
// Bring up wifi with a score of 20.
// Cell stays up because it would satisfy the default request if it validated.
mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
mWiFiNetworkAgent.connect(false); // Score: 20
- callback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent);
- defaultCallback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent);
+ callback.expectAvailableCallbacks(mWiFiNetworkAgent);
+ defaultCallback.expectAvailableCallbacks(mWiFiNetworkAgent);
assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
mWiFiNetworkAgent.disconnect();
callback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
defaultCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
- defaultCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
+ defaultCallback.expectAvailableCallbacks(mCellNetworkAgent);
assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork());
// Bring up wifi with a score of 70.
@@ -1369,31 +1438,33 @@
mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
mWiFiNetworkAgent.adjustScore(50);
mWiFiNetworkAgent.connect(false); // Score: 70
- callback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent);
+ callback.expectAvailableCallbacks(mWiFiNetworkAgent);
callback.expectCallback(CallbackState.LOSING, mCellNetworkAgent);
- defaultCallback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent);
+ defaultCallback.expectAvailableCallbacks(mWiFiNetworkAgent);
assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
// Tear down wifi.
mWiFiNetworkAgent.disconnect();
callback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
defaultCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
- defaultCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
+ defaultCallback.expectAvailableCallbacks(mCellNetworkAgent);
assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork());
// Bring up wifi, then validate it. Previous versions would immediately tear down cell, but
// it's arguably correct to linger it, since it was the default network before it validated.
mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
mWiFiNetworkAgent.connect(true);
- callback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent);
+ callback.expectAvailableCallbacks(mWiFiNetworkAgent);
+ // TODO: Investigate sending validated before losing.
callback.expectCallback(CallbackState.LOSING, mCellNetworkAgent);
- defaultCallback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent);
+ callback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
+ defaultCallback.expectAvailableAndValidatedCallbacks(mWiFiNetworkAgent);
assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
mWiFiNetworkAgent.disconnect();
callback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
defaultCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
- defaultCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
+ defaultCallback.expectAvailableCallbacks(mCellNetworkAgent);
mCellNetworkAgent.disconnect();
callback.expectCallback(CallbackState.LOST, mCellNetworkAgent);
defaultCallback.expectCallback(CallbackState.LOST, mCellNetworkAgent);
@@ -1401,13 +1472,15 @@
// If a network is lingering, and we add and remove a request from it, resume lingering.
mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
mCellNetworkAgent.connect(true);
- callback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
- defaultCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
+ callback.expectAvailableAndValidatedCallbacks(mCellNetworkAgent);
+ defaultCallback.expectAvailableAndValidatedCallbacks(mCellNetworkAgent);
mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
mWiFiNetworkAgent.connect(true);
- callback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent);
- defaultCallback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent);
+ defaultCallback.expectAvailableAndValidatedCallbacks(mWiFiNetworkAgent);
+ callback.expectAvailableCallbacks(mWiFiNetworkAgent);
+ // TODO: Investigate sending validated before losing.
callback.expectCallback(CallbackState.LOSING, mCellNetworkAgent);
+ callback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
NetworkRequest cellRequest = new NetworkRequest.Builder()
.addTransportType(TRANSPORT_CELLULAR).build();
@@ -1423,7 +1496,7 @@
mWiFiNetworkAgent.disconnect();
callback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
defaultCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
- defaultCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
+ defaultCallback.expectAvailableCallbacks(mCellNetworkAgent);
// Cell is now the default network. Pin it with a cell-specific request.
noopCallback = new NetworkCallback(); // Can't reuse NetworkCallbacks. http://b/20701525
@@ -1432,8 +1505,8 @@
// Now connect wifi, and expect it to become the default network.
mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
mWiFiNetworkAgent.connect(true);
- callback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent);
- defaultCallback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent);
+ callback.expectAvailableAndValidatedCallbacks(mWiFiNetworkAgent);
+ defaultCallback.expectAvailableAndValidatedCallbacks(mWiFiNetworkAgent);
// The default request is lingering on cell, but nothing happens to cell, and we send no
// callbacks for it, because it's kept up by cellRequest.
callback.assertNoCallback();
@@ -1619,7 +1692,7 @@
mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
mCellNetworkAgent.addCapability(NET_CAPABILITY_MMS);
mCellNetworkAgent.connectWithoutInternet();
- networkCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
+ networkCallback.expectAvailableCallbacks(mCellNetworkAgent);
verifyActiveNetwork(TRANSPORT_WIFI);
// Test releasing NetworkRequest disconnects cellular with MMS
cv = mCellNetworkAgent.getDisconnectedCV();
@@ -1645,7 +1718,7 @@
MockNetworkAgent mmsNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
mmsNetworkAgent.addCapability(NET_CAPABILITY_MMS);
mmsNetworkAgent.connectWithoutInternet();
- networkCallback.expectCallback(CallbackState.AVAILABLE, mmsNetworkAgent);
+ networkCallback.expectAvailableCallbacks(mmsNetworkAgent);
verifyActiveNetwork(TRANSPORT_CELLULAR);
// Test releasing MMS NetworkRequest does not disconnect main cellular NetworkAgent
cv = mmsNetworkAgent.getDisconnectedCV();
@@ -1671,7 +1744,7 @@
mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
String firstRedirectUrl = "http://example.com/firstPath";
mWiFiNetworkAgent.connectWithCaptivePortal(firstRedirectUrl);
- captivePortalCallback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent);
+ captivePortalCallback.expectAvailableCallbacks(mWiFiNetworkAgent);
assertEquals(mWiFiNetworkAgent.waitForRedirectUrl(), firstRedirectUrl);
// Take down network.
@@ -1684,7 +1757,7 @@
mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
String secondRedirectUrl = "http://example.com/secondPath";
mWiFiNetworkAgent.connectWithCaptivePortal(secondRedirectUrl);
- captivePortalCallback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent);
+ captivePortalCallback.expectAvailableCallbacks(mWiFiNetworkAgent);
assertEquals(mWiFiNetworkAgent.waitForRedirectUrl(), secondRedirectUrl);
// Make captive portal disappear then revalidate.
@@ -1694,7 +1767,9 @@
captivePortalCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
// Expect NET_CAPABILITY_VALIDATED onAvailable callback.
- validatedCallback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent);
+ validatedCallback.expectAvailableCallbacks(mWiFiNetworkAgent);
+ // TODO: Investigate only sending available callbacks.
+ validatedCallback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
// Break network connectivity.
// Expect NET_CAPABILITY_VALIDATED onLost callback.
@@ -1739,7 +1814,7 @@
mWiFiNetworkAgent.connectWithCaptivePortal(secondRedirectUrl);
// Expect NET_CAPABILITY_VALIDATED onAvailable callback.
- validatedCallback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent);
+ validatedCallback.expectAvailableCallbacks(mWiFiNetworkAgent);
// But there should be no CaptivePortal callback.
captivePortalCallback.assertNoCallback();
}
@@ -1792,14 +1867,14 @@
// Bring up cell and expect CALLBACK_AVAILABLE.
mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
mCellNetworkAgent.connect(true);
- cellNetworkCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
- defaultNetworkCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
+ cellNetworkCallback.expectAvailableAndValidatedCallbacks(mCellNetworkAgent);
+ defaultNetworkCallback.expectAvailableAndValidatedCallbacks(mCellNetworkAgent);
// Bring up wifi and expect CALLBACK_AVAILABLE.
mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
mWiFiNetworkAgent.connect(true);
cellNetworkCallback.assertNoCallback();
- defaultNetworkCallback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent);
+ defaultNetworkCallback.expectAvailableAndValidatedCallbacks(mWiFiNetworkAgent);
// Bring down cell. Expect no default network callback, since it wasn't the default.
mCellNetworkAgent.disconnect();
@@ -1809,7 +1884,7 @@
// Bring up cell. Expect no default network callback, since it won't be the default.
mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
mCellNetworkAgent.connect(true);
- cellNetworkCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
+ cellNetworkCallback.expectAvailableAndValidatedCallbacks(mCellNetworkAgent);
defaultNetworkCallback.assertNoCallback();
// Bring down wifi. Expect the default network callback to notified of LOST wifi
@@ -1817,28 +1892,16 @@
mWiFiNetworkAgent.disconnect();
cellNetworkCallback.assertNoCallback();
defaultNetworkCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
- defaultNetworkCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
+ defaultNetworkCallback.expectAvailableCallbacks(mCellNetworkAgent);
mCellNetworkAgent.disconnect();
cellNetworkCallback.expectCallback(CallbackState.LOST, mCellNetworkAgent);
defaultNetworkCallback.expectCallback(CallbackState.LOST, mCellNetworkAgent);
}
- private class TestRequestUpdateCallback extends TestNetworkCallback {
- @Override
- public void onCapabilitiesChanged(Network network, NetworkCapabilities netCap) {
- setLastCallback(CallbackState.NETWORK_CAPABILITIES, network, netCap);
- }
-
- @Override
- public void onLinkPropertiesChanged(Network network, LinkProperties linkProp) {
- setLastCallback(CallbackState.LINK_PROPERTIES, network, linkProp);
- }
- }
-
@SmallTest
- public void testRequestCallbackUpdates() throws Exception {
+ public void testAdditionalStateCallbacks() throws Exception {
// File a network request for mobile.
- final TestNetworkCallback cellNetworkCallback = new TestRequestUpdateCallback();
+ final TestNetworkCallback cellNetworkCallback = new TestNetworkCallback();
final NetworkRequest cellRequest = new NetworkRequest.Builder()
.addTransportType(TRANSPORT_CELLULAR).build();
mCm.requestNetwork(cellRequest, cellNetworkCallback);
@@ -1847,10 +1910,10 @@
mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
mCellNetworkAgent.connect(true);
- // We should get onAvailable().
- cellNetworkCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
- // We should get onCapabilitiesChanged(), when the mobile network successfully validates.
- cellNetworkCallback.expectCallback(CallbackState.NETWORK_CAPABILITIES, mCellNetworkAgent);
+ // We should get onAvailable(), onCapabilitiesChanged(), and
+ // onLinkPropertiesChanged() in rapid succession. Additionally, we
+ // should get onCapabilitiesChanged() when the mobile network validates.
+ cellNetworkCallback.expectAvailableAndValidatedCallbacks(mCellNetworkAgent);
cellNetworkCallback.assertNoCallback();
// Update LinkProperties.
@@ -1861,20 +1924,28 @@
cellNetworkCallback.expectCallback(CallbackState.LINK_PROPERTIES, mCellNetworkAgent);
cellNetworkCallback.assertNoCallback();
+ // Suspend the network.
+ mCellNetworkAgent.suspend();
+ cellNetworkCallback.expectCallback(CallbackState.SUSPENDED, mCellNetworkAgent);
+ cellNetworkCallback.assertNoCallback();
+
// Register a garden variety default network request.
- final TestNetworkCallback dfltNetworkCallback = new TestRequestUpdateCallback();
+ final TestNetworkCallback dfltNetworkCallback = new TestNetworkCallback();
mCm.registerDefaultNetworkCallback(dfltNetworkCallback);
- // Only onAvailable() is called; no other information is delivered.
- dfltNetworkCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
+ // We should get onAvailable(), onCapabilitiesChanged(), onLinkPropertiesChanged(),
+ // as well as onNetworkSuspended() in rapid succession.
+ dfltNetworkCallback.expectAvailableAndSuspendedCallbacks(mCellNetworkAgent);
dfltNetworkCallback.assertNoCallback();
// Request a NetworkCapabilities update; only the requesting callback is notified.
+ // TODO: Delete this together with Connectivity{Manager,Service} code.
mCm.requestNetworkCapabilities(dfltNetworkCallback);
dfltNetworkCallback.expectCallback(CallbackState.NETWORK_CAPABILITIES, mCellNetworkAgent);
cellNetworkCallback.assertNoCallback();
dfltNetworkCallback.assertNoCallback();
// Request a LinkProperties update; only the requesting callback is notified.
+ // TODO: Delete this together with Connectivity{Manager,Service} code.
mCm.requestLinkProperties(dfltNetworkCallback);
dfltNetworkCallback.expectCallback(CallbackState.LINK_PROPERTIES, mCellNetworkAgent);
cellNetworkCallback.assertNoCallback();
@@ -1917,18 +1988,20 @@
mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
mCellNetworkAgent.connect(true);
- callback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
- fgCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
+ callback.expectAvailableAndValidatedCallbacks(mCellNetworkAgent);
+ fgCallback.expectAvailableAndValidatedCallbacks(mCellNetworkAgent);
assertTrue(isForegroundNetwork(mCellNetworkAgent));
mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
mWiFiNetworkAgent.connect(true);
// When wifi connects, cell lingers.
- callback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent);
- fgCallback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent);
+ callback.expectAvailableCallbacks(mWiFiNetworkAgent);
callback.expectCallback(CallbackState.LOSING, mCellNetworkAgent);
+ callback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
+ fgCallback.expectAvailableCallbacks(mWiFiNetworkAgent);
fgCallback.expectCallback(CallbackState.LOSING, mCellNetworkAgent);
+ fgCallback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
assertTrue(isForegroundNetwork(mCellNetworkAgent));
assertTrue(isForegroundNetwork(mWiFiNetworkAgent));
@@ -1936,7 +2009,8 @@
mService.waitForIdle();
int timeoutMs = TEST_LINGER_DELAY_MS + TEST_LINGER_DELAY_MS / 4;
fgCallback.expectCallback(CallbackState.LOST, mCellNetworkAgent, timeoutMs);
- callback.assertNoCallback();
+ // Expect a network capabilities update sans FOREGROUND.
+ callback.expectCapabilitiesWithout(NET_CAPABILITY_FOREGROUND, mCellNetworkAgent);
assertFalse(isForegroundNetwork(mCellNetworkAgent));
assertTrue(isForegroundNetwork(mWiFiNetworkAgent));
@@ -1945,9 +2019,15 @@
.addTransportType(TRANSPORT_CELLULAR).build();
final TestNetworkCallback cellCallback = new TestNetworkCallback();
mCm.requestNetwork(cellRequest, cellCallback);
- cellCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
- fgCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
- callback.assertNoCallback(); // Because the network is already up.
+ // NOTE: This request causes the network's capabilities to change. This
+ // is currently delivered before the onAvailable() callbacks.
+ // TODO: Fix this.
+ cellCallback.expectCapabilitiesWith(NET_CAPABILITY_FOREGROUND, mCellNetworkAgent);
+ cellCallback.expectAvailableCallbacks(mCellNetworkAgent);
+ fgCallback.expectAvailableCallbacks(mCellNetworkAgent);
+ // Expect a network capabilities update with FOREGROUND, because the most recent
+ // request causes its state to change.
+ callback.expectCapabilitiesWith(NET_CAPABILITY_FOREGROUND, mCellNetworkAgent);
assertTrue(isForegroundNetwork(mCellNetworkAgent));
assertTrue(isForegroundNetwork(mWiFiNetworkAgent));
@@ -1955,7 +2035,8 @@
// lingering.
mCm.unregisterNetworkCallback(cellCallback);
fgCallback.expectCallback(CallbackState.LOST, mCellNetworkAgent);
- callback.assertNoCallback();
+ // Expect a network capabilities update sans FOREGROUND.
+ callback.expectCapabilitiesWithout(NET_CAPABILITY_FOREGROUND, mCellNetworkAgent);
assertFalse(isForegroundNetwork(mCellNetworkAgent));
assertTrue(isForegroundNetwork(mWiFiNetworkAgent));
@@ -1963,7 +2044,7 @@
mWiFiNetworkAgent.disconnect();
callback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
fgCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
- fgCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
+ fgCallback.expectAvailableCallbacks(mCellNetworkAgent);
assertTrue(isForegroundNetwork(mCellNetworkAgent));
mCm.unregisterNetworkCallback(callback);
@@ -2104,7 +2185,7 @@
mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
testFactory.expectAddRequests(2); // Because the cell request changes score twice.
mCellNetworkAgent.connect(true);
- cellNetworkCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
+ cellNetworkCallback.expectAvailableAndValidatedCallbacks(mCellNetworkAgent);
testFactory.waitForNetworkRequests(2);
assertFalse(testFactory.getMyStartRequested()); // Because the cell network outscores us.
@@ -2195,20 +2276,22 @@
// Bring up validated cell.
mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
mCellNetworkAgent.connect(true);
- cellNetworkCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
- defaultCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
+ cellNetworkCallback.expectAvailableAndValidatedCallbacks(mCellNetworkAgent);
+ defaultCallback.expectAvailableAndValidatedCallbacks(mCellNetworkAgent);
Network cellNetwork = mCellNetworkAgent.getNetwork();
// Bring up validated wifi.
mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
mWiFiNetworkAgent.connect(true);
- defaultCallback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent);
- validatedWifiCallback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent);
+ defaultCallback.expectAvailableAndValidatedCallbacks(mWiFiNetworkAgent);
+ validatedWifiCallback.expectAvailableCallbacks(mWiFiNetworkAgent);
+ validatedWifiCallback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
Network wifiNetwork = mWiFiNetworkAgent.getNetwork();
// Fail validation on wifi.
mWiFiNetworkAgent.getWrappedNetworkMonitor().gen204ProbeResult = 599;
mCm.reportNetworkConnectivity(wifiNetwork, false);
+ defaultCallback.expectCapabilitiesWithout(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
validatedWifiCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
// Because avoid bad wifi is off, we don't switch to cellular.
@@ -2223,18 +2306,18 @@
// that we switch back to cell.
tracker.configRestrictsAvoidBadWifi = false;
tracker.reevaluate();
- defaultCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
+ defaultCallback.expectAvailableCallbacks(mCellNetworkAgent);
assertEquals(mCm.getActiveNetwork(), cellNetwork);
// Switch back to a restrictive carrier.
tracker.configRestrictsAvoidBadWifi = true;
tracker.reevaluate();
- defaultCallback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent);
+ defaultCallback.expectAvailableCallbacks(mWiFiNetworkAgent);
assertEquals(mCm.getActiveNetwork(), wifiNetwork);
// Simulate the user selecting "switch" on the dialog, and check that we switch to cell.
mCm.setAvoidUnvalidated(wifiNetwork);
- defaultCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
+ defaultCallback.expectAvailableCallbacks(mCellNetworkAgent);
assertFalse(mCm.getNetworkCapabilities(wifiNetwork).hasCapability(
NET_CAPABILITY_VALIDATED));
assertTrue(mCm.getNetworkCapabilities(cellNetwork).hasCapability(
@@ -2245,13 +2328,15 @@
mWiFiNetworkAgent.disconnect();
mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
mWiFiNetworkAgent.connect(true);
- defaultCallback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent);
- validatedWifiCallback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent);
+ defaultCallback.expectAvailableAndValidatedCallbacks(mWiFiNetworkAgent);
+ validatedWifiCallback.expectAvailableCallbacks(mWiFiNetworkAgent);
+ validatedWifiCallback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
wifiNetwork = mWiFiNetworkAgent.getNetwork();
// Fail validation on wifi and expect the dialog to appear.
mWiFiNetworkAgent.getWrappedNetworkMonitor().gen204ProbeResult = 599;
mCm.reportNetworkConnectivity(wifiNetwork, false);
+ defaultCallback.expectCapabilitiesWithout(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
validatedWifiCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
// Simulate the user selecting "switch" and checking the don't ask again checkbox.
@@ -2259,7 +2344,7 @@
tracker.reevaluate();
// We now switch to cell.
- defaultCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
+ defaultCallback.expectAvailableCallbacks(mCellNetworkAgent);
assertFalse(mCm.getNetworkCapabilities(wifiNetwork).hasCapability(
NET_CAPABILITY_VALIDATED));
assertTrue(mCm.getNetworkCapabilities(cellNetwork).hasCapability(
@@ -2270,17 +2355,17 @@
// We switch to wifi and then to cell.
Settings.Global.putString(cr, Settings.Global.NETWORK_AVOID_BAD_WIFI, null);
tracker.reevaluate();
- defaultCallback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent);
+ defaultCallback.expectAvailableCallbacks(mWiFiNetworkAgent);
assertEquals(mCm.getActiveNetwork(), wifiNetwork);
Settings.Global.putInt(cr, Settings.Global.NETWORK_AVOID_BAD_WIFI, 1);
tracker.reevaluate();
- defaultCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
+ defaultCallback.expectAvailableCallbacks(mCellNetworkAgent);
assertEquals(mCm.getActiveNetwork(), cellNetwork);
// If cell goes down, we switch to wifi.
mCellNetworkAgent.disconnect();
defaultCallback.expectCallback(CallbackState.LOST, mCellNetworkAgent);
- defaultCallback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent);
+ defaultCallback.expectAvailableCallbacks(mWiFiNetworkAgent);
validatedWifiCallback.assertNoCallback();
mCm.unregisterNetworkCallback(cellNetworkCallback);
@@ -2322,7 +2407,7 @@
mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
mWiFiNetworkAgent.connect(false);
- networkCallback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent, timeoutMs);
+ networkCallback.expectAvailableCallbacks(mWiFiNetworkAgent, false, timeoutMs);
// pass timeout and validate that UNAVAILABLE is not called
networkCallback.assertNoCallback();
@@ -2343,7 +2428,7 @@
mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
mWiFiNetworkAgent.connect(false);
final int assertTimeoutMs = 150;
- networkCallback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent, assertTimeoutMs);
+ networkCallback.expectAvailableCallbacks(mWiFiNetworkAgent, false, assertTimeoutMs);
sleepFor(20);
mWiFiNetworkAgent.disconnect();
networkCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
diff --git a/tests/net/java/com/android/server/connectivity/MetricsTestUtil.java b/tests/net/java/com/android/server/connectivity/MetricsTestUtil.java
index e201012..c5965e8 100644
--- a/tests/net/java/com/android/server/connectivity/MetricsTestUtil.java
+++ b/tests/net/java/com/android/server/connectivity/MetricsTestUtil.java
@@ -17,101 +17,59 @@
package com.android.server.connectivity;
import android.net.ConnectivityMetricsEvent;
-import android.net.ConnectivityMetricsLogger;
import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
+import java.util.function.Consumer;
+
abstract public class MetricsTestUtil {
private MetricsTestUtil() {
}
- static ConnectivityMetricsEvent ipEv(Parcelable p) {
- return ev(ConnectivityMetricsLogger.COMPONENT_TAG_CONNECTIVITY, p);
+ static ConnectivityMetricsEvent ev(Parcelable p) {
+ return new ConnectivityMetricsEvent(1L, 0, 0, p);
}
- static ConnectivityMetricsEvent telephonyEv() {
- return ev(ConnectivityMetricsLogger.COMPONENT_TAG_TELEPHONY, new Bundle());
- }
-
- static ConnectivityMetricsEvent ev(int tag, Parcelable p) {
- return new ConnectivityMetricsEvent(1L, tag, 0, p);
- }
-
- // Utiliy interface for describing the content of a Parcel. This relies on
- // the implementation defails of Parcelable and on the fact that the fully
- // qualified Parcelable class names are written as string in the Parcels.
- interface ParcelField {
- void write(Parcel p);
- }
-
- static ConnectivityMetricsEvent describeIpEvent(ParcelField... fs) {
+ static ConnectivityMetricsEvent describeIpEvent(Consumer<Parcel>... fs) {
Parcel p = Parcel.obtain();
- for (ParcelField f : fs) {
- f.write(p);
+ for (Consumer<Parcel> f : fs) {
+ f.accept(p);
}
p.setDataPosition(0);
- return ipEv(p.readParcelable(ClassLoader.getSystemClassLoader()));
+ return ev(p.readParcelable(ClassLoader.getSystemClassLoader()));
}
- static ParcelField aType(Class<?> c) {
- return new ParcelField() {
- public void write(Parcel p) {
- p.writeString(c.getName());
- }
- };
+ static Consumer<Parcel> aType(Class<?> c) {
+ return aString(c.getName());
}
- static ParcelField aBool(boolean b) {
+ static Consumer<Parcel> aBool(boolean b) {
return aByte((byte) (b ? 1 : 0));
}
- static ParcelField aByte(byte b) {
- return new ParcelField() {
- public void write(Parcel p) {
- p.writeByte(b);
- }
- };
+ static Consumer<Parcel> aByte(byte b) {
+ return (p) -> p.writeByte(b);
}
- static ParcelField anInt(int i) {
- return new ParcelField() {
- public void write(Parcel p) {
- p.writeInt(i);
- }
- };
+ static Consumer<Parcel> anInt(int i) {
+ return (p) -> p.writeInt(i);
}
- static ParcelField aLong(long l) {
- return new ParcelField() {
- public void write(Parcel p) {
- p.writeLong(l);
- }
- };
+ static Consumer<Parcel> aLong(long l) {
+ return (p) -> p.writeLong(l);
}
- static ParcelField aString(String s) {
- return new ParcelField() {
- public void write(Parcel p) {
- p.writeString(s);
- }
- };
+ static Consumer<Parcel> aString(String s) {
+ return (p) -> p.writeString(s);
}
- static ParcelField aByteArray(byte... ary) {
- return new ParcelField() {
- public void write(Parcel p) {
- p.writeByteArray(ary);
- }
- };
+ static Consumer<Parcel> aByteArray(byte... ary) {
+ return (p) -> p.writeByteArray(ary);
}
- static ParcelField anIntArray(int... ary) {
- return new ParcelField() {
- public void write(Parcel p) {
- p.writeIntArray(ary);
- }
- };
+ static Consumer<Parcel> anIntArray(int... ary) {
+ return (p) -> p.writeIntArray(ary);
}
static byte b(int i) {
diff --git a/tests/net/java/com/android/server/connectivity/tethering/UpstreamNetworkMonitorTest.java b/tests/net/java/com/android/server/connectivity/tethering/UpstreamNetworkMonitorTest.java
index 3ed56df..c72efb0 100644
--- a/tests/net/java/com/android/server/connectivity/tethering/UpstreamNetworkMonitorTest.java
+++ b/tests/net/java/com/android/server/connectivity/tethering/UpstreamNetworkMonitorTest.java
@@ -32,6 +32,8 @@
import static org.mockito.Mockito.verifyNoMoreInteractions;
import android.content.Context;
+import android.os.Handler;
+import android.os.Message;
import android.net.ConnectivityManager;
import android.net.ConnectivityManager.NetworkCallback;
import android.net.IConnectivityManager;
@@ -42,6 +44,10 @@
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
+import com.android.internal.util.State;
+import com.android.internal.util.StateMachine;
+
+import org.junit.After;
import org.junit.Before;
import org.junit.runner.RunWith;
import org.junit.Test;
@@ -49,6 +55,7 @@
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
+import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
@@ -63,6 +70,7 @@
@Mock private Context mContext;
@Mock private IConnectivityManager mCS;
+ private TestStateMachine mSM;
private TestConnectivityManager mCM;
private UpstreamNetworkMonitor mUNM;
@@ -72,7 +80,15 @@
reset(mCS);
mCM = spy(new TestConnectivityManager(mContext, mCS));
- mUNM = new UpstreamNetworkMonitor(null, EVENT_UNM_UPDATE, (ConnectivityManager) mCM);
+ mSM = new TestStateMachine();
+ mUNM = new UpstreamNetworkMonitor(mSM, EVENT_UNM_UPDATE, (ConnectivityManager) mCM);
+ }
+
+ @After public void tearDown() throws Exception {
+ if (mSM != null) {
+ mSM.quit();
+ mSM = null;
+ }
}
@Test
@@ -139,15 +155,17 @@
mUNM.start();
verify(mCM, Mockito.times(1)).registerNetworkCallback(
- any(NetworkRequest.class), any(NetworkCallback.class));
- verify(mCM, Mockito.times(1)).registerDefaultNetworkCallback(any(NetworkCallback.class));
+ any(NetworkRequest.class), any(NetworkCallback.class), any(Handler.class));
+ verify(mCM, Mockito.times(1)).registerDefaultNetworkCallback(
+ any(NetworkCallback.class), any(Handler.class));
assertFalse(mUNM.mobileNetworkRequested());
assertEquals(0, mCM.requested.size());
mUNM.updateMobileRequiresDun(true);
mUNM.registerMobileNetworkRequest();
verify(mCM, Mockito.times(1)).requestNetwork(
- any(NetworkRequest.class), any(NetworkCallback.class), anyInt(), anyInt());
+ any(NetworkRequest.class), any(NetworkCallback.class), anyInt(), anyInt(),
+ any(Handler.class));
assertTrue(mUNM.mobileNetworkRequested());
assertUpstreamTypeRequested(TYPE_MOBILE_DUN);
@@ -224,6 +242,7 @@
}
public static class TestConnectivityManager extends ConnectivityManager {
+ public Map<NetworkCallback, Handler> allCallbacks = new HashMap<>();
public Set<NetworkCallback> trackingDefault = new HashSet<>();
public Map<NetworkCallback, NetworkRequest> listening = new HashMap<>();
public Map<NetworkCallback, NetworkRequest> requested = new HashMap<>();
@@ -234,7 +253,8 @@
}
boolean hasNoCallbacks() {
- return trackingDefault.isEmpty() &&
+ return allCallbacks.isEmpty() &&
+ trackingDefault.isEmpty() &&
listening.isEmpty() &&
requested.isEmpty() &&
legacyTypeMap.isEmpty();
@@ -262,14 +282,23 @@
}
@Override
- public void requestNetwork(NetworkRequest req, NetworkCallback cb) {
+ public void requestNetwork(NetworkRequest req, NetworkCallback cb, Handler h) {
+ assertFalse(allCallbacks.containsKey(cb));
+ allCallbacks.put(cb, h);
assertFalse(requested.containsKey(cb));
requested.put(cb, req);
}
@Override
+ public void requestNetwork(NetworkRequest req, NetworkCallback cb) {
+ fail("Should never be called.");
+ }
+
+ @Override
public void requestNetwork(NetworkRequest req, NetworkCallback cb,
- int timeoutMs, int legacyType) {
+ int timeoutMs, int legacyType, Handler h) {
+ assertFalse(allCallbacks.containsKey(cb));
+ allCallbacks.put(cb, h);
assertFalse(requested.containsKey(cb));
requested.put(cb, req);
assertFalse(legacyTypeMap.containsKey(cb));
@@ -279,18 +308,32 @@
}
@Override
- public void registerNetworkCallback(NetworkRequest req, NetworkCallback cb) {
+ public void registerNetworkCallback(NetworkRequest req, NetworkCallback cb, Handler h) {
+ assertFalse(allCallbacks.containsKey(cb));
+ allCallbacks.put(cb, h);
assertFalse(listening.containsKey(cb));
listening.put(cb, req);
}
@Override
- public void registerDefaultNetworkCallback(NetworkCallback cb) {
+ public void registerNetworkCallback(NetworkRequest req, NetworkCallback cb) {
+ fail("Should never be called.");
+ }
+
+ @Override
+ public void registerDefaultNetworkCallback(NetworkCallback cb, Handler h) {
+ assertFalse(allCallbacks.containsKey(cb));
+ allCallbacks.put(cb, h);
assertFalse(trackingDefault.contains(cb));
trackingDefault.add(cb);
}
@Override
+ public void registerDefaultNetworkCallback(NetworkCallback cb) {
+ fail("Should never be called.");
+ }
+
+ @Override
public void unregisterNetworkCallback(NetworkCallback cb) {
if (trackingDefault.contains(cb)) {
trackingDefault.remove(cb);
@@ -302,10 +345,35 @@
} else {
fail("Unexpected callback removed");
}
+ allCallbacks.remove(cb);
+ assertFalse(allCallbacks.containsKey(cb));
assertFalse(trackingDefault.contains(cb));
assertFalse(listening.containsKey(cb));
assertFalse(requested.containsKey(cb));
}
}
+
+ public static class TestStateMachine extends StateMachine {
+ public final ArrayList<Message> messages = new ArrayList<>();
+ private final State mLoggingState = new LoggingState();
+
+ class LoggingState extends State {
+ @Override public void enter() { messages.clear(); }
+
+ @Override public void exit() { messages.clear(); }
+
+ @Override public boolean processMessage(Message msg) {
+ messages.add(msg);
+ return true;
+ }
+ }
+
+ public TestStateMachine() {
+ super("UpstreamNetworkMonitor.TestStateMachine");
+ addState(mLoggingState);
+ setInitialState(mLoggingState);
+ super.start();
+ }
+ }
}
diff --git a/tools/aapt2/Resource.h b/tools/aapt2/Resource.h
index cffe8d5..493f238 100644
--- a/tools/aapt2/Resource.h
+++ b/tools/aapt2/Resource.h
@@ -118,6 +118,9 @@
bool is_valid() const;
};
+constexpr const uint8_t kAppPackageId = 0x7fu;
+constexpr const uint8_t kFrameworkPackageId = 0x01u;
+
/**
* A binary identifier representing a resource. Internally it
* is a 32bit integer split as follows:
diff --git a/tools/aapt2/ResourceUtils.cpp b/tools/aapt2/ResourceUtils.cpp
index 2d8e5a21..ca6738b 100644
--- a/tools/aapt2/ResourceUtils.cpp
+++ b/tools/aapt2/ResourceUtils.cpp
@@ -533,6 +533,7 @@
case android::Res_value::TYPE_REFERENCE:
case android::Res_value::TYPE_ATTRIBUTE:
case android::Res_value::TYPE_DYNAMIC_REFERENCE:
+ case android::Res_value::TYPE_DYNAMIC_ATTRIBUTE:
return android::ResTable_map::TYPE_REFERENCE;
case android::Res_value::TYPE_STRING:
diff --git a/tools/aapt2/ResourceValues.cpp b/tools/aapt2/ResourceValues.cpp
index f75ed7a..2868b2a 100644
--- a/tools/aapt2/ResourceValues.cpp
+++ b/tools/aapt2/ResourceValues.cpp
@@ -88,10 +88,24 @@
}
bool Reference::Flatten(android::Res_value* out_value) const {
- out_value->dataType = (reference_type == Reference::Type::kResource)
- ? android::Res_value::TYPE_REFERENCE
- : android::Res_value::TYPE_ATTRIBUTE;
- out_value->data = util::HostToDevice32(id ? id.value().id : 0);
+ const ResourceId resid = id.value_or_default(ResourceId(0));
+ const bool dynamic =
+ (resid.package_id() != kFrameworkPackageId && resid.package_id() != kAppPackageId);
+
+ if (reference_type == Reference::Type::kResource) {
+ if (dynamic) {
+ out_value->dataType = android::Res_value::TYPE_DYNAMIC_REFERENCE;
+ } else {
+ out_value->dataType = android::Res_value::TYPE_REFERENCE;
+ }
+ } else {
+ if (dynamic) {
+ out_value->dataType = android::Res_value::TYPE_DYNAMIC_ATTRIBUTE;
+ } else {
+ out_value->dataType = android::Res_value::TYPE_ATTRIBUTE;
+ }
+ }
+ out_value->data = util::HostToDevice32(resid.id);
return true;
}
diff --git a/tools/aapt2/java/JavaClassGenerator.cpp b/tools/aapt2/java/JavaClassGenerator.cpp
index 9c0f13c..68bdb95 100644
--- a/tools/aapt2/java/JavaClassGenerator.cpp
+++ b/tools/aapt2/java/JavaClassGenerator.cpp
@@ -533,9 +533,14 @@
std::unique_ptr<MethodDefinition> rewrite_method;
// Generate an onResourcesLoaded() callback if requested.
- if (options_.generate_rewrite_callback) {
+ if (options_.rewrite_callback_options) {
rewrite_method =
util::make_unique<MethodDefinition>("public static void onResourcesLoaded(int p)");
+ for (const std::string& package_to_callback :
+ options_.rewrite_callback_options.value().packages_to_callback) {
+ rewrite_method->AppendStatement(
+ StringPrintf("%s.R.onResourcesLoaded(p);", package_to_callback.data()));
+ }
}
for (const auto& package : table_->packages) {
diff --git a/tools/aapt2/java/JavaClassGenerator.h b/tools/aapt2/java/JavaClassGenerator.h
index 178f558..4510430 100644
--- a/tools/aapt2/java/JavaClassGenerator.h
+++ b/tools/aapt2/java/JavaClassGenerator.h
@@ -33,13 +33,19 @@
class ClassDefinition;
class MethodDefinition;
+// Options for generating onResourcesLoaded callback in R.java.
+struct OnResourcesLoadedCallbackOptions {
+ // Other R classes to delegate the same callback to (with the same package ID).
+ std::vector<std::string> packages_to_callback;
+};
+
struct JavaClassGeneratorOptions {
// Specifies whether to use the 'final' modifier on resource entries. Default is true.
bool use_final = true;
- // Whether to generate code to rewrite the package ID of resources.
- // Implies use_final == true. Default is false.
- bool generate_rewrite_callback = false;
+ // If set, generates code to rewrite the package ID of resources.
+ // Implies use_final == true. Default is unset.
+ Maybe<OnResourcesLoadedCallbackOptions> rewrite_callback_options;
enum class SymbolTypes {
kAll,
diff --git a/tools/aapt2/java/JavaClassGenerator_test.cpp b/tools/aapt2/java/JavaClassGenerator_test.cpp
index bcb2d4f..271279f 100644
--- a/tools/aapt2/java/JavaClassGenerator_test.cpp
+++ b/tools/aapt2/java/JavaClassGenerator_test.cpp
@@ -381,7 +381,9 @@
JavaClassGeneratorOptions options;
options.use_final = false;
- options.generate_rewrite_callback = true;
+ options.rewrite_callback_options = OnResourcesLoadedCallbackOptions{
+ {"com.foo", "com.boo"},
+ };
JavaClassGenerator generator(context.get(), table.get(), options);
std::stringstream out;
@@ -389,7 +391,9 @@
std::string actual = out.str();
- EXPECT_NE(std::string::npos, actual.find("onResourcesLoaded"));
+ EXPECT_NE(std::string::npos, actual.find("void onResourcesLoaded"));
+ EXPECT_NE(std::string::npos, actual.find("com.foo.R.onResourcesLoaded"));
+ EXPECT_NE(std::string::npos, actual.find("com.boo.R.onResourcesLoaded"));
}
} // namespace aapt
diff --git a/tools/aapt2/link/Link.cpp b/tools/aapt2/link/Link.cpp
index 4905216..dd8e14b 100644
--- a/tools/aapt2/link/Link.cpp
+++ b/tools/aapt2/link/Link.cpp
@@ -1097,18 +1097,15 @@
return false;
}
- std::unique_ptr<ResourceTable> table =
- LoadTablePbFromCollection(collection.get());
+ std::unique_ptr<ResourceTable> table = LoadTablePbFromCollection(collection.get());
if (!table) {
- context_->GetDiagnostics()->Error(DiagMessage(input)
- << "invalid static library");
+ context_->GetDiagnostics()->Error(DiagMessage(input) << "invalid static library");
return false;
}
ResourceTablePackage* pkg = table->FindPackageById(0x7f);
if (!pkg) {
- context_->GetDiagnostics()->Error(DiagMessage(input)
- << "static library has no package");
+ context_->GetDiagnostics()->Error(DiagMessage(input) << "static library has no package");
return false;
}
@@ -1125,11 +1122,9 @@
pkg->name = "";
if (override) {
- result = table_merger_->MergeOverlay(Source(input), table.get(),
- collection.get());
+ result = table_merger_->MergeOverlay(Source(input), table.get(), collection.get());
} else {
- result =
- table_merger_->Merge(Source(input), table.get(), collection.get());
+ result = table_merger_->Merge(Source(input), table.get(), collection.get());
}
} else {
@@ -1782,17 +1777,21 @@
}
if (options_.generate_java_class_path) {
- JavaClassGeneratorOptions options;
- options.types = JavaClassGeneratorOptions::SymbolTypes::kAll;
- options.javadoc_annotations = options_.javadoc_annotations;
+ // The set of packages whose R class to call in the main classes
+ // onResourcesLoaded callback.
+ std::vector<std::string> packages_to_callback;
+
+ JavaClassGeneratorOptions template_options;
+ template_options.types = JavaClassGeneratorOptions::SymbolTypes::kAll;
+ template_options.javadoc_annotations = options_.javadoc_annotations;
if (options_.package_type == PackageType::kStaticLib || options_.generate_non_final_ids) {
- options.use_final = false;
+ template_options.use_final = false;
}
if (options_.package_type == PackageType::kSharedLib) {
- options.use_final = false;
- options.generate_rewrite_callback = true;
+ template_options.use_final = false;
+ template_options.rewrite_callback_options = OnResourcesLoadedCallbackOptions{};
}
const StringPiece actual_package = context_->GetCompilationPackage();
@@ -1802,36 +1801,51 @@
output_package = options_.custom_java_package.value();
}
+ // Generate the private symbols if required.
if (options_.private_symbols) {
+ packages_to_callback.push_back(options_.private_symbols.value());
+
// If we defined a private symbols package, we only emit Public symbols
// to the original package, and private and public symbols to the
// private package.
-
- options.types = JavaClassGeneratorOptions::SymbolTypes::kPublic;
- if (!WriteJavaFile(&final_table_, context_->GetCompilationPackage(),
- output_package, options)) {
- return 1;
- }
-
+ JavaClassGeneratorOptions options = template_options;
options.types = JavaClassGeneratorOptions::SymbolTypes::kPublicPrivate;
- output_package = options_.private_symbols.value();
- }
-
- if (!WriteJavaFile(&final_table_, actual_package, output_package,
- options)) {
- return 1;
- }
-
- for (const std::string& extra_package : options_.extra_java_packages) {
- if (!WriteJavaFile(&final_table_, actual_package, extra_package,
+ if (!WriteJavaFile(&final_table_, actual_package, options_.private_symbols.value(),
options)) {
return 1;
}
}
+
+ // Generate all the symbols for all extra packages.
+ for (const std::string& extra_package : options_.extra_java_packages) {
+ packages_to_callback.push_back(extra_package);
+
+ JavaClassGeneratorOptions options = template_options;
+ options.types = JavaClassGeneratorOptions::SymbolTypes::kAll;
+ if (!WriteJavaFile(&final_table_, actual_package, extra_package, options)) {
+ return 1;
+ }
+ }
+
+ // Generate the main public R class.
+ JavaClassGeneratorOptions options = template_options;
+
+ // Only generate public symbols if we have a private package.
+ if (options_.private_symbols) {
+ options.types = JavaClassGeneratorOptions::SymbolTypes::kPublic;
+ }
+
+ if (options.rewrite_callback_options) {
+ options.rewrite_callback_options.value().packages_to_callback =
+ std::move(packages_to_callback);
+ }
+
+ if (!WriteJavaFile(&final_table_, actual_package, output_package, options)) {
+ return 1;
+ }
}
- if (!WriteProguardFile(options_.generate_proguard_rules_path,
- proguard_keep_set)) {
+ if (!WriteProguardFile(options_.generate_proguard_rules_path, proguard_keep_set)) {
return 1;
}
diff --git a/tools/aapt2/link/ManifestFixer.cpp b/tools/aapt2/link/ManifestFixer.cpp
index d5c0dc4..313fe45 100644
--- a/tools/aapt2/link/ManifestFixer.cpp
+++ b/tools/aapt2/link/ManifestFixer.cpp
@@ -79,6 +79,17 @@
return false;
}
+static xml::XmlNodeAction::ActionFuncWithDiag RequiredAndroidAttribute(const std::string& attr) {
+ return [=](xml::Element* el, SourcePathDiagnostics* diag) -> bool {
+ if (el->FindAttribute(xml::kSchemaAndroid, attr) == nullptr) {
+ diag->Error(DiagMessage(el->line_number)
+ << "<" << el->name << "> is missing required attribute 'android:" << attr << "'");
+ return false;
+ }
+ return true;
+ };
+}
+
static bool VerifyManifest(xml::Element* el, SourcePathDiagnostics* diag) {
xml::Attribute* attr = el->FindAttribute({}, "package");
if (!attr) {
@@ -272,6 +283,16 @@
application_action["uses-library"].Action(RequiredNameIsJavaPackage);
application_action["library"].Action(RequiredNameIsJavaPackage);
+
+ xml::XmlNodeAction& static_library_action = application_action["static-library"];
+ static_library_action.Action(RequiredNameIsJavaPackage);
+ static_library_action.Action(RequiredAndroidAttribute("version"));
+
+ xml::XmlNodeAction& uses_static_library_action = application_action["uses-static-library"];
+ uses_static_library_action.Action(RequiredNameIsJavaPackage);
+ uses_static_library_action.Action(RequiredAndroidAttribute("version"));
+ uses_static_library_action.Action(RequiredAndroidAttribute("certDigest"));
+
application_action["meta-data"] = meta_data_action;
application_action["activity"] = component_action;
application_action["activity-alias"] = component_action;
diff --git a/tools/aapt2/link/ReferenceLinker.cpp b/tools/aapt2/link/ReferenceLinker.cpp
index 4a42826..0331313 100644
--- a/tools/aapt2/link/ReferenceLinker.cpp
+++ b/tools/aapt2/link/ReferenceLinker.cpp
@@ -122,8 +122,7 @@
DiagMessage msg(entry.key.GetSource());
// Call the matches method again, this time with a DiagMessage so we
- // fill
- // in the actual error message.
+ // fill in the actual error message.
symbol->attribute->Matches(entry.value.get(), &msg);
context_->GetDiagnostics()->Error(msg);
error_ = true;
diff --git a/tools/aapt2/link/TableMerger.cpp b/tools/aapt2/link/TableMerger.cpp
index 7e7b9fb..9311091 100644
--- a/tools/aapt2/link/TableMerger.cpp
+++ b/tools/aapt2/link/TableMerger.cpp
@@ -39,14 +39,12 @@
bool TableMerger::Merge(const Source& src, ResourceTable* table,
io::IFileCollection* collection) {
- return MergeImpl(src, table, collection, false /* overlay */,
- true /* allow new */);
+ return MergeImpl(src, table, collection, false /* overlay */, true /* allow new */);
}
bool TableMerger::MergeOverlay(const Source& src, ResourceTable* table,
io::IFileCollection* collection) {
- return MergeImpl(src, table, collection, true /* overlay */,
- options_.auto_add_overlay);
+ return MergeImpl(src, table, collection, true /* overlay */, options_.auto_add_overlay);
}
/**
@@ -55,25 +53,13 @@
bool TableMerger::MergeImpl(const Source& src, ResourceTable* table,
io::IFileCollection* collection, bool overlay,
bool allow_new) {
- const uint8_t desired_package_id = context_->GetPackageId();
-
bool error = false;
for (auto& package : table->packages) {
- // Warn of packages with an unrelated ID.
- const Maybe<ResourceId>& id = package->id;
- if (id && id.value() != 0x0 && id.value() != desired_package_id) {
- context_->GetDiagnostics()->Warn(DiagMessage(src) << "ignoring package "
- << package->name);
- continue;
- }
-
// Only merge an empty package or the package we're building.
// Other packages may exist, which likely contain attribute definitions.
// This is because at compile time it is unknown if the attributes are
- // simply
- // uses of the attribute or definitions.
- if (package->name.empty() ||
- context_->GetCompilationPackage() == package->name) {
+ // simply uses of the attribute or definitions.
+ if (package->name.empty() || context_->GetCompilationPackage() == package->name) {
FileMergeCallback callback;
if (collection) {
callback = [&](const ResourceNameRef& name,
@@ -83,8 +69,7 @@
io::IFile* f = collection->FindFile(*old_file->path);
if (!f) {
context_->GetDiagnostics()->Error(DiagMessage(src)
- << "file '" << *old_file->path
- << "' not found");
+ << "file '" << *old_file->path << "' not found");
return false;
}
diff --git a/tools/aapt2/process/SymbolTable.cpp b/tools/aapt2/process/SymbolTable.cpp
index 5d75e76..bcafbca 100644
--- a/tools/aapt2/process/SymbolTable.cpp
+++ b/tools/aapt2/process/SymbolTable.cpp
@@ -293,6 +293,11 @@
std::unique_ptr<SymbolTable::Symbol> AssetManagerSymbolSource::FindById(
ResourceId id) {
+ if (!id.is_valid()) {
+ // Exit early and avoid the error logs from AssetManager.
+ return {};
+ }
+
const android::ResTable& table = assets_.getResources(false);
Maybe<ResourceName> maybe_name = GetResourceName(table, id);
if (!maybe_name) {
diff --git a/tools/aapt2/unflatten/BinaryResourceParser.cpp b/tools/aapt2/unflatten/BinaryResourceParser.cpp
index 29a921c..9158bdd 100644
--- a/tools/aapt2/unflatten/BinaryResourceParser.cpp
+++ b/tools/aapt2/unflatten/BinaryResourceParser.cpp
@@ -458,10 +458,14 @@
}
if (value->dataType == Res_value::TYPE_REFERENCE ||
- value->dataType == Res_value::TYPE_ATTRIBUTE) {
- const Reference::Type type = (value->dataType == Res_value::TYPE_REFERENCE)
- ? Reference::Type::kResource
- : Reference::Type::kAttribute;
+ value->dataType == Res_value::TYPE_ATTRIBUTE ||
+ value->dataType == Res_value::TYPE_DYNAMIC_REFERENCE ||
+ value->dataType == Res_value::TYPE_DYNAMIC_ATTRIBUTE) {
+ Reference::Type type = Reference::Type::kResource;
+ if (value->dataType == Res_value::TYPE_ATTRIBUTE ||
+ value->dataType == Res_value::TYPE_DYNAMIC_ATTRIBUTE) {
+ type = Reference::Type::kAttribute;
+ }
if (data == 0) {
// A reference of 0, must be the magic @null reference.
diff --git a/tools/fonts/fontchain_lint.py b/tools/fonts/fontchain_lint.py
index f193ea4..eb8a1cc 100755
--- a/tools/fonts/fontchain_lint.py
+++ b/tools/fonts/fontchain_lint.py
@@ -14,7 +14,9 @@
LANG_TO_SCRIPT = {
'as': 'Beng',
+ 'bg': 'Cyrl',
'bn': 'Beng',
+ 'cu': 'Cyrl',
'cy': 'Latn',
'da': 'Latn',
'de': 'Latn',
diff --git a/tools/layoutlib/bridge/src/android/graphics/drawable/VectorDrawable_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/drawable/VectorDrawable_Delegate.java
index 174bbcf..cc7631a 100644
--- a/tools/layoutlib/bridge/src/android/graphics/drawable/VectorDrawable_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/drawable/VectorDrawable_Delegate.java
@@ -571,6 +571,8 @@
@NonNull
public Consumer<Float> getFloatPropertySetter(int propertyIdx) {
switch (propertyIdx) {
+ case STROKE_WIDTH_INDEX:
+ return this::setStrokeWidth;
case STROKE_ALPHA_INDEX:
return this::setStrokeAlpha;
case FILL_ALPHA_INDEX:
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
index 3d5d5c6..04fdae9 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
@@ -106,7 +106,7 @@
import java.util.List;
import java.util.Map;
-import static android.os.Build.VERSION_CODES.JELLY_BEAN_MR1;
+import static android.os._Original_Build.VERSION_CODES.JELLY_BEAN_MR1;
import static com.android.layoutlib.bridge.android.RenderParamsFlags.FLAG_KEY_APPLICATION_PACKAGE;
/**
@@ -640,6 +640,10 @@
return AccessibilityManager.getInstance(this);
}
+ if (AUTO_FILL_MANAGER_SERVICE.equals(service)) {
+ return null;
+ }
+
throw new UnsupportedOperationException("Unsupported Service: " + service);
}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/Config.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/Config.java
index 5386b17..7f8d992 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/Config.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/Config.java
@@ -16,13 +16,13 @@
package com.android.layoutlib.bridge.bars;
-import android.os.Build.VERSION_CODES;
+import android.os._Original_Build.VERSION_CODES;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
-import static android.os.Build.VERSION_CODES.*;
+import static android.os._Original_Build.VERSION_CODES.*;
/**
* Various helper methods to simulate older versions of platform.
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/CustomBar.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/CustomBar.java
index a6e5fb8..8bb2c59 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/CustomBar.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/CustomBar.java
@@ -49,7 +49,7 @@
import java.io.IOException;
import java.io.InputStream;
-import static android.os.Build.VERSION_CODES.LOLLIPOP;
+import static android.os._Original_Build.VERSION_CODES.LOLLIPOP;
/**
* Base "bar" class for the window decor around the the edited layout.
diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/allwidgets.png b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/allwidgets.png
index a53dcba..f15d669 100644
--- a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/allwidgets.png
+++ b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/allwidgets.png
Binary files differ
diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/res/layout/allwidgets.xml b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/res/layout/allwidgets.xml
index 05a3665..456b5f6 100644
--- a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/res/layout/allwidgets.xml
+++ b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/res/layout/allwidgets.xml
@@ -263,7 +263,8 @@
android:id="@id/radioButton2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:text="New RadioButton" />
+ android:text="New RadioButton"
+ android:checked="true" />
</RadioGroup>
diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/AsmGenerator.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/AsmGenerator.java
index bed5806a..d59b419 100644
--- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/AsmGenerator.java
+++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/AsmGenerator.java
@@ -37,6 +37,7 @@
import java.util.jar.JarEntry;
import java.util.jar.JarOutputStream;
import java.util.stream.Collectors;
+import java.util.stream.Stream;
/**
* Class that generates a new JAR from a list of classes, some of which are to be kept as-is
@@ -127,7 +128,10 @@
// Create the map of classes to rename.
mRenameClasses = new HashMap<>();
mClassesNotRenamed = new HashSet<>();
- String[] renameClasses = createInfo.getRenamedClasses();
+ String[] renameClasses = Stream.concat(
+ Arrays.stream(createInfo.getRenamedClasses()),
+ Arrays.stream(createInfo.getRefactoredClasses()))
+ .toArray(String[]::new);
int n = renameClasses.length;
for (int i = 0; i < n; i += 2) {
assert i + 1 < n;
@@ -140,7 +144,10 @@
// Create a map of classes to be refactored.
mRefactorClasses = new HashMap<>();
- String[] refactorClasses = createInfo.getJavaPkgClasses();
+ String[] refactorClasses = Stream.concat(
+ Arrays.stream(createInfo.getJavaPkgClasses()),
+ Arrays.stream(createInfo.getRefactoredClasses()))
+ .toArray(String[]::new);
n = refactorClasses.length;
for (int i = 0; i < n; i += 2) {
assert i + 1 < n;
diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java
index a8582c6..b0aa3c2 100644
--- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java
+++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java
@@ -36,66 +36,42 @@
*/
public final class CreateInfo implements ICreateInfo {
- /**
- * Returns the list of class from layoutlib_create to inject in layoutlib.
- * The list can be empty but must not be null.
- */
@Override
public Class<?>[] getInjectedClasses() {
return INJECTED_CLASSES;
}
- /**
- * Returns the list of methods to rewrite as delegates.
- * The list can be empty but must not be null.
- */
@Override
public String[] getDelegateMethods() {
return DELEGATE_METHODS;
}
- /**
- * Returns the list of classes on which to delegate all native methods.
- * The list can be empty but must not be null.
- */
@Override
public String[] getDelegateClassNatives() {
return DELEGATE_CLASS_NATIVES;
}
- /**
- * Returns the list of classes to rename, must be an even list: the binary FQCN
- * of class to replace followed by the new FQCN.
- * The list can be empty but must not be null.
- */
@Override
public String[] getRenamedClasses() {
return RENAMED_CLASSES;
}
- /**
- * Returns the list of classes for which the methods returning them should be deleted.
- * The array contains a list of null terminated section starting with the name of the class
- * to rename in which the methods are deleted, followed by a list of return types identifying
- * the methods to delete.
- * The list can be empty but must not be null.
- */
@Override
public String[] getDeleteReturns() {
return DELETE_RETURNS;
}
- /**
- * Returns the list of classes to refactor, must be an even list: the binary FQCN of class to
- * replace followed by the new FQCN. All references to the old class should be updated to the
- * new class. The list can be empty but must not be null.
- */
@Override
public String[] getJavaPkgClasses() {
return JAVA_PKG_CLASSES;
}
@Override
+ public String[] getRefactoredClasses() {
+ return REFACTOR_CLASSES;
+ }
+
+ @Override
public Set<String> getExcludedClasses() {
String[] refactoredClasses = getJavaPkgClasses();
int count = refactoredClasses.length / 2 + EXCLUDED_CLASSES.length;
@@ -333,10 +309,22 @@
"java.text.SimpleDateFormat", "android.icu.text.SimpleDateFormat",
};
+ /**
+ * List of classes to refactor. This is similar to combining {@link #getRenamedClasses()} and
+ * {@link #getJavaPkgClasses()}.
+ * Classes included here will be renamed and then all their references in any other classes
+ * will be also modified.
+ * FQCN of class to refactor followed by its new FQCN.
+ */
+ private final static String[] REFACTOR_CLASSES =
+ new String[] {
+ "android.os.Build", "android.os._Original_Build",
+ };
+
private final static String[] EXCLUDED_CLASSES =
new String[] {
"android.preference.PreferenceActivity",
- "org.kxml2.io.KXmlParser"
+ "org.kxml2.io.KXmlParser",
};
/**
diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/ICreateInfo.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/ICreateInfo.java
index 48abde4..eca1c07 100644
--- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/ICreateInfo.java
+++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/ICreateInfo.java
@@ -52,6 +52,15 @@
String[] getRenamedClasses();
/**
+ * List of classes to refactor. This is similar to combining {@link #getRenamedClasses()} and
+ * {@link #getJavaPkgClasses()}.
+ * Classes included here will be renamed and then all their references in any other classes
+ * will be also modified.
+ * FQCN of class to refactor followed by its new FQCN.
+ */
+ String[] getRefactoredClasses();
+
+ /**
* Returns the list of classes for which the methods returning them should be deleted.
* The array contains a list of null terminated section starting with the name of the class
* to rename in which the methods are deleted, followed by a list of return types identifying
diff --git a/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/AsmGeneratorTest.java b/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/AsmGeneratorTest.java
index 4d5d5d2..e718fb9 100644
--- a/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/AsmGeneratorTest.java
+++ b/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/AsmGeneratorTest.java
@@ -35,6 +35,7 @@
import java.lang.reflect.Method;
import java.net.URL;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashSet;
@@ -54,8 +55,6 @@
* Unit tests for some methods of {@link AsmGenerator}.
*/
public class AsmGeneratorTest {
-
- private static final String[] EMPTY_STRING_ARRAY = new String[0];
private MockLog mLog;
private ArrayList<String> mOsJarPath;
private String mOsDestJar;
@@ -81,6 +80,7 @@
@After
public void tearDown() throws Exception {
if (mTempFile != null) {
+ //noinspection ResultOfMethodCallIgnored
mTempFile.delete();
mTempFile = null;
}
@@ -89,23 +89,7 @@
@Test
public void testClassRenaming() throws IOException, LogAbortException {
- ICreateInfo ci = new ICreateInfo() {
- @Override
- public Class<?>[] getInjectedClasses() {
- // classes to inject in the final JAR
- return new Class<?>[0];
- }
-
- @Override
- public String[] getDelegateMethods() {
- return EMPTY_STRING_ARRAY;
- }
-
- @Override
- public String[] getDelegateClassNatives() {
- return EMPTY_STRING_ARRAY;
- }
-
+ ICreateInfo ci = new CreateInfoAdapter() {
@Override
public String[] getRenamedClasses() {
// classes to rename (so that we can replace them)
@@ -114,37 +98,6 @@
"not.an.actual.ClassName", "anoter.fake.NewClassName",
};
}
-
- @Override
- public String[] getJavaPkgClasses() {
- return EMPTY_STRING_ARRAY;
- }
-
- @Override
- public Set<String> getExcludedClasses() {
- return null;
- }
-
- @Override
- public String[] getDeleteReturns() {
- // methods deleted from their return type.
- return EMPTY_STRING_ARRAY;
- }
-
- @Override
- public String[] getPromotedFields() {
- return EMPTY_STRING_ARRAY;
- }
-
- @Override
- public String[] getPromotedClasses() {
- return EMPTY_STRING_ARRAY;
- }
-
- @Override
- public Map<String, InjectMethodRunnable> getInjectedMethodsMap() {
- return Collections.emptyMap();
- }
};
AsmGenerator agen = new AsmGenerator(mLog, mOsDestJar, ci);
@@ -154,7 +107,7 @@
new String[] { // include classes
"**"
},
- Collections.<String>emptySet() /* excluded classes */,
+ Collections.emptySet() /* excluded classes */,
new String[]{} /* include files */);
aa.analyze();
agen.generate();
@@ -165,8 +118,8 @@
}
@Test
- public void testClassRefactoring() throws IOException, LogAbortException {
- ICreateInfo ci = new ICreateInfo() {
+ public void testJavaClassRefactoring() throws IOException, LogAbortException {
+ ICreateInfo ci = new CreateInfoAdapter() {
@Override
public Class<?>[] getInjectedClasses() {
// classes to inject in the final JAR
@@ -176,22 +129,6 @@
}
@Override
- public String[] getDelegateMethods() {
- return EMPTY_STRING_ARRAY;
- }
-
- @Override
- public String[] getDelegateClassNatives() {
- return EMPTY_STRING_ARRAY;
- }
-
- @Override
- public String[] getRenamedClasses() {
- // classes to rename (so that we can replace them)
- return EMPTY_STRING_ARRAY;
- }
-
- @Override
public String[] getJavaPkgClasses() {
// classes to refactor (so that we can replace them)
return new String[] {
@@ -203,27 +140,6 @@
public Set<String> getExcludedClasses() {
return Collections.singleton("java.lang.JavaClass");
}
-
- @Override
- public String[] getDeleteReturns() {
- // methods deleted from their return type.
- return EMPTY_STRING_ARRAY;
- }
-
- @Override
- public String[] getPromotedFields() {
- return EMPTY_STRING_ARRAY;
- }
-
- @Override
- public String[] getPromotedClasses() {
- return EMPTY_STRING_ARRAY;
- }
-
- @Override
- public Map<String, InjectMethodRunnable> getInjectedMethodsMap() {
- return Collections.emptyMap();
- }
};
AsmGenerator agen = new AsmGenerator(mLog, mOsDestJar, ci);
@@ -233,7 +149,7 @@
new String[] { // include classes
"**"
},
- Collections.<String>emptySet(),
+ Collections.emptySet(),
new String[] { /* include files */
"mock_android/data/data*"
});
@@ -242,47 +158,64 @@
Map<String, ClassReader> output = new TreeMap<>();
Map<String, InputStream> filesFound = new TreeMap<>();
parseZip(mOsDestJar, output, filesFound);
- boolean injectedClassFound = false;
+ RecordingClassVisitor cv = new RecordingClassVisitor();
for (ClassReader cr: output.values()) {
- TestClassVisitor cv = new TestClassVisitor();
cr.accept(cv, 0);
- injectedClassFound |= cv.mInjectedClassFound;
}
- assertTrue(injectedClassFound);
+ assertTrue(cv.mVisitedClasses.contains(
+ "com/android/tools/layoutlib/create/dataclass/JavaClass"));
+ assertFalse(cv.mVisitedClasses.contains(
+ JAVA_CLASS_NAME));
assertArrayEquals(new String[] {"mock_android/data/dataFile"},
filesFound.keySet().toArray());
}
@Test
- public void testClassExclusion() throws IOException, LogAbortException {
- ICreateInfo ci = new ICreateInfo() {
+ public void testClassRefactoring() throws IOException, LogAbortException {
+ ICreateInfo ci = new CreateInfoAdapter() {
@Override
public Class<?>[] getInjectedClasses() {
- return new Class<?>[0];
+ // classes to inject in the final JAR
+ return new Class<?>[] {
+ com.android.tools.layoutlib.create.dataclass.JavaClass.class
+ };
}
@Override
- public String[] getDelegateMethods() {
- return EMPTY_STRING_ARRAY;
- }
-
- @Override
- public String[] getDelegateClassNatives() {
- return EMPTY_STRING_ARRAY;
- }
-
- @Override
- public String[] getRenamedClasses() {
- // classes to rename (so that we can replace them)
- return EMPTY_STRING_ARRAY;
- }
-
- @Override
- public String[] getJavaPkgClasses() {
+ public String[] getRefactoredClasses() {
// classes to refactor (so that we can replace them)
- return EMPTY_STRING_ARRAY;
+ return new String[] {
+ "mock_android.view.View", "mock_android.view._Original_View",
+ };
}
+ };
+ AsmGenerator agen = new AsmGenerator(mLog, mOsDestJar, ci);
+
+ AsmAnalyzer aa = new AsmAnalyzer(mLog, mOsJarPath, agen,
+ null, // derived from
+ new String[] { // include classes
+ "**"
+ },
+ Collections.emptySet(),
+ new String[] {});
+ aa.analyze();
+ agen.generate();
+ Map<String, ClassReader> output = new TreeMap<>();
+ parseZip(mOsDestJar, output, new TreeMap<>());
+ RecordingClassVisitor cv = new RecordingClassVisitor();
+ for (ClassReader cr: output.values()) {
+ cr.accept(cv, 0);
+ }
+ assertTrue(cv.mVisitedClasses.contains(
+ "mock_android/view/_Original_View"));
+ assertFalse(cv.mVisitedClasses.contains(
+ "mock_android/view/View"));
+ }
+
+ @Test
+ public void testClassExclusion() throws IOException, LogAbortException {
+ ICreateInfo ci = new CreateInfoAdapter() {
@Override
public Set<String> getExcludedClasses() {
Set<String> set = new HashSet<>(2);
@@ -290,27 +223,6 @@
set.add("java.lang.JavaClass");
return set;
}
-
- @Override
- public String[] getDeleteReturns() {
- // methods deleted from their return type.
- return EMPTY_STRING_ARRAY;
- }
-
- @Override
- public String[] getPromotedFields() {
- return EMPTY_STRING_ARRAY;
- }
-
- @Override
- public String[] getPromotedClasses() {
- return EMPTY_STRING_ARRAY;
- }
-
- @Override
- public Map<String, InjectMethodRunnable> getInjectedMethodsMap() {
- return Collections.emptyMap();
- }
};
AsmGenerator agen = new AsmGenerator(mLog, mOsDestJar, ci);
@@ -340,55 +252,7 @@
public void testMethodInjection() throws IOException, LogAbortException,
ClassNotFoundException, IllegalAccessException, InstantiationException,
NoSuchMethodException, InvocationTargetException {
- ICreateInfo ci = new ICreateInfo() {
- @Override
- public Class<?>[] getInjectedClasses() {
- return new Class<?>[0];
- }
-
- @Override
- public String[] getDelegateMethods() {
- return EMPTY_STRING_ARRAY;
- }
-
- @Override
- public String[] getDelegateClassNatives() {
- return EMPTY_STRING_ARRAY;
- }
-
- @Override
- public String[] getRenamedClasses() {
- // classes to rename (so that we can replace them)
- return EMPTY_STRING_ARRAY;
- }
-
- @Override
- public String[] getJavaPkgClasses() {
- // classes to refactor (so that we can replace them)
- return EMPTY_STRING_ARRAY;
- }
-
- @Override
- public Set<String> getExcludedClasses() {
- return Collections.emptySet();
- }
-
- @Override
- public String[] getDeleteReturns() {
- // methods deleted from their return type.
- return EMPTY_STRING_ARRAY;
- }
-
- @Override
- public String[] getPromotedFields() {
- return EMPTY_STRING_ARRAY;
- }
-
- @Override
- public String[] getPromotedClasses() {
- return EMPTY_STRING_ARRAY;
- }
-
+ ICreateInfo ci = new CreateInfoAdapter() {
@Override
public Map<String, InjectMethodRunnable> getInjectedMethodsMap() {
return Collections.singletonMap("mock_android.util.EmptyArray",
@@ -474,97 +338,94 @@
}
}
- private class TestClassVisitor extends ClassVisitor {
+ /**
+ * {@link ClassVisitor} that records every class that sees.
+ */
+ private static class RecordingClassVisitor extends ClassVisitor {
+ private Set<String> mVisitedClasses = new HashSet<>();
- boolean mInjectedClassFound = false;
-
- TestClassVisitor() {
+ private RecordingClassVisitor() {
super(Main.ASM_VERSION);
}
- @Override
- public void visit(int version, int access, String name, String signature,
- String superName, String[] interfaces) {
- assertTrue(!getBase(name).equals(JAVA_CLASS_NAME));
- if (name.equals("com/android/tools/layoutlib/create/dataclass/JavaClass")) {
- mInjectedClassFound = true;
+ private void addClass(String className) {
+ if (className == null) {
+ return;
}
- super.visit(version, access, name, signature, superName, interfaces);
+
+ int pos = className.indexOf('$');
+ if (pos > 0) {
+ // For inner classes, add also the base class
+ mVisitedClasses.add(className.substring(0, pos));
+ }
+ mVisitedClasses.add(className);
}
@Override
- public FieldVisitor visitField(int access, String name, String desc,
- String signature, Object value) {
- assertTrue(testType(Type.getType(desc)));
+ public void visit(int version, int access, String name, String signature, String superName,
+ String[] interfaces) {
+ addClass(superName);
+ Arrays.stream(interfaces).forEach(this::addClass);
+ }
+
+ private void processType(Type type) {
+ switch (type.getSort()) {
+ case Type.OBJECT:
+ addClass(type.getInternalName());
+ break;
+ case Type.ARRAY:
+ addClass(type.getElementType().getInternalName());
+ break;
+ case Type.METHOD:
+ processType(type.getReturnType());
+ Arrays.stream(type.getArgumentTypes()).forEach(this::processType);
+ break;
+ }
+ }
+
+ @Override
+ public FieldVisitor visitField(int access, String name, String desc, String signature,
+ Object value) {
+ processType(Type.getType(desc));
return super.visitField(access, name, desc, signature, value);
}
- @SuppressWarnings("hiding")
@Override
- public MethodVisitor visitMethod(int access, String name, String desc,
- String signature, String[] exceptions) {
+ public MethodVisitor visitMethod(int access, String name, String desc, String signature,
+ String[] exceptions) {
MethodVisitor mv = super.visitMethod(access, name, desc, signature, exceptions);
return new MethodVisitor(Main.ASM_VERSION, mv) {
@Override
- public void visitFieldInsn(int opcode, String owner, String name,
- String desc) {
- assertTrue(!getBase(owner).equals(JAVA_CLASS_NAME));
- assertTrue(testType(Type.getType(desc)));
+ public void visitFieldInsn(int opcode, String owner, String name, String desc) {
+ addClass(owner);
+ processType(Type.getType(desc));
super.visitFieldInsn(opcode, owner, name, desc);
}
@Override
public void visitLdcInsn(Object cst) {
if (cst instanceof Type) {
- assertTrue(testType((Type)cst));
+ processType((Type) cst);
}
super.visitLdcInsn(cst);
}
@Override
public void visitTypeInsn(int opcode, String type) {
- assertTrue(!getBase(type).equals(JAVA_CLASS_NAME));
+ addClass(type);
super.visitTypeInsn(opcode, type);
}
@Override
- public void visitMethodInsn(int opcode, String owner, String name,
- String desc, boolean itf) {
- assertTrue(!getBase(owner).equals(JAVA_CLASS_NAME));
- assertTrue(testType(Type.getType(desc)));
+ public void visitMethodInsn(int opcode, String owner, String name, String desc,
+ boolean itf) {
+ addClass(owner);
+ processType(Type.getType(desc));
super.visitMethodInsn(opcode, owner, name, desc, itf);
}
};
}
-
- private boolean testType(Type type) {
- int sort = type.getSort();
- if (sort == Type.OBJECT) {
- assertTrue(!getBase(type.getInternalName()).equals(JAVA_CLASS_NAME));
- } else if (sort == Type.ARRAY) {
- assertTrue(!getBase(type.getElementType().getInternalName())
- .equals(JAVA_CLASS_NAME));
- } else if (sort == Type.METHOD) {
- boolean r = true;
- for (Type t : type.getArgumentTypes()) {
- r &= testType(t);
- }
- return r & testType(type.getReturnType());
- }
- return true;
- }
-
- private String getBase(String className) {
- if (className == null) {
- return null;
- }
- int pos = className.indexOf('$');
- if (pos > 0) {
- return className.substring(0, pos);
- }
- return className;
- }
}
}
diff --git a/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/CreateInfoAdapter.java b/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/CreateInfoAdapter.java
new file mode 100644
index 0000000..ad7cb9a
--- /dev/null
+++ b/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/CreateInfoAdapter.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2017 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.tools.layoutlib.create;
+
+import java.util.Collections;
+import java.util.Map;
+import java.util.Set;
+
+class CreateInfoAdapter implements ICreateInfo {
+ private static final String[] EMPTY_STRING_ARRAY = new String[0];
+
+ @Override
+ public Class<?>[] getInjectedClasses() {
+ return new Class<?>[0];
+ }
+
+ @Override
+ public String[] getDelegateMethods() {
+ return EMPTY_STRING_ARRAY;
+ }
+
+ @Override
+ public String[] getDelegateClassNatives() {
+ return EMPTY_STRING_ARRAY;
+ }
+
+ @Override
+ public String[] getRenamedClasses() {
+ return EMPTY_STRING_ARRAY;
+ }
+
+ @Override
+ public String[] getRefactoredClasses() {
+ return EMPTY_STRING_ARRAY;
+ }
+
+ @Override
+ public String[] getDeleteReturns() {
+ return EMPTY_STRING_ARRAY;
+ }
+
+ @Override
+ public String[] getJavaPkgClasses() {
+ return EMPTY_STRING_ARRAY;
+ }
+
+ @Override
+ public Set<String> getExcludedClasses() {
+ return Collections.emptySet();
+ }
+
+ @Override
+ public String[] getPromotedFields() {
+ return EMPTY_STRING_ARRAY;
+ }
+
+ @Override
+ public String[] getPromotedClasses() {
+ return EMPTY_STRING_ARRAY;
+ }
+
+ @Override
+ public Map<String, InjectMethodRunnable> getInjectedMethodsMap() {
+ return Collections.emptyMap();
+ }
+}
diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java
index 3eb9934..a4ab64f 100644
--- a/wifi/java/android/net/wifi/WifiConfiguration.java
+++ b/wifi/java/android/net/wifi/WifiConfiguration.java
@@ -1305,6 +1305,7 @@
setConnectChoice(source.getConnectChoice());
setConnectChoiceTimestamp(source.getConnectChoiceTimestamp());
setHasEverConnected(source.getHasEverConnected());
+ setNotRecommended(source.isNotRecommended());
}
public void writeToParcel(Parcel dest) {
diff --git a/wifi/java/android/net/wifi/aware/DiscoverySession.java b/wifi/java/android/net/wifi/aware/DiscoverySession.java
index adf189b..59fe1ee 100644
--- a/wifi/java/android/net/wifi/aware/DiscoverySession.java
+++ b/wifi/java/android/net/wifi/aware/DiscoverySession.java
@@ -31,8 +31,7 @@
* {@link PublishDiscoverySession} and {@link SubscribeDiscoverySession}. This
* class provides functionality common to both publish and subscribe discovery sessions:
* <ul>
- * <li>Sending messages: {@link #sendMessage(PeerHandle, int, byte[])} or
- * {@link #sendMessage(PeerHandle, int, byte[], int)} methods.
+ * <li>Sending messages: {@link #sendMessage(PeerHandle, int, byte[])} method.
* <li>Creating a network-specifier when requesting a Aware connection:
* {@link #createNetworkSpecifier(PeerHandle, byte[])}.
* </ul>
@@ -62,6 +61,8 @@
* {@link #sendMessage(PeerHandle, int, byte[], int)}.
*
* @return Maximum retry count when sending messages.
+ *
+ * @hide
*/
public static int getMaxSendRetryCount() {
return MAX_SEND_RETRY_COUNT;
@@ -163,6 +164,8 @@
* or MAC level) retries should be attempted if there is no ACK from the receiver
* (note: no retransmissions are attempted in other failure cases). A value of 0
* indicates no retries. Max permitted value is {@link #getMaxSendRetryCount()}.
+ *
+ * @hide
*/
public void sendMessage(@NonNull PeerHandle peerHandle, int messageId,
@Nullable byte[] message, int retryCount) {
@@ -195,8 +198,6 @@
* The peer will get a callback indicating a message was received using
* {@link DiscoverySessionCallback#onMessageReceived(PeerHandle,
* byte[])}.
- * Equivalent to {@link #sendMessage(PeerHandle, int, byte[], int)}
- * with a {@code retryCount} of 0.
*
* @param peerHandle The peer's handle for the message. Must be a result of an
* {@link DiscoverySessionCallback#onServiceDiscovered(PeerHandle,
@@ -246,8 +247,8 @@
}
/**
- * Create a {@link android.net.NetworkRequest.Builder#setNetworkSpecifier(String)} for a
- * WiFi Aware connection to the specified peer. The
+ * Create a {@link android.net.NetworkRequest.Builder#setNetworkSpecifier(String)} for an
+ * unencrypted WiFi Aware connection (link) to the specified peer. The
* {@link android.net.NetworkRequest.Builder#addTransportType(int)} should be set to
* {@link android.net.NetworkCapabilities#TRANSPORT_WIFI_AWARE}.
* <p>
@@ -255,7 +256,58 @@
* discovery or communication (in such scenarios the MAC address of the peer is shielded by
* an opaque peer ID handle). If a Aware connection is needed to a peer discovered using other
* OOB (out-of-band) mechanism then use the alternative
- * {@link WifiAwareSession#createNetworkSpecifier(int, byte[], byte[])} method - which uses the
+ * {@link WifiAwareSession#createNetworkSpecifierOpen(int, byte[])} method - which uses the
+ * peer's MAC address.
+ * <p>
+ * Note: per the Wi-Fi Aware specification the roles are fixed - a Subscriber is an INITIATOR
+ * and a Publisher is a RESPONDER.
+ *
+ * @param peerHandle The peer's handle obtained through
+ * {@link DiscoverySessionCallback#onServiceDiscovered(PeerHandle, byte[], java.util.List)}
+ * or
+ * {@link DiscoverySessionCallback#onMessageReceived(PeerHandle, byte[])}.
+ * On a RESPONDER this value is used to gate the acceptance of a connection
+ * request from only that peer. A RESPONDER may specify a null - indicating
+ * that it will accept connection requests from any device.
+ *
+ * @return A string to be used to construct
+ * {@link android.net.NetworkRequest.Builder#setNetworkSpecifier(String)} to pass to
+ * {@link android.net.ConnectivityManager#requestNetwork(android.net.NetworkRequest,
+ * android.net.ConnectivityManager.NetworkCallback)}
+ * [or other varieties of that API].
+ *
+ * @hide
+ */
+ public String createNetworkSpecifierOpen(@Nullable PeerHandle peerHandle) {
+ if (mTerminated) {
+ Log.w(TAG, "createNetworkSpecifierOpen: called on terminated session");
+ return null;
+ } else {
+ WifiAwareManager mgr = mMgr.get();
+ if (mgr == null) {
+ Log.w(TAG, "createNetworkSpecifierOpen: called post GC on WifiAwareManager");
+ return null;
+ }
+
+ int role = this instanceof SubscribeDiscoverySession
+ ? WifiAwareManager.WIFI_AWARE_DATA_PATH_ROLE_INITIATOR
+ : WifiAwareManager.WIFI_AWARE_DATA_PATH_ROLE_RESPONDER;
+
+ return mgr.createNetworkSpecifier(mClientId, role, mSessionId, peerHandle, null);
+ }
+ }
+
+ /**
+ * Create a {@link android.net.NetworkRequest.Builder#setNetworkSpecifier(String)} for an
+ * encrypted WiFi Aware connection (link) to the specified peer. The
+ * {@link android.net.NetworkRequest.Builder#addTransportType(int)} should be set to
+ * {@link android.net.NetworkCapabilities#TRANSPORT_WIFI_AWARE}.
+ * <p>
+ * This method should be used when setting up a connection with a peer discovered through Aware
+ * discovery or communication (in such scenarios the MAC address of the peer is shielded by
+ * an opaque peer ID handle). If a Aware connection is needed to a peer discovered using other
+ * OOB (out-of-band) mechanism then use the alternative
+ * {@link WifiAwareSession#createNetworkSpecifierPmk(int, byte[], byte[])} method - which uses the
* peer's MAC address.
* <p>
* Note: per the Wi-Fi Aware specification the roles are fixed - a Subscriber is an INITIATOR
@@ -266,29 +318,34 @@
* byte[], java.util.List)} or
* {@link DiscoverySessionCallback#onMessageReceived(PeerHandle,
* byte[])}. On a RESPONDER this value is used to gate the acceptance of a connection request
- * from only that peer. A RESPONDER may specified a null - indicating that
+ * from only that peer. A RESPONDER may specify a null - indicating that
* it will accept connection requests from any device.
- * @param token An arbitrary token (message) to be used to match connection initiation request
- * to a responder setup. A RESPONDER is set up with a {@code token} which must
- * be matched by the token provided by the INITIATOR. A null token is permitted
- * on the RESPONDER and matches any peer token. An empty ({@code ""}) token is
- * not the same as a null token and requires the peer token to be empty as well.
+ * @param pmk A PMK (pairwise master key, see IEEE 802.11i) specifying the key to use for
+ * encrypting the data-path. Use the
+ * {@link #createNetworkSpecifierOpen(PeerHandle)} to specify an open (unencrypted)
+ * link.
*
* @return A string to be used to construct
* {@link android.net.NetworkRequest.Builder#setNetworkSpecifier(String)} to pass to
* {@link android.net.ConnectivityManager#requestNetwork(android.net.NetworkRequest,
* android.net.ConnectivityManager.NetworkCallback)}
* [or other varieties of that API].
+ *
+ * @hide
*/
- public String createNetworkSpecifier(@Nullable PeerHandle peerHandle,
- @Nullable byte[] token) {
+ public String createNetworkSpecifierPmk(@Nullable PeerHandle peerHandle,
+ @NonNull byte[] pmk) {
+ if (pmk == null || pmk.length == 0) {
+ throw new IllegalArgumentException("PMK must not be null or empty");
+ }
+
if (mTerminated) {
- Log.w(TAG, "createNetworkSpecifier: called on terminated session");
+ Log.w(TAG, "createNetworkSpecifierPmk: called on terminated session");
return null;
} else {
WifiAwareManager mgr = mMgr.get();
if (mgr == null) {
- Log.w(TAG, "createNetworkSpecifier: called post GC on WifiAwareManager");
+ Log.w(TAG, "createNetworkSpecifierPmk: called post GC on WifiAwareManager");
return null;
}
@@ -296,7 +353,30 @@
? WifiAwareManager.WIFI_AWARE_DATA_PATH_ROLE_INITIATOR
: WifiAwareManager.WIFI_AWARE_DATA_PATH_ROLE_RESPONDER;
- return mgr.createNetworkSpecifier(mClientId, role, mSessionId, peerHandle, token);
+ return mgr.createNetworkSpecifier(mClientId, role, mSessionId, peerHandle, pmk);
}
}
+
+ /**
+ * Place-holder for {@code createNetworkSpecifierOpen(PeerHandle)}. Present to enable
+ * development of replacements CL without causing an API change. Will be removed when new
+ * APIs are exposed.
+ *
+ * @param peerHandle The peer's handle obtained through
+ * {@link DiscoverySessionCallback#onServiceDiscovered(PeerHandle,
+ * byte[], java.util.List)} or
+ * {@link DiscoverySessionCallback#onMessageReceived(PeerHandle,
+ * byte[])}. On a RESPONDER this value is used to gate the acceptance of a connection request
+ * from only that peer. A RESPONDER may specify a null - indicating that
+ * it will accept connection requests from any device.
+ * @param token Deprecated and ignored.
+ * @return A string to be used to construct
+ * {@link android.net.NetworkRequest.Builder#setNetworkSpecifier(String)} to pass to
+ * {@link android.net.ConnectivityManager#requestNetwork(android.net.NetworkRequest,
+ * android.net.ConnectivityManager.NetworkCallback)}
+ * [or other varieties of that API].
+ */
+ public String createNetworkSpecifier(@Nullable PeerHandle peerHandle, @Nullable byte[] token) {
+ return createNetworkSpecifierOpen(peerHandle);
+ }
}
diff --git a/wifi/java/android/net/wifi/aware/DiscoverySessionCallback.java b/wifi/java/android/net/wifi/aware/DiscoverySessionCallback.java
index 33da182..9645b1d 100644
--- a/wifi/java/android/net/wifi/aware/DiscoverySessionCallback.java
+++ b/wifi/java/android/net/wifi/aware/DiscoverySessionCallback.java
@@ -124,10 +124,9 @@
}
/**
- * Called when message transmission fails - when no ACK is received from the peer.
- * Retries when ACKs are not received are done by hardware, MAC, and in the Aware stack (using
- * the {@link DiscoverySession#sendMessage(PeerHandle, int,
- * byte[], int)} method) - this event is received after all retries are exhausted.
+ * Called when message transmission initiated with
+ * {@link DiscoverySession#sendMessage(PeerHandle, int, byte[])} fails. E.g. when no ACK is
+ * received from the peer.
* <p>
* Note that either this callback or
* {@link DiscoverySessionCallback#onMessageSendSucceeded(int)} will be received
@@ -141,9 +140,7 @@
/**
* Called when a message is received from a discovery session peer - in response to the
- * peer's {@link DiscoverySession#sendMessage(PeerHandle, int,
- * byte[])} or {@link DiscoverySession#sendMessage(PeerHandle,
- * int, byte[], int)}.
+ * peer's {@link DiscoverySession#sendMessage(PeerHandle, int, byte[])}.
*
* @param peerHandle An opaque handle to the peer matching our discovery operation.
* @param message A byte array containing the message.
diff --git a/wifi/java/android/net/wifi/aware/WifiAwareManager.java b/wifi/java/android/net/wifi/aware/WifiAwareManager.java
index 0eb6a3d..3d784ba 100644
--- a/wifi/java/android/net/wifi/aware/WifiAwareManager.java
+++ b/wifi/java/android/net/wifi/aware/WifiAwareManager.java
@@ -130,55 +130,34 @@
*/
/**
- * TYPE_1A: role, client_id, session_id, peer_id, token
+ * TYPE: in band, specific peer: role, client_id, session_id, peer_id, pmk optional
* @hide
*/
- public static final int NETWORK_SPECIFIER_TYPE_1A = 0;
+ public static final int NETWORK_SPECIFIER_TYPE_IB = 0;
/**
- * TYPE_1B: role, client_id, session_id, peer_id [only permitted for RESPONDER]
+ * TYPE: in band, any peer: role, client_id, session_id, pmk optional
+ * [only permitted for RESPONDER]
* @hide
*/
- public static final int NETWORK_SPECIFIER_TYPE_1B = 1;
+ public static final int NETWORK_SPECIFIER_TYPE_IB_ANY_PEER = 1;
/**
- * TYPE_1C: role, client_id, session_id, token [only permitted for RESPONDER]
+ * TYPE: out-of-band: role, client_id, peer_mac, pmk optional
* @hide
*/
- public static final int NETWORK_SPECIFIER_TYPE_1C = 2;
+ public static final int NETWORK_SPECIFIER_TYPE_OOB = 2;
/**
- * TYPE_1C: role, client_id, session_id [only permitted for RESPONDER]
+ * TYPE: out-of-band, any peer: role, client_id, pmk optional
+ * [only permitted for RESPONDER]
* @hide
*/
- public static final int NETWORK_SPECIFIER_TYPE_1D = 3;
+ public static final int NETWORK_SPECIFIER_TYPE_OOB_ANY_PEER = 3;
- /**
- * TYPE_2A: role, client_id, peer_mac, token
- * @hide
- */
- public static final int NETWORK_SPECIFIER_TYPE_2A = 4;
-
- /**
- * TYPE_2B: role, client_id, peer_mac [only permitted for RESPONDER]
- * @hide
- */
- public static final int NETWORK_SPECIFIER_TYPE_2B = 5;
-
- /**
- * TYPE_2C: role, client_id, token [only permitted for RESPONDER]
- * @hide
- */
- public static final int NETWORK_SPECIFIER_TYPE_2C = 6;
-
- /**
- * TYPE_2D: role, client_id [only permitted for RESPONDER]
- * @hide
- */
- public static final int NETWORK_SPECIFIER_TYPE_2D = 7;
/** @hide */
- public static final int NETWORK_SPECIFIER_TYPE_MAX_VALID = NETWORK_SPECIFIER_TYPE_2D;
+ public static final int NETWORK_SPECIFIER_TYPE_MAX_VALID = NETWORK_SPECIFIER_TYPE_OOB_ANY_PEER;
/** @hide */
public static final String NETWORK_SPECIFIER_KEY_TYPE = "type";
@@ -199,7 +178,7 @@
public static final String NETWORK_SPECIFIER_KEY_PEER_MAC = "peer_mac";
/** @hide */
- public static final String NETWORK_SPECIFIER_KEY_TOKEN = "token";
+ public static final String NETWORK_SPECIFIER_KEY_PMK = "pmk";
/**
* Broadcast intent action to indicate that the state of Wi-Fi Aware availability has changed.
@@ -494,23 +473,15 @@
/** @hide */
public String createNetworkSpecifier(int clientId, int role, int sessionId,
- PeerHandle peerHandle, byte[] token) {
+ PeerHandle peerHandle, @Nullable byte[] pmk) {
if (VDBG) {
Log.v(TAG, "createNetworkSpecifier: role=" + role + ", sessionId=" + sessionId
+ ", peerHandle=" + ((peerHandle == null) ? peerHandle : peerHandle.peerId)
- + ", token=" + token);
+ + ", pmk=" + ((pmk == null) ? "null" : "non-null"));
}
- int type;
- if (token != null && peerHandle != null) {
- type = NETWORK_SPECIFIER_TYPE_1A;
- } else if (token == null && peerHandle != null) {
- type = NETWORK_SPECIFIER_TYPE_1B;
- } else if (token != null && peerHandle == null) {
- type = NETWORK_SPECIFIER_TYPE_1C;
- } else {
- type = NETWORK_SPECIFIER_TYPE_1D;
- }
+ int type = (peerHandle == null) ? NETWORK_SPECIFIER_TYPE_IB_ANY_PEER
+ : NETWORK_SPECIFIER_TYPE_IB;
if (role != WIFI_AWARE_DATA_PATH_ROLE_INITIATOR
&& role != WIFI_AWARE_DATA_PATH_ROLE_RESPONDER) {
@@ -519,10 +490,6 @@
+ "specifier");
}
if (role == WIFI_AWARE_DATA_PATH_ROLE_INITIATOR) {
- if (token == null) {
- throw new IllegalArgumentException(
- "createNetworkSpecifier: Invalid null token - not permitted on INITIATOR");
- }
if (peerHandle == null) {
throw new IllegalArgumentException(
"createNetworkSpecifier: Invalid peer handle (value of null) - not "
@@ -540,10 +507,11 @@
if (peerHandle != null) {
json.put(NETWORK_SPECIFIER_KEY_PEER_ID, peerHandle.peerId);
}
- if (token != null) {
- json.put(NETWORK_SPECIFIER_KEY_TOKEN,
- Base64.encodeToString(token, 0, token.length, Base64.DEFAULT));
+ if (pmk == null) {
+ pmk = new byte[0];
}
+ json.put(NETWORK_SPECIFIER_KEY_PMK,
+ Base64.encodeToString(pmk, 0, pmk.length, Base64.DEFAULT));
} catch (JSONException e) {
return "";
}
@@ -553,21 +521,14 @@
/** @hide */
public String createNetworkSpecifier(int clientId, @DataPathRole int role,
- @Nullable byte[] peer, @Nullable byte[] token) {
+ @Nullable byte[] peer, @Nullable byte[] pmk) {
if (VDBG) {
- Log.v(TAG, "createNetworkSpecifier: role=" + role + ", token=" + token);
+ Log.v(TAG, "createNetworkSpecifier: role=" + role
+ + ", pmk=" + ((pmk == null) ? "null" : "non-null"));
}
- int type;
- if (token != null && peer != null) {
- type = NETWORK_SPECIFIER_TYPE_2A;
- } else if (token == null && peer != null) {
- type = NETWORK_SPECIFIER_TYPE_2B;
- } else if (token != null && peer == null) {
- type = NETWORK_SPECIFIER_TYPE_2C;
- } else { // both are null
- type = NETWORK_SPECIFIER_TYPE_2D;
- }
+ int type = (peer == null) ?
+ NETWORK_SPECIFIER_TYPE_OOB_ANY_PEER : NETWORK_SPECIFIER_TYPE_OOB;
if (role != WIFI_AWARE_DATA_PATH_ROLE_INITIATOR
&& role != WIFI_AWARE_DATA_PATH_ROLE_RESPONDER) {
@@ -576,19 +537,13 @@
+ "specifier");
}
if (role == WIFI_AWARE_DATA_PATH_ROLE_INITIATOR) {
- if (peer == null || peer.length != 6) {
- throw new IllegalArgumentException(
- "createNetworkSpecifier: Invalid peer MAC address");
+ if (peer == null) {
+ throw new IllegalArgumentException("createNetworkSpecifier: Invalid peer MAC "
+ + "address - null not permitted on INITIATOR");
}
- if (token == null) {
- throw new IllegalArgumentException(
- "createNetworkSpecifier: Invalid null token - not permitted on INITIATOR");
- }
- } else {
- if (peer != null && peer.length != 6) {
- throw new IllegalArgumentException(
- "createNetworkSpecifier: Invalid peer MAC address");
- }
+ }
+ if (peer != null && peer.length != 6) {
+ throw new IllegalArgumentException("createNetworkSpecifier: Invalid peer MAC address");
}
JSONObject json;
@@ -600,10 +555,11 @@
if (peer != null) {
json.put(NETWORK_SPECIFIER_KEY_PEER_MAC, new String(HexEncoding.encode(peer)));
}
- if (token != null) {
- json.put(NETWORK_SPECIFIER_KEY_TOKEN,
- Base64.encodeToString(token, 0, token.length, Base64.DEFAULT));
+ if (pmk == null) {
+ pmk = new byte[0];
}
+ json.put(NETWORK_SPECIFIER_KEY_PMK,
+ Base64.encodeToString(pmk, 0, pmk.length, Base64.DEFAULT));
} catch (JSONException e) {
return "";
}
diff --git a/wifi/java/android/net/wifi/aware/WifiAwareSession.java b/wifi/java/android/net/wifi/aware/WifiAwareSession.java
index 8696920..856066e 100644
--- a/wifi/java/android/net/wifi/aware/WifiAwareSession.java
+++ b/wifi/java/android/net/wifi/aware/WifiAwareSession.java
@@ -183,47 +183,114 @@
}
/**
- * Create a {@link android.net.NetworkRequest.Builder#setNetworkSpecifier(String)} for a
- * WiFi Aware connection to the specified peer. The
+ * Create a {@link android.net.NetworkRequest.Builder#setNetworkSpecifier(String)} for an
+ * unencrypted WiFi Aware connection (link) to the specified peer. The
* {@link android.net.NetworkRequest.Builder#addTransportType(int)} should be set to
* {@link android.net.NetworkCapabilities#TRANSPORT_WIFI_AWARE}.
* <p>
* This API is targeted for applications which can obtain the peer MAC address using OOB
* (out-of-band) discovery. Aware discovery does not provide the MAC address of the peer -
* when using Aware discovery use the alternative network specifier method -
- * {@link DiscoverySession#createNetworkSpecifier(PeerHandle,
- * byte[])}.
+ * {@link DiscoverySession#createNetworkSpecifierOpen(PeerHandle)}.
*
* @param role The role of this device:
* {@link WifiAwareManager#WIFI_AWARE_DATA_PATH_ROLE_INITIATOR} or
* {@link WifiAwareManager#WIFI_AWARE_DATA_PATH_ROLE_RESPONDER}
* @param peer The MAC address of the peer's Aware discovery interface. On a RESPONDER this
* value is used to gate the acceptance of a connection request from only that
- * peer. A RESPONDER may specified a null - indicating that it will accept
+ * peer. A RESPONDER may specify a null - indicating that it will accept
* connection requests from any device.
- * @param token An arbitrary token (message) to be used to match connection initiation request
- * to a responder setup. A RESPONDER is set up with a {@code token} which must
- * be matched by the token provided by the INITIATOR. A null token is permitted
- * on the RESPONDER and matches any peer token. An empty ({@code ""}) token is
- * not the same as a null token and requires the peer token to be empty as well.
*
* @return A string to be used to construct
* {@link android.net.NetworkRequest.Builder#setNetworkSpecifier(String)} to pass to
* {@link android.net.ConnectivityManager#requestNetwork(android.net.NetworkRequest,
* android.net.ConnectivityManager.NetworkCallback)}
* [or other varieties of that API].
+ *
+ * @hide
+ */
+ public String createNetworkSpecifierOpen(@WifiAwareManager.DataPathRole int role,
+ @Nullable byte[] peer) {
+ WifiAwareManager mgr = mMgr.get();
+ if (mgr == null) {
+ Log.e(TAG, "createNetworkSpecifierOpen: called post GC on WifiAwareManager");
+ return "";
+ }
+ if (mTerminated) {
+ Log.e(TAG, "createNetworkSpecifierOpen: called after termination");
+ return "";
+ }
+ return mgr.createNetworkSpecifier(mClientId, role, peer, null);
+ }
+
+ /**
+ * Create a {@link android.net.NetworkRequest.Builder#setNetworkSpecifier(String)} for an
+ * encrypted WiFi Aware connection (link) to the specified peer. The
+ * {@link android.net.NetworkRequest.Builder#addTransportType(int)} should be set to
+ * {@link android.net.NetworkCapabilities#TRANSPORT_WIFI_AWARE}.
+ * <p>
+ * This API is targeted for applications which can obtain the peer MAC address using OOB
+ * (out-of-band) discovery. Aware discovery does not provide the MAC address of the peer -
+ * when using Aware discovery use the alternative network specifier method -
+ * {@link DiscoverySession#createNetworkSpecifierPmk(PeerHandle, byte[])}}.
+ *
+ * @param role The role of this device:
+ * {@link WifiAwareManager#WIFI_AWARE_DATA_PATH_ROLE_INITIATOR} or
+ * {@link WifiAwareManager#WIFI_AWARE_DATA_PATH_ROLE_RESPONDER}
+ * @param peer The MAC address of the peer's Aware discovery interface. On a RESPONDER this
+ * value is used to gate the acceptance of a connection request from only that
+ * peer. A RESPONDER may specify a null - indicating that it will accept
+ * connection requests from any device.
+ * @param pmk A PMK (pairwise master key, see IEEE 802.11i) specifying the key to use for
+ * encrypting the data-path. Use the {@link #createNetworkSpecifierOpen(int, byte[])}
+ * to specify an open (unencrypted) link.
+ *
+ * @return A string to be used to construct
+ * {@link android.net.NetworkRequest.Builder#setNetworkSpecifier(String)} to pass to
+ * {@link android.net.ConnectivityManager#requestNetwork(android.net.NetworkRequest,
+ * android.net.ConnectivityManager.NetworkCallback)}
+ * [or other varieties of that API].
+ *
+ * @hide
+ */
+ public String createNetworkSpecifierPmk(@WifiAwareManager.DataPathRole int role,
+ @Nullable byte[] peer, @NonNull byte[] pmk) {
+ WifiAwareManager mgr = mMgr.get();
+ if (mgr == null) {
+ Log.e(TAG, "createNetworkSpecifierPmk: called post GC on WifiAwareManager");
+ return "";
+ }
+ if (mTerminated) {
+ Log.e(TAG, "createNetworkSpecifierPmk: called after termination");
+ return "";
+ }
+ if (pmk == null || pmk.length == 0) {
+ throw new IllegalArgumentException("PMK must not be null or empty");
+ }
+ return mgr.createNetworkSpecifier(mClientId, role, peer, pmk);
+ }
+
+ /**
+ * Place-holder for {@code #createNetworkSpecifierOpen(int, byte[])}. Present to enable
+ * development of replacements CL without causing an API change. Will be removed when new
+ * APIs are exposed.
+ *
+ * @param role The role of this device:
+ * {@link WifiAwareManager#WIFI_AWARE_DATA_PATH_ROLE_INITIATOR} or
+ * {@link WifiAwareManager#WIFI_AWARE_DATA_PATH_ROLE_RESPONDER}
+ * @param peer The MAC address of the peer's Aware discovery interface. On a RESPONDER this
+ * value is used to gate the acceptance of a connection request from only that
+ * peer. A RESPONDER may specify a null - indicating that it will accept
+ * connection requests from any device.
+ * @param token Deprecated and ignored.
+ * @return A string to be used to construct
+ * {@link android.net.NetworkRequest.Builder#setNetworkSpecifier(String)} to pass to
+ * {@link android.net.ConnectivityManager#requestNetwork(android.net.NetworkRequest,
+ * android.net.ConnectivityManager.NetworkCallback)}
+ * [or other varieties of that API].
*/
public String createNetworkSpecifier(@WifiAwareManager.DataPathRole int role,
@Nullable byte[] peer, @Nullable byte[] token) {
- WifiAwareManager mgr = mMgr.get();
- if (mgr == null) {
- Log.e(TAG, "createNetworkSpecifier: called post GC on WifiAwareManager");
- return "";
- }
- if (mTerminated) {
- Log.e(TAG, "createNetworkSpecifier: called after termination");
- return "";
- }
- return mgr.createNetworkSpecifier(mClientId, role, peer, token);
+ return createNetworkSpecifierOpen(role, peer);
}
}
diff --git a/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java b/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java
index 5f949747..632cfaf 100644
--- a/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java
+++ b/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java
@@ -20,6 +20,7 @@
import static org.junit.Assert.assertEquals;
import android.os.Parcel;
+import android.net.wifi.WifiConfiguration.NetworkSelectionStatus;
import org.junit.Before;
import org.junit.Test;
@@ -66,4 +67,35 @@
assertArrayEquals(bytes, rebytes);
}
+
+ @Test
+ public void testNetworkSelectionStatusCopy() {
+ NetworkSelectionStatus networkSelectionStatus = new NetworkSelectionStatus();
+ networkSelectionStatus.setNotRecommended(true);
+
+ NetworkSelectionStatus copy = new NetworkSelectionStatus();
+ copy.copy(networkSelectionStatus);
+
+ assertEquals(networkSelectionStatus.isNotRecommended(), copy.isNotRecommended());
+ }
+
+ @Test
+ public void testNetworkSelectionStatusParcel() {
+ NetworkSelectionStatus networkSelectionStatus = new NetworkSelectionStatus();
+ networkSelectionStatus.setNotRecommended(true);
+
+ Parcel parcelW = Parcel.obtain();
+ networkSelectionStatus.writeToParcel(parcelW);
+ byte[] bytes = parcelW.marshall();
+ parcelW.recycle();
+
+ Parcel parcelR = Parcel.obtain();
+ parcelR.unmarshall(bytes, 0, bytes.length);
+ parcelR.setDataPosition(0);
+
+ NetworkSelectionStatus copy = new NetworkSelectionStatus();
+ copy.readFromParcel(parcelR);
+
+ assertEquals(networkSelectionStatus.isNotRecommended(), copy.isNotRecommended());
+ }
}
diff --git a/wifi/tests/src/android/net/wifi/aware/WifiAwareManagerTest.java b/wifi/tests/src/android/net/wifi/aware/WifiAwareManagerTest.java
index 7f68f6f..992958b 100644
--- a/wifi/tests/src/android/net/wifi/aware/WifiAwareManagerTest.java
+++ b/wifi/tests/src/android/net/wifi/aware/WifiAwareManagerTest.java
@@ -973,11 +973,11 @@
final int sessionId = 123;
final PeerHandle peerHandle = new PeerHandle(123412);
final int role = WifiAwareManager.WIFI_AWARE_DATA_PATH_ROLE_RESPONDER;
- final String token = "Some arbitrary token string - can really be anything";
+ final byte[] pmk = "Some arbitrary byte array".getBytes();
final ConfigRequest configRequest = new ConfigRequest.Builder().build();
final PublishConfig publishConfig = new PublishConfig.Builder().build();
- String tokenB64 = Base64.encodeToString(token.getBytes(), Base64.DEFAULT);
+ String pmkB64 = Base64.encodeToString(pmk, Base64.DEFAULT);
ArgumentCaptor<WifiAwareSession> sessionCaptor = ArgumentCaptor.forClass(
WifiAwareSession.class);
@@ -1008,9 +1008,8 @@
mMockLooper.dispatchAll();
inOrder.verify(mockSessionCallback).onPublishStarted(publishSession.capture());
- // (3) request a network specifier from the session
- String networkSpecifier = publishSession.getValue().createNetworkSpecifier(peerHandle,
- token.getBytes());
+ // (3) request an open (unencrypted) network specifier from the session
+ String networkSpecifier = publishSession.getValue().createNetworkSpecifierOpen(peerHandle);
// validate format
JSONObject jsonObject = new JSONObject(networkSpecifier);
@@ -1022,8 +1021,22 @@
equalTo(jsonObject.getInt(WifiAwareManager.NETWORK_SPECIFIER_KEY_SESSION_ID)));
collector.checkThat("peer_id", peerHandle.peerId,
equalTo(jsonObject.getInt(WifiAwareManager.NETWORK_SPECIFIER_KEY_PEER_ID)));
- collector.checkThat("token", tokenB64,
- equalTo(jsonObject.getString(WifiAwareManager.NETWORK_SPECIFIER_KEY_TOKEN)));
+
+ // (4) request an encrypted (PMK) network specifier from the session
+ networkSpecifier = publishSession.getValue().createNetworkSpecifierPmk(peerHandle, pmk);
+
+ // validate format
+ jsonObject = new JSONObject(networkSpecifier);
+ collector.checkThat("role", role,
+ equalTo(jsonObject.getInt(WifiAwareManager.NETWORK_SPECIFIER_KEY_ROLE)));
+ collector.checkThat("client_id", clientId,
+ equalTo(jsonObject.getInt(WifiAwareManager.NETWORK_SPECIFIER_KEY_CLIENT_ID)));
+ collector.checkThat("session_id", sessionId,
+ equalTo(jsonObject.getInt(WifiAwareManager.NETWORK_SPECIFIER_KEY_SESSION_ID)));
+ collector.checkThat("peer_id", peerHandle.peerId,
+ equalTo(jsonObject.getInt(WifiAwareManager.NETWORK_SPECIFIER_KEY_PEER_ID)));
+ collector.checkThat("pmk", pmkB64 ,
+ equalTo(jsonObject.getString(WifiAwareManager.NETWORK_SPECIFIER_KEY_PMK)));
verifyNoMoreInteractions(mockCallback, mockSessionCallback, mockAwareService,
mockPublishSession, mockRttListener);
@@ -1039,9 +1052,9 @@
final ConfigRequest configRequest = new ConfigRequest.Builder().build();
final byte[] someMac = HexEncoding.decode("000102030405".toCharArray(), false);
final int role = WifiAwareManager.WIFI_AWARE_DATA_PATH_ROLE_INITIATOR;
- final String token = "Some arbitrary token string - can really be anything";
+ final byte[] pmk = "Some arbitrary pmk data".getBytes();
- String tokenB64 = Base64.encodeToString(token.getBytes(), Base64.DEFAULT);
+ String pmkB64 = Base64.encodeToString(pmk, Base64.DEFAULT);
ArgumentCaptor<WifiAwareSession> sessionCaptor = ArgumentCaptor.forClass(
WifiAwareSession.class);
@@ -1060,10 +1073,10 @@
inOrder.verify(mockCallback).onAttached(sessionCaptor.capture());
WifiAwareSession session = sessionCaptor.getValue();
- /* (2) request a direct network specifier*/
- String networkSpecifier = session.createNetworkSpecifier(role, someMac, token.getBytes());
+ // (2) request an open (unencrypted) direct network specifier
+ String networkSpecifier = session.createNetworkSpecifierOpen(role, someMac);
- /* validate format*/
+ // validate format
JSONObject jsonObject = new JSONObject(networkSpecifier);
collector.checkThat("role", role,
equalTo(jsonObject.getInt(WifiAwareManager.NETWORK_SPECIFIER_KEY_ROLE)));
@@ -1072,8 +1085,21 @@
collector.checkThat("peer_mac", someMac, equalTo(HexEncoding.decode(
jsonObject.getString(WifiAwareManager.NETWORK_SPECIFIER_KEY_PEER_MAC).toCharArray(),
false)));
- collector.checkThat("token", tokenB64,
- equalTo(jsonObject.getString(WifiAwareManager.NETWORK_SPECIFIER_KEY_TOKEN)));
+
+ // (3) request an encrypted (PMK) direct network specifier
+ networkSpecifier = session.createNetworkSpecifierPmk(role, someMac, pmk);
+
+ // validate format
+ jsonObject = new JSONObject(networkSpecifier);
+ collector.checkThat("role", role,
+ equalTo(jsonObject.getInt(WifiAwareManager.NETWORK_SPECIFIER_KEY_ROLE)));
+ collector.checkThat("client_id", clientId,
+ equalTo(jsonObject.getInt(WifiAwareManager.NETWORK_SPECIFIER_KEY_CLIENT_ID)));
+ collector.checkThat("peer_mac", someMac, equalTo(HexEncoding.decode(
+ jsonObject.getString(WifiAwareManager.NETWORK_SPECIFIER_KEY_PEER_MAC).toCharArray(),
+ false)));
+ collector.checkThat("pmk", pmkB64,
+ equalTo(jsonObject.getString(WifiAwareManager.NETWORK_SPECIFIER_KEY_PMK)));
verifyNoMoreInteractions(mockCallback, mockSessionCallback, mockAwareService,
mockPublishSession, mockRttListener);