summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CleanSpec.mk3
-rw-r--r--api/current.txt130
-rw-r--r--cmds/media/src/com/android/commands/media/Media.java10
-rw-r--r--cmds/pm/src/com/android/commands/pm/Pm.java161
-rw-r--r--core/java/android/app/ActivityThread.java8
-rw-r--r--core/java/android/app/ApplicationPackageManager.java2
-rw-r--r--core/java/android/app/ContextImpl.java4
-rw-r--r--core/java/android/app/DatePickerDialog.java84
-rw-r--r--core/java/android/app/INotificationManager.aidl2
-rw-r--r--core/java/android/app/LoadedApk.java19
-rw-r--r--core/java/android/app/TimePickerDialog.java120
-rw-r--r--core/java/android/app/backup/BackupManager.java22
-rw-r--r--core/java/android/appwidget/AppWidgetProviderInfo.java15
-rw-r--r--core/java/android/content/pm/FeatureGroupInfo.java65
-rw-r--r--core/java/android/content/pm/FeatureInfo.java2
-rw-r--r--core/java/android/content/pm/IPackageInstaller.aidl15
-rw-r--r--core/java/android/content/pm/IPackageInstallerSession.aidl5
-rw-r--r--core/java/android/content/pm/InstallSessionInfo.java181
-rw-r--r--core/java/android/content/pm/InstallSessionParams.aidl19
-rw-r--r--core/java/android/content/pm/InstallSessionParams.java227
-rw-r--r--core/java/android/content/pm/PackageInfo.java14
-rw-r--r--core/java/android/content/pm/PackageInstaller.aidl (renamed from core/java/android/content/pm/InstallSessionInfo.aidl)3
-rw-r--r--core/java/android/content/pm/PackageInstaller.java568
-rw-r--r--core/java/android/content/pm/PackageInstallerParams.aidl19
-rw-r--r--core/java/android/content/pm/PackageManager.java128
-rw-r--r--core/java/android/content/pm/PackageParser.java79
-rw-r--r--core/java/android/content/pm/VerificationParams.java2
-rw-r--r--core/java/android/content/res/Resources.java8
-rw-r--r--core/java/android/hardware/camera2/legacy/LegacyCameraDevice.java2
-rw-r--r--core/java/android/hardware/camera2/legacy/LegacyMetadataMapper.java19
-rw-r--r--core/java/android/hardware/camera2/legacy/LegacyRequestMapper.java67
-rw-r--r--core/java/android/hardware/camera2/legacy/LegacyResultMapper.java24
-rw-r--r--core/java/android/hardware/camera2/legacy/ParameterUtils.java27
-rw-r--r--core/java/android/hardware/camera2/legacy/RequestThreadManager.java7
-rw-r--r--core/java/android/hardware/camera2/legacy/SurfaceTextureRenderer.java49
-rw-r--r--core/java/android/net/LinkProperties.java17
-rw-r--r--core/java/android/nfc/INfcAdapter.aidl2
-rw-r--r--core/java/android/nfc/NfcAdapter.java39
-rw-r--r--core/java/android/os/PowerManager.java5
-rw-r--r--core/java/android/os/Trace.java3
-rw-r--r--core/java/android/os/UserManager.java22
-rw-r--r--core/java/android/provider/Settings.java38
-rw-r--r--core/java/android/service/notification/ZenModeConfig.java143
-rw-r--r--core/java/android/service/trust/TrustAgentService.java13
-rw-r--r--core/java/android/widget/DatePicker.java61
-rw-r--r--core/java/android/widget/DatePickerCalendarDelegate.java55
-rw-r--r--core/java/android/widget/ListView.java2
-rw-r--r--core/java/android/widget/RadialTimePickerView.java7
-rw-r--r--core/java/android/widget/SimpleMonthView.java38
-rw-r--r--core/java/android/widget/TimePicker.java60
-rw-r--r--core/java/android/widget/TimePickerClockDelegate.java75
-rw-r--r--core/java/android/widget/TimePickerSpinnerDelegate.java89
-rw-r--r--core/java/android/widget/YearPickerView.java2
-rw-r--r--core/java/com/android/internal/os/InstallerConnection.java207
-rw-r--r--core/java/com/android/internal/os/RuntimeInit.java15
-rw-r--r--core/java/com/android/internal/os/ZygoteConnection.java2
-rw-r--r--core/java/com/android/internal/os/ZygoteInit.java55
-rw-r--r--core/java/com/android/server/BootReceiver.java (renamed from services/core/java/com/android/server/BootReceiver.java)0
-rw-r--r--core/jni/Android.mk1
-rw-r--r--core/jni/AndroidRuntime.cpp8
-rw-r--r--core/jni/android_app_NativeActivity.cpp26
-rw-r--r--core/jni/android_hardware_camera2_legacy_LegacyCameraDevice.cpp17
-rw-r--r--core/res/AndroidManifest.xml8
-rw-r--r--core/res/res/animator/leanback_setup_fragment_close_enter.xml27
-rw-r--r--core/res/res/animator/leanback_setup_fragment_close_exit.xml34
-rw-r--r--core/res/res/animator/leanback_setup_fragment_open_enter.xml34
-rw-r--r--core/res/res/animator/leanback_setup_fragment_open_exit.xml27
-rw-r--r--core/res/res/drawable-hdpi/spinner_textfield_activated_mtrl_alpha.9.pngbin0 -> 590 bytes
-rw-r--r--core/res/res/drawable-hdpi/spinner_textfield_default_mtrl_alpha.9.pngbin0 -> 588 bytes
-rw-r--r--core/res/res/drawable-mdpi/spinner_textfield_activated_mtrl_alpha.9.pngbin0 -> 449 bytes
-rw-r--r--core/res/res/drawable-mdpi/spinner_textfield_default_mtrl_alpha.9.pngbin0 -> 445 bytes
-rw-r--r--core/res/res/drawable-xhdpi/spinner_textfield_activated_mtrl_alpha.9.pngbin0 -> 703 bytes
-rw-r--r--core/res/res/drawable-xhdpi/spinner_textfield_default_mtrl_alpha.9.pngbin0 -> 692 bytes
-rw-r--r--core/res/res/drawable-xxhdpi/spinner_textfield_activated_mtrl_alpha.9.pngbin0 -> 984 bytes
-rw-r--r--core/res/res/drawable-xxhdpi/spinner_textfield_default_mtrl_alpha.9.pngbin0 -> 973 bytes
-rw-r--r--core/res/res/drawable-xxxhdpi/spinner_textfield_activated_mtrl_alpha.9.pngbin0 -> 1764 bytes
-rw-r--r--core/res/res/drawable-xxxhdpi/spinner_textfield_default_mtrl_alpha.9.pngbin0 -> 1782 bytes
-rw-r--r--core/res/res/drawable/spinner_textfield_background_material.xml31
-rw-r--r--core/res/res/layout-land/date_picker_holo.xml25
-rw-r--r--core/res/res/layout-land/time_picker_holo.xml43
-rw-r--r--core/res/res/layout-sw600dp/date_picker_holo.xml18
-rw-r--r--core/res/res/layout/alert_dialog_material.xml9
-rw-r--r--core/res/res/layout/date_picker_done_button.xml33
-rw-r--r--core/res/res/layout/date_picker_header_view.xml23
-rw-r--r--core/res/res/layout/date_picker_holo.xml15
-rw-r--r--core/res/res/layout/date_picker_selected_date.xml71
-rw-r--r--core/res/res/layout/time_header_label.xml31
-rw-r--r--core/res/res/layout/time_picker_dialog.xml3
-rw-r--r--core/res/res/layout/time_picker_holo.xml17
-rw-r--r--core/res/res/layout/time_picker_legacy_leanback.xml10
-rw-r--r--core/res/res/values/attrs_manifest.xml4
-rw-r--r--core/res/res/values/dimens.xml12
-rw-r--r--core/res/res/values/dimens_leanback.xml71
-rw-r--r--core/res/res/values/dimens_material.xml2
-rw-r--r--core/res/res/values/donottranslate_material.xml2
-rw-r--r--core/res/res/values/public.xml34
-rw-r--r--core/res/res/values/strings.xml8
-rw-r--r--core/res/res/values/styles_leanback.xml6
-rw-r--r--core/res/res/values/styles_material.xml44
-rw-r--r--core/res/res/values/symbols.xml4
-rw-r--r--core/res/res/values/themes_leanback.xml1
-rw-r--r--core/res/res/values/themes_material.xml21
-rw-r--r--graphics/java/android/graphics/drawable/AnimatedStateListDrawable.java6
-rw-r--r--graphics/java/android/graphics/drawable/RippleDrawable.java10
-rw-r--r--graphics/java/android/graphics/drawable/VectorDrawable.java2
-rw-r--r--graphics/java/android/graphics/drawable/shapes/Shape.java8
-rw-r--r--libs/androidfw/ResourceTypes.cpp31
-rw-r--r--libs/androidfw/tests/ResTable_test.cpp11
-rw-r--r--libs/hwui/font/Font.cpp21
-rw-r--r--media/java/android/media/AudioTrack.java20
-rw-r--r--media/java/android/media/MediaCodecInfo.java129
-rw-r--r--media/java/android/media/Utils.java13
-rw-r--r--media/java/android/media/session/MediaSessionLegacyHelper.java7
-rw-r--r--media/java/android/media/tv/TvContract.java24
-rw-r--r--media/java/android/media/tv/TvInputInfo.java4
-rw-r--r--packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java143
-rw-r--r--packages/SystemUI/res/values/strings.xml6
-rw-r--r--packages/SystemUI/src/com/android/systemui/settings/BrightnessController.java34
-rw-r--r--packages/SystemUI/src/com/android/systemui/settings/BrightnessDialog.java16
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java1
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java34
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java61
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java1
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeController.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeControllerImpl.java14
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java1
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java57
-rw-r--r--packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java150
-rw-r--r--services/appwidget/Android.mk2
-rw-r--r--services/backup/java/com/android/server/backup/BackupManagerService.java12
-rw-r--r--services/core/java/com/android/server/ConnectivityService.java8
-rw-r--r--services/core/java/com/android/server/NetworkScoreService.java12
-rw-r--r--services/core/java/com/android/server/SystemService.java (renamed from core/java/com/android/server/SystemService.java)0
-rw-r--r--services/core/java/com/android/server/SystemServiceManager.java (renamed from core/java/com/android/server/SystemServiceManager.java)0
-rwxr-xr-xservices/core/java/com/android/server/am/ActivityManagerService.java2
-rw-r--r--services/core/java/com/android/server/display/DisplayPowerController.java14
-rw-r--r--services/core/java/com/android/server/display/DisplayPowerState.java26
-rw-r--r--services/core/java/com/android/server/display/LocalDisplayAdapter.java12
-rw-r--r--services/core/java/com/android/server/dreams/DreamController.java169
-rw-r--r--services/core/java/com/android/server/lights/LightsService.java8
-rw-r--r--services/core/java/com/android/server/notification/ConditionProviders.java90
-rw-r--r--services/core/java/com/android/server/notification/CountdownConditionProvider.java5
-rw-r--r--services/core/java/com/android/server/notification/DowntimeConditionProvider.java289
-rw-r--r--services/core/java/com/android/server/notification/ManagedServices.java3
-rw-r--r--services/core/java/com/android/server/notification/NotificationManagerService.java4
-rw-r--r--services/core/java/com/android/server/notification/ZenLog.java35
-rw-r--r--services/core/java/com/android/server/notification/ZenModeHelper.java125
-rw-r--r--services/core/java/com/android/server/pm/Installer.java290
-rw-r--r--services/core/java/com/android/server/pm/PackageInstallerService.java145
-rw-r--r--services/core/java/com/android/server/pm/PackageInstallerSession.java37
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerService.java23
-rw-r--r--services/core/java/com/android/server/power/Notifier.java1
-rw-r--r--services/core/java/com/android/server/power/PowerManagerService.java344
-rw-r--r--services/core/java/com/android/server/tv/TvInputManagerService.java2
-rw-r--r--services/core/jni/onload.cpp4
-rw-r--r--services/devicepolicy/Android.mk2
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java70
-rw-r--r--services/print/Android.mk2
-rw-r--r--services/restrictions/Android.mk2
-rw-r--r--services/usage/Android.mk2
-rw-r--r--telecomm/java/android/telecomm/Call.java57
-rw-r--r--telecomm/java/android/telecomm/Connection.java23
-rw-r--r--telecomm/java/android/telecomm/ConnectionService.java12
-rw-r--r--telecomm/java/android/telecomm/ConnectionServiceAdapter.java9
-rw-r--r--telecomm/java/android/telecomm/Phone.java27
-rw-r--r--telecomm/java/android/telecomm/RemoteConnection.java16
-rw-r--r--telephony/java/com/android/internal/telephony/PhoneConstants.java3
-rw-r--r--tests/OneMedia/AndroidManifest.xml2
-rw-r--r--tests/OneMedia/res/drawable/ic_fast_forward.xml25
-rw-r--r--tests/OneMedia/res/drawable/ic_fast_rewind.xml24
-rw-r--r--tests/OneMedia/res/drawable/ic_pause.xml25
-rw-r--r--tests/OneMedia/res/drawable/ic_play_arrow.xml25
-rw-r--r--tests/OneMedia/res/drawable/ic_skip_next.xml25
-rw-r--r--tests/OneMedia/res/drawable/ic_skip_previous.xml28
-rw-r--r--tests/OneMedia/res/drawable/ic_stop.xml25
-rw-r--r--tests/OneMedia/res/layout/activity_one_player.xml13
-rw-r--r--tests/OneMedia/res/values/strings.xml2
-rw-r--r--tests/OneMedia/src/com/android/onemedia/IPlayerService.aidl2
-rw-r--r--tests/OneMedia/src/com/android/onemedia/NotificationHelper.java234
-rw-r--r--tests/OneMedia/src/com/android/onemedia/OnePlayerActivity.java74
-rw-r--r--tests/OneMedia/src/com/android/onemedia/PlayerController.java28
-rw-r--r--tests/OneMedia/src/com/android/onemedia/PlayerService.java14
-rw-r--r--tests/OneMedia/src/com/android/onemedia/PlayerSession.java27
-rw-r--r--tests/OneMedia/src/com/android/onemedia/playback/RequestUtils.java6
-rw-r--r--tests/UsesFeature2Test/AndroidManifest.xml9
-rw-r--r--tools/aapt/Command.cpp83
-rw-r--r--tools/aapt/Resource.cpp35
189 files changed, 4510 insertions, 2679 deletions
diff --git a/CleanSpec.mk b/CleanSpec.mk
index ae2f3adb6143..c7cf940fd217 100644
--- a/CleanSpec.mk
+++ b/CleanSpec.mk
@@ -218,6 +218,9 @@ $(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/androi
$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework_intermediates)
$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/services.core_intermediates)
$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/services_intermediates)
+$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework_intermediates)
+$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/services.core_intermediates)
+$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/services_intermediates)
# ******************************************************************
# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST ABOVE THIS BANNER
diff --git a/api/current.txt b/api/current.txt
index 2a3c08600508..cb6c512767bf 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -2558,6 +2558,7 @@ package android {
field public static final int Widget_Material_Light_SeekBar = 16974534; // 0x10302c6
field public static final int Widget_Material_Light_SegmentedButton = 16974535; // 0x10302c7
field public static final int Widget_Material_Light_Spinner = 16974537; // 0x10302c9
+ field public static final int Widget_Material_Light_Spinner_Form = 16974567; // 0x10302e7
field public static final int Widget_Material_Light_StackView = 16974536; // 0x10302c8
field public static final int Widget_Material_Light_Tab = 16974538; // 0x10302ca
field public static final int Widget_Material_Light_TabWidget = 16974539; // 0x10302cb
@@ -2584,6 +2585,7 @@ package android {
field public static final int Widget_Material_SeekBar = 16974471; // 0x1030287
field public static final int Widget_Material_SegmentedButton = 16974472; // 0x1030288
field public static final int Widget_Material_Spinner = 16974474; // 0x103028a
+ field public static final int Widget_Material_Spinner_Form = 16974566; // 0x10302e6
field public static final int Widget_Material_StackView = 16974473; // 0x1030289
field public static final int Widget_Material_Tab = 16974475; // 0x103028b
field public static final int Widget_Material_TabWidget = 16974476; // 0x103028c
@@ -8526,6 +8528,15 @@ package android.content.pm {
field public int reqTouchScreen;
}
+ public final class FeatureGroupInfo implements android.os.Parcelable {
+ ctor public FeatureGroupInfo();
+ ctor public FeatureGroupInfo(android.content.pm.FeatureGroupInfo);
+ method public int describeContents();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator CREATOR;
+ field public android.content.pm.FeatureInfo[] features;
+ }
+
public class FeatureInfo implements android.os.Parcelable {
ctor public FeatureInfo();
ctor public FeatureInfo(android.content.pm.FeatureInfo);
@@ -8540,36 +8551,6 @@ package android.content.pm {
field public int reqGlEsVersion;
}
- public class InstallSessionInfo implements android.os.Parcelable {
- method public int describeContents();
- method public android.graphics.Bitmap getAppIcon();
- method public java.lang.CharSequence getAppLabel();
- method public java.lang.String getAppPackageName();
- method public android.content.Intent getDetailsIntent();
- method public java.lang.String getInstallerPackageName();
- method public float getProgress();
- method public int getSessionId();
- method public boolean isOpen();
- method public void writeToParcel(android.os.Parcel, int);
- field public static final android.os.Parcelable.Creator CREATOR;
- }
-
- public class InstallSessionParams implements android.os.Parcelable {
- ctor public InstallSessionParams(int);
- method public int describeContents();
- method public void setAppIcon(android.graphics.Bitmap);
- method public void setAppLabel(java.lang.CharSequence);
- method public void setAppPackageName(java.lang.String);
- method public void setInstallLocation(int);
- method public void setOriginatingUri(android.net.Uri);
- method public void setReferrerUri(android.net.Uri);
- method public void setSize(long);
- method public void writeToParcel(android.os.Parcel, int);
- field public static final android.os.Parcelable.Creator CREATOR;
- field public static final int MODE_FULL_INSTALL = 1; // 0x1
- field public static final int MODE_INHERIT_EXISTING = 2; // 0x2
- }
-
public class InstrumentationInfo extends android.content.pm.PackageItemInfo implements android.os.Parcelable {
ctor public InstrumentationInfo();
ctor public InstrumentationInfo(android.content.pm.InstrumentationInfo);
@@ -8647,6 +8628,7 @@ package android.content.pm {
field public android.content.pm.ActivityInfo[] activities;
field public android.content.pm.ApplicationInfo applicationInfo;
field public android.content.pm.ConfigurationInfo[] configPreferences;
+ field public android.content.pm.FeatureGroupInfo[] featureGroups;
field public long firstInstallTime;
field public int[] gids;
field public int installLocation;
@@ -8671,37 +8653,35 @@ package android.content.pm {
public class PackageInstaller {
method public void addSessionCallback(android.content.pm.PackageInstaller.SessionCallback);
method public void addSessionCallback(android.content.pm.PackageInstaller.SessionCallback, android.os.Handler);
- method public int createSession(android.content.pm.InstallSessionParams) throws java.io.IOException;
- method public java.util.List<android.content.pm.InstallSessionInfo> getAllSessions();
- method public java.util.List<android.content.pm.InstallSessionInfo> getMySessions();
- method public android.content.pm.InstallSessionInfo getSessionInfo(int);
+ method public int createSession(android.content.pm.PackageInstaller.SessionParams) throws java.io.IOException;
+ method public java.util.List<android.content.pm.PackageInstaller.SessionInfo> getAllSessions();
+ method public java.util.List<android.content.pm.PackageInstaller.SessionInfo> getMySessions();
+ method public android.content.pm.PackageInstaller.SessionInfo getSessionInfo(int);
method public android.content.pm.PackageInstaller.Session openSession(int);
method public void removeSessionCallback(android.content.pm.PackageInstaller.SessionCallback);
- method public void uninstall(java.lang.String, android.content.pm.PackageInstaller.UninstallCallback);
+ method public void uninstall(java.lang.String, android.content.IntentSender);
field public static final java.lang.String ACTION_SESSION_DETAILS = "android.content.pm.action.SESSION_DETAILS";
+ field public static final java.lang.String EXTRA_PACKAGE_NAMES = "android.content.pm.extra.PACKAGE_NAMES";
field public static final java.lang.String EXTRA_SESSION_ID = "android.content.pm.extra.SESSION_ID";
- }
-
- public static abstract class PackageInstaller.CommitCallback {
- ctor public PackageInstaller.CommitCallback();
- method public abstract void onFailure(int, java.lang.String, android.os.Bundle);
- method public abstract void onSuccess();
- method public abstract void onUserActionRequired(android.content.Intent);
- field public static final java.lang.String EXTRA_PACKAGE_NAME = "android.content.pm.extra.PACKAGE_NAME";
- field public static final int FAILURE_ABORTED = 5; // 0x5
- field public static final int FAILURE_CONFLICT = 2; // 0x2
- field public static final int FAILURE_INCOMPATIBLE = 4; // 0x4
- field public static final int FAILURE_INVALID = 1; // 0x1
- field public static final int FAILURE_STORAGE = 3; // 0x3
- field public static final int FAILURE_UNKNOWN = 0; // 0x0
+ 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";
+ field public static final int STATUS_FAILURE = 1; // 0x1
+ field public static final int STATUS_FAILURE_ABORTED = 2; // 0x2
+ field public static final int STATUS_FAILURE_BLOCKED = 1; // 0x1
+ field public static final int STATUS_FAILURE_CONFLICT = 4; // 0x4
+ field public static final int STATUS_FAILURE_INCOMPATIBLE = 6; // 0x6
+ field public static final int STATUS_FAILURE_INVALID = 3; // 0x3
+ field public static final int STATUS_FAILURE_STORAGE = 5; // 0x5
+ field public static final int STATUS_SUCCESS = 0; // 0x0
+ field public static final int STATUS_USER_ACTION_REQUIRED = -1; // 0xffffffff
}
public static class PackageInstaller.Session implements java.io.Closeable {
method public void abandon();
method public void close();
- method public void commit(android.content.pm.PackageInstaller.CommitCallback);
+ method public void commit(android.content.IntentSender);
method public void fsync(java.io.OutputStream) throws java.io.IOException;
- method public java.lang.String[] list();
+ method public java.lang.String[] getNames();
method public java.io.InputStream openRead(java.lang.String) throws java.io.IOException;
method public java.io.OutputStream openWrite(java.lang.String, long, long) throws java.io.IOException;
method public void setProgress(float);
@@ -8716,14 +8696,34 @@ package android.content.pm {
method public abstract void onProgressChanged(int, float);
}
- public static abstract class PackageInstaller.UninstallCallback {
- ctor public PackageInstaller.UninstallCallback();
- method public abstract void onFailure(int, java.lang.String, android.os.Bundle);
- method public abstract void onSuccess();
- method public abstract void onUserActionRequired(android.content.Intent);
- field public static final int FAILURE_ABORTED = 2; // 0x2
- field public static final int FAILURE_BLOCKED = 1; // 0x1
- field public static final int FAILURE_UNKNOWN = 0; // 0x0
+ public static class PackageInstaller.SessionInfo implements android.os.Parcelable {
+ method public int describeContents();
+ method public android.graphics.Bitmap getAppIcon();
+ method public java.lang.CharSequence getAppLabel();
+ method public java.lang.String getAppPackageName();
+ method public android.content.Intent getDetailsIntent();
+ method public java.lang.String getInstallerPackageName();
+ method public float getProgress();
+ method public int getSessionId();
+ method public boolean isOpen();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator CREATOR;
+ }
+
+ public static class PackageInstaller.SessionParams implements android.os.Parcelable {
+ ctor public PackageInstaller.SessionParams(int);
+ method public int describeContents();
+ method public void setAppIcon(android.graphics.Bitmap);
+ method public void setAppLabel(java.lang.CharSequence);
+ method public void setAppPackageName(java.lang.String);
+ method public void setInstallLocation(int);
+ method public void setOriginatingUri(android.net.Uri);
+ method public void setReferrerUri(android.net.Uri);
+ method public void setSize(long);
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator CREATOR;
+ field public static final int MODE_FULL_INSTALL = 1; // 0x1
+ field public static final int MODE_INHERIT_EXISTING = 2; // 0x2
}
public class PackageItemInfo {
@@ -11654,7 +11654,7 @@ package android.graphics.drawable {
public class AnimatedStateListDrawable extends android.graphics.drawable.StateListDrawable {
ctor public AnimatedStateListDrawable();
method public void addState(int[], android.graphics.drawable.Drawable, int);
- method public void addTransition(int, int, android.graphics.drawable.Drawable, boolean);
+ method public void addTransition(int, int, T, boolean);
}
public class AnimatedVectorDrawable extends android.graphics.drawable.Drawable implements android.graphics.drawable.Animatable {
@@ -16913,7 +16913,7 @@ package android.media.tv {
method public static final android.net.Uri buildChannelLogoUri(long);
method public static final android.net.Uri buildChannelLogoUri(android.net.Uri);
method public static final android.net.Uri buildChannelUri(long);
- method public static final android.net.Uri buildChannelUriForPassthroughTvInput(java.lang.String);
+ method public static final android.net.Uri buildChannelUriForPassthroughInput(java.lang.String);
method public static final android.net.Uri buildChannelsUriForInput(java.lang.String);
method public static final java.lang.String buildInputId(android.content.ComponentName);
method public static final android.net.Uri buildProgramUri(long);
@@ -17045,7 +17045,7 @@ package android.media.tv {
method public java.lang.String getParentId();
method public android.content.pm.ServiceInfo getServiceInfo();
method public int getType();
- method public boolean isPassthroughInputType();
+ method public boolean isPassthroughInput();
method public android.graphics.drawable.Drawable loadIcon(android.content.Context);
method public java.lang.CharSequence loadLabel(android.content.Context);
method public void writeToParcel(android.os.Parcel, int);
@@ -23026,9 +23026,9 @@ package android.os {
method public boolean isUserRunning(android.os.UserHandle);
method public boolean isUserRunningOrStopping(android.os.UserHandle);
method public boolean setRestrictionsChallenge(java.lang.String);
- method public void setUserRestriction(java.lang.String, boolean);
- method public void setUserRestrictions(android.os.Bundle);
- method public void setUserRestrictions(android.os.Bundle, android.os.UserHandle);
+ method public deprecated void setUserRestriction(java.lang.String, boolean);
+ method public deprecated void setUserRestrictions(android.os.Bundle);
+ method public deprecated void setUserRestrictions(android.os.Bundle, android.os.UserHandle);
field public static final java.lang.String DISALLOW_ADD_USER = "no_add_user";
field public static final java.lang.String DISALLOW_ADJUST_VOLUME = "no_adjust_volume";
field public static final java.lang.String DISALLOW_APPS_CONTROL = "no_control_apps";
diff --git a/cmds/media/src/com/android/commands/media/Media.java b/cmds/media/src/com/android/commands/media/Media.java
index b13b0093db36..b37f896c6c42 100644
--- a/cmds/media/src/com/android/commands/media/Media.java
+++ b/cmds/media/src/com/android/commands/media/Media.java
@@ -225,7 +225,7 @@ public class Media extends BaseCommand {
void printUsageMessage() {
try {
System.out.println("V2Monitoring session " + mController.getTag()
- + "... available commands:");
+ + "... available commands: play, pause, next, previous");
} catch (RemoteException e) {
System.out.println("Error trying to monitor session!");
}
@@ -257,6 +257,14 @@ public class Media extends BaseCommand {
addNewline = false;
} else if ("q".equals(line) || "quit".equals(line)) {
break;
+ } else if ("play".equals(line)) {
+ mController.play();
+ } else if ("pause".equals(line)) {
+ mController.pause();
+ } else if ("next".equals(line)) {
+ mController.next();
+ } else if ("previous".equals(line)) {
+ mController.previous();
} else {
System.out.println("Invalid command: " + line);
}
diff --git a/cmds/pm/src/com/android/commands/pm/Pm.java b/cmds/pm/src/com/android/commands/pm/Pm.java
index 15152e522036..46d8adeecd14 100644
--- a/cmds/pm/src/com/android/commands/pm/Pm.java
+++ b/cmds/pm/src/com/android/commands/pm/Pm.java
@@ -19,21 +19,22 @@ package com.android.commands.pm;
import android.app.ActivityManager;
import android.app.ActivityManagerNative;
import android.app.IActivityManager;
-import android.app.PackageDeleteObserver;
import android.app.PackageInstallObserver;
import android.content.ComponentName;
+import android.content.IIntentReceiver;
+import android.content.IIntentSender;
import android.content.Intent;
+import android.content.IntentSender;
import android.content.pm.ApplicationInfo;
import android.content.pm.FeatureInfo;
import android.content.pm.IPackageDataObserver;
import android.content.pm.IPackageInstaller;
import android.content.pm.IPackageManager;
-import android.content.pm.InstallSessionInfo;
-import android.content.pm.InstallSessionParams;
import android.content.pm.InstrumentationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageInstaller;
-import android.content.pm.PackageInstaller.CommitCallback;
+import android.content.pm.PackageInstaller.SessionInfo;
+import android.content.pm.PackageInstaller.SessionParams;
import android.content.pm.PackageItemInfo;
import android.content.pm.PackageManager;
import android.content.pm.ParceledListSlice;
@@ -74,6 +75,8 @@ import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.WeakHashMap;
+import java.util.concurrent.SynchronousQueue;
+import java.util.concurrent.TimeUnit;
public final class Pm {
private static final String TAG = "Pm";
@@ -776,36 +779,6 @@ public final class Pm {
}
}
- class LocalCommitCallback extends CommitCallback {
- boolean finished;
- boolean success;
- String msg;
-
- private void setResult(boolean success, String msg) {
- synchronized (this) {
- this.finished = true;
- this.success = success;
- this.msg = msg;
- notifyAll();
- }
- }
-
- @Override
- public void onUserActionRequired(Intent intent) {
- setResult(false, "Unexepected user action required!");
- }
-
- @Override
- public void onSuccess() {
- setResult(true, null);
- }
-
- @Override
- public void onFailure(int failureReason, String msg, Bundle extras) {
- setResult(false, msg);
- }
- }
-
/**
* Converts a failure code into a string by using reflection to find a matching constant
* in PackageManager.
@@ -1007,8 +980,7 @@ public final class Pm {
private void runInstallCreate() throws RemoteException {
String installerPackageName = null;
- final InstallSessionParams params = new InstallSessionParams(
- InstallSessionParams.MODE_FULL_INSTALL);
+ final SessionParams params = new SessionParams(SessionParams.MODE_FULL_INSTALL);
params.installFlags = PackageManager.INSTALL_ALL_USERS;
String opt;
@@ -1031,7 +1003,7 @@ public final class Pm {
} else if (opt.equals("-d")) {
params.installFlags |= PackageManager.INSTALL_ALLOW_DOWNGRADE;
} else if (opt.equals("-p")) {
- params.mode = InstallSessionParams.MODE_INHERIT_EXISTING;
+ params.mode = SessionParams.MODE_INHERIT_EXISTING;
} else if (opt.equals("-S")) {
params.setSize(Long.parseLong(nextOptionData()));
} else if (opt.equals("--abi")) {
@@ -1073,7 +1045,7 @@ public final class Pm {
}
}
- final InstallSessionInfo info = mInstaller.getSessionInfo(sessionId);
+ final SessionInfo info = mInstaller.getSessionInfo(sessionId);
PackageInstaller.Session session = null;
InputStream in = null;
@@ -1117,22 +1089,20 @@ public final class Pm {
try {
session = new PackageInstaller.Session(mInstaller.openSession(sessionId));
- final LocalCommitCallback callback = new LocalCommitCallback();
- session.commit(callback);
+ final LocalIntentReceiver receiver = new LocalIntentReceiver();
+ session.commit(receiver.getIntentSender());
- synchronized (callback) {
- while (!callback.finished) {
- try {
- callback.wait();
- } catch (InterruptedException e) {
- }
- }
- if (!callback.success) {
- throw new IllegalStateException("Failure [" + callback.msg + "]");
- }
+ final Intent result = receiver.getResult();
+ final int status = result.getIntExtra(PackageInstaller.EXTRA_STATUS,
+ PackageInstaller.STATUS_FAILURE);
+ if (status == PackageInstaller.STATUS_SUCCESS) {
+ System.out.println("Success");
+ } else {
+ Log.e(TAG, "Failure details: " + result.getExtras());
+ System.out.println("Failure ["
+ + result.getStringExtra(PackageInstaller.EXTRA_STATUS_MESSAGE) + "]");
+ return;
}
-
- System.out.println("Success");
} finally {
IoUtils.closeQuietly(session);
}
@@ -1274,28 +1244,14 @@ public final class Pm {
}
}
- class LocalPackageDeleteObserver extends PackageDeleteObserver {
- boolean finished;
- boolean result;
-
- @Override
- public void onPackageDeleted(String name, int returnCode, String msg) {
- synchronized (this) {
- finished = true;
- result = returnCode == PackageManager.DELETE_SUCCEEDED;
- notifyAll();
- }
- }
- }
-
- private void runUninstall() {
- int unInstallFlags = 0;
+ private void runUninstall() throws RemoteException {
+ int flags = 0;
int userId = UserHandle.USER_ALL;
String opt;
while ((opt=nextOption()) != null) {
if (opt.equals("-k")) {
- unInstallFlags |= PackageManager.DELETE_KEEP_DATA;
+ flags |= PackageManager.DELETE_KEEP_DATA;
} else if (opt.equals("--user")) {
String param = nextArg();
if (isNumber(param)) {
@@ -1320,7 +1276,7 @@ public final class Pm {
if (userId == UserHandle.USER_ALL) {
userId = UserHandle.USER_OWNER;
- unInstallFlags |= PackageManager.DELETE_ALL_USERS;
+ flags |= PackageManager.DELETE_ALL_USERS;
} else {
PackageInfo info;
try {
@@ -1340,38 +1296,25 @@ public final class Pm {
// user set flag so it disables rather than reverting to system
// version of the app.
if (isSystem) {
- unInstallFlags |= PackageManager.DELETE_SYSTEM_APP;
+ flags |= PackageManager.DELETE_SYSTEM_APP;
}
}
- boolean result = deletePackage(pkg, unInstallFlags, userId);
- if (result) {
+ final LocalIntentReceiver receiver = new LocalIntentReceiver();
+ mInstaller.uninstall(pkg, flags, receiver.getIntentSender(), userId);
+
+ final Intent result = receiver.getResult();
+ final int status = result.getIntExtra(PackageInstaller.EXTRA_STATUS,
+ PackageInstaller.STATUS_FAILURE);
+ if (status == PackageInstaller.STATUS_SUCCESS) {
System.out.println("Success");
} else {
- System.out.println("Failure");
+ Log.e(TAG, "Failure details: " + result.getExtras());
+ System.out.println("Failure ["
+ + result.getStringExtra(PackageInstaller.EXTRA_STATUS_MESSAGE) + "]");
}
}
- private boolean deletePackage(String packageName, int flags, int userId) {
- LocalPackageDeleteObserver obs = new LocalPackageDeleteObserver();
- try {
- mInstaller.uninstall(packageName, flags, obs.getBinder(), userId);
-
- synchronized (obs) {
- while (!obs.finished) {
- try {
- obs.wait();
- } catch (InterruptedException e) {
- }
- }
- }
- } catch (RemoteException e) {
- System.err.println(e.toString());
- System.err.println(PM_NOT_RUNNING_ERR);
- }
- return obs.result;
- }
-
static class ClearDataObserver extends IPackageDataObserver.Stub {
boolean finished;
boolean result;
@@ -1384,7 +1327,6 @@ public final class Pm {
notifyAll();
}
}
-
}
private void runClear() {
@@ -1717,6 +1659,35 @@ public final class Pm {
throw new IllegalArgumentException("ABI " + abi + " not supported on this device");
}
+ private static class LocalIntentReceiver {
+ private final SynchronousQueue<Intent> mResult = new SynchronousQueue<>();
+
+ private IIntentSender.Stub mLocalSender = new IIntentSender.Stub() {
+ @Override
+ public int send(int code, Intent intent, String resolvedType,
+ IIntentReceiver finishedReceiver, String requiredPermission) {
+ try {
+ mResult.offer(intent, 5, TimeUnit.SECONDS);
+ } catch (InterruptedException e) {
+ throw new RuntimeException(e);
+ }
+ return 0;
+ }
+ };
+
+ public IntentSender getIntentSender() {
+ return new IntentSender((IIntentSender) mLocalSender);
+ }
+
+ public Intent getResult() {
+ try {
+ return mResult.poll(30, TimeUnit.SECONDS);
+ } catch (InterruptedException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ }
+
private String nextOption() {
if (mNextArg >= mArgs.length) {
return null;
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 1b82d8e9cc5b..d9ea671071ba 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -1807,9 +1807,13 @@ public final class ActivityThread {
}
}
- public void installSystemApplicationInfo(ApplicationInfo info) {
+ public void installSystemApplicationInfo(ApplicationInfo info, ClassLoader classLoader) {
synchronized (this) {
- getSystemContext().installSystemApplicationInfo(info);
+ getSystemContext().installSystemApplicationInfo(info, classLoader);
+
+ // The code package for "android" in the system server needs
+ // to be the system context's package.
+ mPackages.put("android", new WeakReference<LoadedApk>(getSystemContext().mPackageInfo));
// give ourselves a default profiler
mProfiler = new Profiler();
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index a935dc02c3fc..b2812e3099ca 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -1568,7 +1568,7 @@ final class ApplicationPackageManager extends PackageManager {
synchronized (mLock) {
if (mInstaller == null) {
try {
- mInstaller = new PackageInstaller(this, mPM.getPackageInstaller(),
+ mInstaller = new PackageInstaller(mContext, this, mPM.getPackageInstaller(),
mContext.getPackageName(), mContext.getUserId());
} catch (RemoteException e) {
throw e.rethrowAsRuntimeException();
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 4cf8cb4b3523..da343ac2f5dd 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -2301,8 +2301,8 @@ class ContextImpl extends Context {
}
}
- void installSystemApplicationInfo(ApplicationInfo info) {
- mPackageInfo.installSystemApplicationInfo(info);
+ void installSystemApplicationInfo(ApplicationInfo info, ClassLoader classLoader) {
+ mPackageInfo.installSystemApplicationInfo(info, classLoader);
}
final void scheduleFinalCleanup(String who, String what) {
diff --git a/core/java/android/app/DatePickerDialog.java b/core/java/android/app/DatePickerDialog.java
index a78b13726589..1e556d67d45c 100644
--- a/core/java/android/app/DatePickerDialog.java
+++ b/core/java/android/app/DatePickerDialog.java
@@ -24,8 +24,10 @@ import android.text.format.DateUtils;
import android.util.TypedValue;
import android.view.LayoutInflater;
import android.view.View;
+import android.widget.Button;
import android.widget.DatePicker;
import android.widget.DatePicker.OnDateChangedListener;
+import android.widget.DatePicker.ValidationCallback;
import com.android.internal.R;
@@ -49,7 +51,6 @@ public class DatePickerDialog extends AlertDialog implements OnClickListener,
private final Calendar mCalendar;
private boolean mTitleNeedsUpdate = true;
- private boolean mIsCanceled = false;
/**
* The callback used to indicate the user is done filling in the date.
@@ -83,7 +84,7 @@ public class DatePickerDialog extends AlertDialog implements OnClickListener,
static int resolveDialogTheme(Context context, int resid) {
if (resid == 0) {
- TypedValue outValue = new TypedValue();
+ final TypedValue outValue = new TypedValue();
context.getTheme().resolveAttribute(R.attr.datePickerDialogTheme, outValue, true);
return outValue.resourceId;
} else {
@@ -99,68 +100,41 @@ public class DatePickerDialog extends AlertDialog implements OnClickListener,
* @param monthOfYear The initial month of the dialog.
* @param dayOfMonth The initial day of the dialog.
*/
- public DatePickerDialog(Context context,
- int theme,
- OnDateSetListener listener,
- int year,
- int monthOfYear,
- int dayOfMonth) {
+ public DatePickerDialog(Context context, int theme, OnDateSetListener listener, int year,
+ int monthOfYear, int dayOfMonth) {
super(context, resolveDialogTheme(context, theme));
mDateSetListener = listener;
mCalendar = Calendar.getInstance();
- Context themeContext = getContext();
-
- final LayoutInflater inflater = (LayoutInflater) themeContext.getSystemService(
- Context.LAYOUT_INFLATER_SERVICE);
+ final Context themeContext = getContext();
+ final LayoutInflater inflater = LayoutInflater.from(themeContext);
final View view = inflater.inflate(R.layout.date_picker_dialog, null);
setView(view);
+ setButton(BUTTON_POSITIVE, themeContext.getString(R.string.ok), this);
+ setButton(BUTTON_NEGATIVE, themeContext.getString(R.string.cancel), this);
setButtonPanelLayoutHint(LAYOUT_HINT_SIDE);
- // Initialize state
mDatePicker = (DatePicker) view.findViewById(R.id.datePicker);
- mDatePicker.setShowDoneButton(true);
- mDatePicker.setDismissCallback(new DatePicker.DatePickerDismissCallback() {
- @Override
- public void dismiss(DatePicker view, boolean isCancel, int year, int month, int dayOfMonth) {
- mIsCanceled = isCancel;
- if (!isCancel) {
- mDateSetListener.onDateSet(view, year, month, dayOfMonth);
- }
- DatePickerDialog.this.dismiss();
- }
- });
mDatePicker.init(year, monthOfYear, dayOfMonth, this);
- }
-
- public void onClick(DialogInterface dialog, int which) {
- tryNotifyDateSet();
+ mDatePicker.setValidationCallback(mValidationCallback);
}
@Override
- public void cancel() {
- mIsCanceled = true;
- super.cancel();
- }
-
- @Override
- protected void onStop() {
- tryNotifyDateSet();
- super.onStop();
- }
-
- public void onDateChanged(DatePicker view, int year,
- int month, int day) {
+ public void onDateChanged(DatePicker view, int year, int month, int day) {
mDatePicker.init(year, month, day, this);
updateTitle(year, month, day);
}
- private void tryNotifyDateSet() {
- if (mDateSetListener != null && !mIsCanceled) {
- mDatePicker.clearFocus();
- mDateSetListener.onDateSet(mDatePicker, mDatePicker.getYear(),
- mDatePicker.getMonth(), mDatePicker.getDayOfMonth());
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ switch (which) {
+ case BUTTON_POSITIVE:
+ if (mDateSetListener != null) {
+ mDateSetListener.onDateSet(mDatePicker, mDatePicker.getYear(),
+ mDatePicker.getMonth(), mDatePicker.getDayOfMonth());
+ }
+ break;
}
}
@@ -208,7 +182,7 @@ public class DatePickerDialog extends AlertDialog implements OnClickListener,
@Override
public Bundle onSaveInstanceState() {
- Bundle state = super.onSaveInstanceState();
+ final Bundle state = super.onSaveInstanceState();
state.putInt(YEAR, mDatePicker.getYear());
state.putInt(MONTH, mDatePicker.getMonth());
state.putInt(DAY, mDatePicker.getDayOfMonth());
@@ -218,9 +192,19 @@ public class DatePickerDialog extends AlertDialog implements OnClickListener,
@Override
public void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
- int year = savedInstanceState.getInt(YEAR);
- int month = savedInstanceState.getInt(MONTH);
- int day = savedInstanceState.getInt(DAY);
+ final int year = savedInstanceState.getInt(YEAR);
+ final int month = savedInstanceState.getInt(MONTH);
+ final int day = savedInstanceState.getInt(DAY);
mDatePicker.init(year, month, day, this);
}
+
+ private final ValidationCallback mValidationCallback = new ValidationCallback() {
+ @Override
+ public void onValidationChanged(boolean valid) {
+ final Button positive = getButton(BUTTON_POSITIVE);
+ if (positive != null) {
+ positive.setEnabled(valid);
+ }
+ }
+ };
}
diff --git a/core/java/android/app/INotificationManager.aidl b/core/java/android/app/INotificationManager.aidl
index 4b659347e80a..e8f681872450 100644
--- a/core/java/android/app/INotificationManager.aidl
+++ b/core/java/android/app/INotificationManager.aidl
@@ -66,7 +66,7 @@ interface INotificationManager
boolean setZenModeConfig(in ZenModeConfig config);
oneway void notifyConditions(String pkg, in IConditionProvider provider, in Condition[] conditions);
oneway void requestZenModeConditions(in IConditionListener callback, int relevance);
- oneway void setZenModeCondition(in Uri conditionId);
+ oneway void setZenModeCondition(in Condition condition);
oneway void setAutomaticZenModeConditions(in Uri[] conditionIds);
Condition[] getAutomaticZenModeConditions();
} \ No newline at end of file
diff --git a/core/java/android/app/LoadedApk.java b/core/java/android/app/LoadedApk.java
index 24c283590188..e0c7816b78d9 100644
--- a/core/java/android/app/LoadedApk.java
+++ b/core/java/android/app/LoadedApk.java
@@ -40,6 +40,7 @@ import android.os.StrictMode;
import android.os.Trace;
import android.os.UserHandle;
import android.util.AndroidRuntimeException;
+import android.util.Log;
import android.util.Slog;
import android.util.SparseArray;
import android.view.DisplayAdjustments;
@@ -199,9 +200,10 @@ public final class LoadedApk {
/**
* Sets application info about the system package.
*/
- void installSystemApplicationInfo(ApplicationInfo info) {
+ void installSystemApplicationInfo(ApplicationInfo info, ClassLoader classLoader) {
assert info.packageName.equals("android");
mApplicationInfo = info;
+ mClassLoader = classLoader;
}
public String getPackageName() {
@@ -262,10 +264,6 @@ public final class LoadedApk {
if (!Objects.equals(mPackageName, ActivityThread.currentPackageName())) {
final String isa = VMRuntime.getRuntime().vmInstructionSet();
try {
- // TODO: We can probably do away with the isa argument since
- // the AM and PM have enough information to figure this out
- // themselves. If we do need it, we should match it against the
- // list of devices ISAs before sending it down to installd.
ActivityThread.getPackageManager().performDexOptIfNeeded(mPackageName, isa);
} catch (RemoteException re) {
// Ignored.
@@ -646,8 +644,17 @@ public final class LoadedApk {
}
private void rewriteRValues(ClassLoader cl, String packageName, int id) {
+ final Class<?> rClazz;
+ try {
+ rClazz = cl.loadClass(packageName + ".R");
+ } catch (ClassNotFoundException e) {
+ // This is not necessarily an error, as some packages do not ship with resources
+ // (or they do not need rewriting).
+ Log.i(TAG, "Could not find R class for package '" + packageName + "'");
+ return;
+ }
+
try {
- final Class<?> rClazz = cl.loadClass(packageName + ".R");
Class<?>[] declaredClasses = rClazz.getDeclaredClasses();
for (Class<?> clazz : declaredClasses) {
try {
diff --git a/core/java/android/app/TimePickerDialog.java b/core/java/android/app/TimePickerDialog.java
index a2f30508c387..697c5d8f4b67 100644
--- a/core/java/android/app/TimePickerDialog.java
+++ b/core/java/android/app/TimePickerDialog.java
@@ -19,13 +19,14 @@ package android.app;
import android.content.Context;
import android.content.DialogInterface;
import android.content.DialogInterface.OnClickListener;
-import android.os.Build;
import android.os.Bundle;
import android.util.TypedValue;
import android.view.LayoutInflater;
import android.view.View;
+import android.widget.Button;
import android.widget.TimePicker;
import android.widget.TimePicker.OnTimeChangedListener;
+import android.widget.TimePicker.ValidationCallback;
import com.android.internal.R;
@@ -35,8 +36,19 @@ import com.android.internal.R;
* <p>See the <a href="{@docRoot}guide/topics/ui/controls/pickers.html">Pickers</a>
* guide.</p>
*/
-public class TimePickerDialog extends AlertDialog
- implements OnClickListener, OnTimeChangedListener {
+public class TimePickerDialog extends AlertDialog implements OnClickListener,
+ OnTimeChangedListener {
+
+ private static final String HOUR = "hour";
+ private static final String MINUTE = "minute";
+ private static final String IS_24_HOUR = "is24hour";
+
+ private final TimePicker mTimePicker;
+ private final OnTimeSetListener mTimeSetCallback;
+
+ private final int mInitialHourOfDay;
+ private final int mInitialMinute;
+ private final boolean mIs24HourView;
/**
* The callback interface used to indicate the user is done filling in
@@ -52,19 +64,6 @@ public class TimePickerDialog extends AlertDialog
void onTimeSet(TimePicker view, int hourOfDay, int minute);
}
- private static final String HOUR = "hour";
- private static final String MINUTE = "minute";
- private static final String IS_24_HOUR = "is24hour";
-
- private final TimePicker mTimePicker;
- private final OnTimeSetListener mTimeSetCallback;
-
- int mInitialHourOfDay;
- int mInitialMinute;
- boolean mIs24HourView;
-
- private boolean mIsCanceled;
-
/**
* @param context Parent.
* @param callBack How parent is notified.
@@ -80,7 +79,7 @@ public class TimePickerDialog extends AlertDialog
static int resolveDialogTheme(Context context, int resid) {
if (resid == 0) {
- TypedValue outValue = new TypedValue();
+ final TypedValue outValue = new TypedValue();
context.getTheme().resolveAttribute(R.attr.timePickerDialogTheme, outValue, true);
return outValue.resourceId;
} else {
@@ -96,10 +95,8 @@ public class TimePickerDialog extends AlertDialog
* @param minute The initial minute.
* @param is24HourView Whether this is a 24 hour view, or AM/PM.
*/
- public TimePickerDialog(Context context,
- int theme,
- OnTimeSetListener callBack,
- int hourOfDay, int minute, boolean is24HourView) {
+ public TimePickerDialog(Context context, int theme, OnTimeSetListener callBack, int hourOfDay,
+ int minute, boolean is24HourView) {
super(context, resolveDialogTheme(context, theme));
mTimeSetCallback = callBack;
@@ -108,72 +105,51 @@ public class TimePickerDialog extends AlertDialog
mIs24HourView = is24HourView;
final Context themeContext = getContext();
-
- final int targetSdkVersion = themeContext.getApplicationInfo().targetSdkVersion;
- if (targetSdkVersion < Build.VERSION_CODES.L) {
- setIcon(0);
- setTitle(R.string.time_picker_dialog_title);
- }
-
final LayoutInflater inflater = LayoutInflater.from(themeContext);
final View view = inflater.inflate(R.layout.time_picker_dialog, null);
setView(view);
+ setButton(BUTTON_POSITIVE, themeContext.getString(R.string.ok), this);
+ setButton(BUTTON_NEGATIVE, themeContext.getString(R.string.cancel), this);
mTimePicker = (TimePicker) view.findViewById(R.id.timePicker);
- mTimePicker.setShowDoneButton(true);
- // If time picker layout has no done button, add a dialog button.
- if (!mTimePicker.isShowDoneButton()) {
- setButton(BUTTON_POSITIVE, themeContext.getText(R.string.date_time_done), this);
- }
-
- mTimePicker.setDismissCallback(new TimePicker.TimePickerDismissCallback() {
- @Override
- public void dismiss(TimePicker view, boolean isCancel, int hourOfDay, int minute) {
- mIsCanceled = isCancel;
- if (!isCancel) {
- mTimeSetCallback.onTimeSet(view, hourOfDay, minute);
- TimePickerDialog.this.dismiss();
- } else {
- TimePickerDialog.this.cancel();
- }
- }
- });
mTimePicker.setIs24HourView(mIs24HourView);
mTimePicker.setCurrentHour(mInitialHourOfDay);
mTimePicker.setCurrentMinute(mInitialMinute);
mTimePicker.setOnTimeChangedListener(this);
+ mTimePicker.setValidationCallback(mValidationCallback);
}
- public void onClick(DialogInterface dialog, int which) {
- tryNotifyTimeSet();
- }
-
- public void updateTime(int hourOfDay, int minutOfHour) {
- mTimePicker.setCurrentHour(hourOfDay);
- mTimePicker.setCurrentMinute(minutOfHour);
- }
-
+ @Override
public void onTimeChanged(TimePicker view, int hourOfDay, int minute) {
/* do nothing */
}
- private void tryNotifyTimeSet() {
- if (mTimeSetCallback != null && !mIsCanceled) {
- mTimePicker.clearFocus();
- mTimeSetCallback.onTimeSet(mTimePicker, mTimePicker.getCurrentHour(),
- mTimePicker.getCurrentMinute());
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ switch (which) {
+ case BUTTON_POSITIVE:
+ if (mTimeSetCallback != null) {
+ mTimeSetCallback.onTimeSet(mTimePicker, mTimePicker.getCurrentHour(),
+ mTimePicker.getCurrentMinute());
+ }
+ break;
}
}
- @Override
- protected void onStop() {
- tryNotifyTimeSet();
- super.onStop();
+ /**
+ * Sets the current time.
+ *
+ * @param hourOfDay The current hour within the day.
+ * @param minuteOfHour The current minute within the hour.
+ */
+ public void updateTime(int hourOfDay, int minuteOfHour) {
+ mTimePicker.setCurrentHour(hourOfDay);
+ mTimePicker.setCurrentMinute(minuteOfHour);
}
@Override
public Bundle onSaveInstanceState() {
- Bundle state = super.onSaveInstanceState();
+ final Bundle state = super.onSaveInstanceState();
state.putInt(HOUR, mTimePicker.getCurrentHour());
state.putInt(MINUTE, mTimePicker.getCurrentMinute());
state.putBoolean(IS_24_HOUR, mTimePicker.is24HourView());
@@ -183,10 +159,20 @@ public class TimePickerDialog extends AlertDialog
@Override
public void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
- int hour = savedInstanceState.getInt(HOUR);
- int minute = savedInstanceState.getInt(MINUTE);
+ final int hour = savedInstanceState.getInt(HOUR);
+ final int minute = savedInstanceState.getInt(MINUTE);
mTimePicker.setIs24HourView(savedInstanceState.getBoolean(IS_24_HOUR));
mTimePicker.setCurrentHour(hour);
mTimePicker.setCurrentMinute(minute);
}
+
+ private final ValidationCallback mValidationCallback = new ValidationCallback() {
+ @Override
+ public void onValidationChanged(boolean valid) {
+ final Button positive = getButton(BUTTON_POSITIVE);
+ if (positive != null) {
+ positive.setEnabled(valid);
+ }
+ }
+ };
}
diff --git a/core/java/android/app/backup/BackupManager.java b/core/java/android/app/backup/BackupManager.java
index e9297b97c2b2..1bb4eba57c37 100644
--- a/core/java/android/app/backup/BackupManager.java
+++ b/core/java/android/app/backup/BackupManager.java
@@ -229,6 +229,28 @@ public class BackupManager {
}
/**
+ * Enable/disable data restore at application install time. When enabled, app
+ * installation will include an attempt to fetch the app's historical data from
+ * the archival restore dataset (if any). When disabled, no such attempt will
+ * be made.
+ *
+ * <p>Callers must hold the android.permission.BACKUP permission to use this method.
+ *
+ * @hide
+ */
+ @SystemApi
+ public void setAutoRestore(boolean isEnabled) {
+ checkServiceBinder();
+ if (sService != null) {
+ try {
+ sService.setAutoRestore(isEnabled);
+ } catch (RemoteException e) {
+ Log.e(TAG, "setAutoRestore() couldn't connect");
+ }
+ }
+ }
+
+ /**
* Identify the currently selected transport. Callers must hold the
* android.permission.BACKUP permission to use this method.
* @return The name of the currently active backup transport. In case of
diff --git a/core/java/android/appwidget/AppWidgetProviderInfo.java b/core/java/android/appwidget/AppWidgetProviderInfo.java
index a767246be808..02f70c8a6809 100644
--- a/core/java/android/appwidget/AppWidgetProviderInfo.java
+++ b/core/java/android/appwidget/AppWidgetProviderInfo.java
@@ -271,13 +271,13 @@ public class AppWidgetProviderInfo implements Parcelable {
* @return The provider icon.
*/
public final Drawable loadIcon(@NonNull Context context, int density) {
- return loadDrawable(context, density, providerInfo.getIconResource());
+ return loadDrawable(context, density, providerInfo.getIconResource(), true);
}
/**
* Loads a preview of what the AppWidget will look like after it's configured.
- * If not supplied, the AppWidget's icon will be used. A client can optionally
- * provide a desired deinsity such as {@link android.util.DisplayMetrics#DENSITY_LOW}
+ * A client can optionally provide a desired density such as
+ * {@link android.util.DisplayMetrics#DENSITY_LOW}
* {@link android.util.DisplayMetrics#DENSITY_MEDIUM}, etc. If no density is
* provided, the density of the current display will be used.
* <p>
@@ -288,10 +288,10 @@ public class AppWidgetProviderInfo implements Parcelable {
* @param context Context for accessing resources.
* @param density The optional desired density as per
* {@link android.util.DisplayMetrics#densityDpi}.
- * @return The widget preview image.
+ * @return The widget preview image or null if preview image is not available.
*/
public final Drawable loadPreviewImage(@NonNull Context context, int density) {
- return loadDrawable(context, density, previewImage);
+ return loadDrawable(context, density, previewImage, false);
}
/**
@@ -361,7 +361,8 @@ public class AppWidgetProviderInfo implements Parcelable {
return 0;
}
- private Drawable loadDrawable(Context context, int density, int resourceId) {
+ private Drawable loadDrawable(Context context, int density, int resourceId,
+ boolean loadDefaultIcon) {
try {
Resources resources = context.getPackageManager().getResourcesForApplication(
providerInfo.applicationInfo);
@@ -374,7 +375,7 @@ public class AppWidgetProviderInfo implements Parcelable {
} catch (PackageManager.NameNotFoundException | Resources.NotFoundException e) {
/* ignore */
}
- return providerInfo.loadIcon(context.getPackageManager());
+ return loadDefaultIcon ? providerInfo.loadIcon(context.getPackageManager()) : null;
}
/**
diff --git a/core/java/android/content/pm/FeatureGroupInfo.java b/core/java/android/content/pm/FeatureGroupInfo.java
new file mode 100644
index 000000000000..79a6eea9a955
--- /dev/null
+++ b/core/java/android/content/pm/FeatureGroupInfo.java
@@ -0,0 +1,65 @@
+/**
+ * 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.content.pm;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * A set of features that can be requested by an application. This corresponds
+ * to information collected from the
+ * AndroidManifest.xml's {@code <feature-group>} tag.
+ */
+public final class FeatureGroupInfo implements Parcelable {
+
+ /**
+ * The list of features that are required by this group.
+ *
+ * @see FeatureInfo#FLAG_REQUIRED
+ */
+ public FeatureInfo[] features;
+
+ public FeatureGroupInfo() {
+ }
+
+ public FeatureGroupInfo(FeatureGroupInfo other) {
+ features = other.features;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeTypedArray(features, flags);
+ }
+
+ public static final Creator<FeatureGroupInfo> CREATOR = new Creator<FeatureGroupInfo>() {
+ @Override
+ public FeatureGroupInfo createFromParcel(Parcel source) {
+ FeatureGroupInfo group = new FeatureGroupInfo();
+ group.features = source.createTypedArray(FeatureInfo.CREATOR);
+ return group;
+ }
+
+ @Override
+ public FeatureGroupInfo[] newArray(int size) {
+ return new FeatureGroupInfo[size];
+ }
+ };
+}
diff --git a/core/java/android/content/pm/FeatureInfo.java b/core/java/android/content/pm/FeatureInfo.java
index d919fc347fd7..79fa32791a31 100644
--- a/core/java/android/content/pm/FeatureInfo.java
+++ b/core/java/android/content/pm/FeatureInfo.java
@@ -22,7 +22,7 @@ import android.os.Parcelable;
/**
* A single feature that can be requested by an application. This corresponds
* to information collected from the
- * AndroidManifest.xml's &lt;uses-feature&gt; tag.
+ * AndroidManifest.xml's {@code <uses-feature>} tag.
*/
public class FeatureInfo implements Parcelable {
/**
diff --git a/core/java/android/content/pm/IPackageInstaller.aidl b/core/java/android/content/pm/IPackageInstaller.aidl
index 5223476fc43d..97be8f0e080b 100644
--- a/core/java/android/content/pm/IPackageInstaller.aidl
+++ b/core/java/android/content/pm/IPackageInstaller.aidl
@@ -19,23 +19,22 @@ package android.content.pm;
import android.content.pm.IPackageDeleteObserver2;
import android.content.pm.IPackageInstallerCallback;
import android.content.pm.IPackageInstallerSession;
-import android.content.pm.InstallSessionInfo;
-import android.content.pm.InstallSessionParams;
+import android.content.pm.PackageInstaller;
+import android.content.IntentSender;
/** {@hide} */
interface IPackageInstaller {
- int createSession(in InstallSessionParams params, String installerPackageName, int userId);
+ int createSession(in PackageInstaller.SessionParams params, String installerPackageName, int userId);
IPackageInstallerSession openSession(int sessionId);
- InstallSessionInfo getSessionInfo(int sessionId);
- List<InstallSessionInfo> getAllSessions(int userId);
- List<InstallSessionInfo> getMySessions(String installerPackageName, int userId);
+ PackageInstaller.SessionInfo getSessionInfo(int sessionId);
+ List<PackageInstaller.SessionInfo> getAllSessions(int userId);
+ List<PackageInstaller.SessionInfo> getMySessions(String installerPackageName, int userId);
void registerCallback(IPackageInstallerCallback callback, int userId);
void unregisterCallback(IPackageInstallerCallback callback);
- void uninstall(String packageName, int flags, in IPackageDeleteObserver2 observer, int userId);
- void uninstallSplit(String packageName, String splitName, int flags, in IPackageDeleteObserver2 observer, int userId);
+ void uninstall(String packageName, int flags, in IntentSender statusReceiver, int userId);
void setPermissionsResult(int sessionId, boolean accepted);
}
diff --git a/core/java/android/content/pm/IPackageInstallerSession.aidl b/core/java/android/content/pm/IPackageInstallerSession.aidl
index af0323fe3059..aee3ba77f1f0 100644
--- a/core/java/android/content/pm/IPackageInstallerSession.aidl
+++ b/core/java/android/content/pm/IPackageInstallerSession.aidl
@@ -17,6 +17,7 @@
package android.content.pm;
import android.content.pm.IPackageInstallObserver2;
+import android.content.IntentSender;
import android.os.ParcelFileDescriptor;
/** {@hide} */
@@ -24,11 +25,11 @@ interface IPackageInstallerSession {
void setClientProgress(float progress);
void addClientProgress(float progress);
- String[] list();
+ String[] getNames();
ParcelFileDescriptor openWrite(String name, long offsetBytes, long lengthBytes);
ParcelFileDescriptor openRead(String name);
void close();
- void commit(in IPackageInstallObserver2 observer);
+ void commit(in IntentSender statusReceiver);
void abandon();
}
diff --git a/core/java/android/content/pm/InstallSessionInfo.java b/core/java/android/content/pm/InstallSessionInfo.java
deleted file mode 100644
index 161bcde5a666..000000000000
--- a/core/java/android/content/pm/InstallSessionInfo.java
+++ /dev/null
@@ -1,181 +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.content.pm;
-
-import android.annotation.Nullable;
-import android.content.Intent;
-import android.graphics.Bitmap;
-import android.os.Parcel;
-import android.os.Parcelable;
-
-/**
- * Details for an active install session.
- */
-public class InstallSessionInfo implements Parcelable {
-
- /** {@hide} */
- public int sessionId;
- /** {@hide} */
- public String installerPackageName;
- /** {@hide} */
- public String resolvedBaseCodePath;
- /** {@hide} */
- public float progress;
- /** {@hide} */
- public boolean sealed;
- /** {@hide} */
- public boolean open;
-
- /** {@hide} */
- public int mode;
- /** {@hide} */
- public long sizeBytes;
- /** {@hide} */
- public String appPackageName;
- /** {@hide} */
- public Bitmap appIcon;
- /** {@hide} */
- public CharSequence appLabel;
-
- /** {@hide} */
- public InstallSessionInfo() {
- }
-
- /** {@hide} */
- public InstallSessionInfo(Parcel source) {
- sessionId = source.readInt();
- installerPackageName = source.readString();
- resolvedBaseCodePath = source.readString();
- progress = source.readFloat();
- sealed = source.readInt() != 0;
- open = source.readInt() != 0;
-
- mode = source.readInt();
- sizeBytes = source.readLong();
- appPackageName = source.readString();
- appIcon = source.readParcelable(null);
- appLabel = source.readString();
- }
-
- /**
- * Return the ID for this session.
- */
- public int getSessionId() {
- return sessionId;
- }
-
- /**
- * Return the package name of the app that owns this session.
- */
- public @Nullable String getInstallerPackageName() {
- return installerPackageName;
- }
-
- /**
- * Return current overall progress of this session, between 0 and 1.
- * <p>
- * Note that this progress may not directly correspond to the value reported
- * by {@link PackageInstaller.Session#setProgress(float)}, as the system may
- * carve out a portion of the overall progress to represent its own internal
- * installation work.
- */
- public float getProgress() {
- return progress;
- }
-
- /**
- * Return if this session is currently open.
- */
- public boolean isOpen() {
- return open;
- }
-
- /**
- * Return the package name this session is working with. May be {@code null}
- * if unknown.
- */
- public @Nullable String getAppPackageName() {
- return appPackageName;
- }
-
- /**
- * Return an icon representing the app being installed. May be {@code null}
- * if unavailable.
- */
- public @Nullable Bitmap getAppIcon() {
- return appIcon;
- }
-
- /**
- * Return a label representing the app being installed. May be {@code null}
- * if unavailable.
- */
- public @Nullable CharSequence getAppLabel() {
- return appLabel;
- }
-
- /**
- * Return an Intent that can be started to view details about this install
- * session. This may surface actions such as pause, resume, or cancel.
- * <p>
- * In some cases, a matching Activity may not exist, so ensure you safeguard
- * against this.
- *
- * @see PackageInstaller#ACTION_SESSION_DETAILS
- */
- public @Nullable Intent getDetailsIntent() {
- final Intent intent = new Intent(PackageInstaller.ACTION_SESSION_DETAILS);
- intent.putExtra(PackageInstaller.EXTRA_SESSION_ID, sessionId);
- intent.setPackage(installerPackageName);
- intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- return intent;
- }
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- @Override
- public void writeToParcel(Parcel dest, int flags) {
- dest.writeInt(sessionId);
- dest.writeString(installerPackageName);
- dest.writeString(resolvedBaseCodePath);
- dest.writeFloat(progress);
- dest.writeInt(sealed ? 1 : 0);
- dest.writeInt(open ? 1 : 0);
-
- dest.writeInt(mode);
- dest.writeLong(sizeBytes);
- dest.writeString(appPackageName);
- dest.writeParcelable(appIcon, flags);
- dest.writeString(appLabel != null ? appLabel.toString() : null);
- }
-
- public static final Parcelable.Creator<InstallSessionInfo>
- CREATOR = new Parcelable.Creator<InstallSessionInfo>() {
- @Override
- public InstallSessionInfo createFromParcel(Parcel p) {
- return new InstallSessionInfo(p);
- }
-
- @Override
- public InstallSessionInfo[] newArray(int size) {
- return new InstallSessionInfo[size];
- }
- };
-}
diff --git a/core/java/android/content/pm/InstallSessionParams.aidl b/core/java/android/content/pm/InstallSessionParams.aidl
deleted file mode 100644
index 81b75740301d..000000000000
--- a/core/java/android/content/pm/InstallSessionParams.aidl
+++ /dev/null
@@ -1,19 +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.content.pm;
-
-parcelable InstallSessionParams;
diff --git a/core/java/android/content/pm/InstallSessionParams.java b/core/java/android/content/pm/InstallSessionParams.java
deleted file mode 100644
index 1716e397cf3e..000000000000
--- a/core/java/android/content/pm/InstallSessionParams.java
+++ /dev/null
@@ -1,227 +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.content.pm;
-
-import android.annotation.Nullable;
-import android.app.ActivityManager;
-import android.content.Intent;
-import android.graphics.Bitmap;
-import android.net.Uri;
-import android.os.Parcel;
-import android.os.Parcelable;
-
-import com.android.internal.util.IndentingPrintWriter;
-
-/**
- * Parameters for creating a new {@link PackageInstaller.Session}.
- */
-public class InstallSessionParams implements Parcelable {
-
- /** {@hide} */
- public static final int MODE_INVALID = -1;
-
- /**
- * Mode for an install session whose staged APKs should fully replace any
- * existing APKs for the target app.
- */
- public static final int MODE_FULL_INSTALL = 1;
-
- /**
- * Mode for an install session that should inherit any existing APKs for the
- * target app, unless they have been explicitly overridden (based on split
- * name) by the session. For example, this can be used to add one or more
- * split APKs to an existing installation.
- * <p>
- * If there are no existing APKs for the target app, this behaves like
- * {@link #MODE_FULL_INSTALL}.
- */
- public static final int MODE_INHERIT_EXISTING = 2;
-
- /** {@hide} */
- public int mode = MODE_INVALID;
- /** {@hide} */
- public int installFlags;
- /** {@hide} */
- public int installLocation = PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY;
- /** {@hide} */
- public long sizeBytes = -1;
- /** {@hide} */
- public String appPackageName;
- /** {@hide} */
- public Bitmap appIcon;
- /** {@hide} */
- public String appLabel;
- /** {@hide} */
- public Uri originatingUri;
- /** {@hide} */
- public Uri referrerUri;
- /** {@hide} */
- public String abiOverride;
-
- /**
- * Construct parameters for a new package install session.
- *
- * @param mode one of {@link #MODE_FULL_INSTALL} or
- * {@link #MODE_INHERIT_EXISTING} describing how the session
- * should interact with an existing app.
- */
- public InstallSessionParams(int mode) {
- this.mode = mode;
- }
-
- /** {@hide} */
- public InstallSessionParams(Parcel source) {
- mode = source.readInt();
- installFlags = source.readInt();
- installLocation = source.readInt();
- sizeBytes = source.readLong();
- appPackageName = source.readString();
- appIcon = source.readParcelable(null);
- appLabel = source.readString();
- originatingUri = source.readParcelable(null);
- referrerUri = source.readParcelable(null);
- abiOverride = source.readString();
- }
-
- /**
- * Provide value of {@link PackageInfo#installLocation}, which may be used
- * to determine where the app will be staged. Defaults to
- * {@link PackageInfo#INSTALL_LOCATION_INTERNAL_ONLY}.
- */
- public void setInstallLocation(int installLocation) {
- this.installLocation = installLocation;
- }
-
- /**
- * @deprecated use {@link PackageInstaller.Session#openRead(String)} to
- * calculate message digest instead.
- * @hide
- */
- @Deprecated
- public void setSignatures(@Nullable Signature[] signatures) {
- throw new UnsupportedOperationException();
- }
-
- /**
- * Optionally indicate the total size (in bytes) of all APKs that will be
- * delivered in this session. The system may use this to ensure enough disk
- * space exists before proceeding, or to estimate container size for
- * installations living on external storage.
- *
- * @see PackageInfo#INSTALL_LOCATION_AUTO
- * @see PackageInfo#INSTALL_LOCATION_PREFER_EXTERNAL
- */
- public void setSize(long sizeBytes) {
- this.sizeBytes = sizeBytes;
- }
-
- /**
- * Optionally set the package name of the app being installed. It's strongly
- * recommended that you provide this value when known, so that observers can
- * communicate installing apps to users.
- * <p>
- * If the APKs staged in the session aren't consistent with this package
- * name, the install will fail. Regardless of this value, all APKs in the
- * app must have the same package name.
- */
- public void setAppPackageName(@Nullable String appPackageName) {
- this.appPackageName = appPackageName;
- }
-
- /**
- * Optionally set an icon representing the app being installed. This should
- * be roughly {@link ActivityManager#getLauncherLargeIconSize()} in both
- * dimensions.
- */
- public void setAppIcon(@Nullable Bitmap appIcon) {
- this.appIcon = appIcon;
- }
-
- /**
- * Optionally set a label representing the app being installed.
- */
- public void setAppLabel(@Nullable CharSequence appLabel) {
- this.appLabel = (appLabel != null) ? appLabel.toString() : null;
- }
-
- /**
- * Optionally set the URI where this package was downloaded from. Used for
- * verification purposes.
- *
- * @see Intent#EXTRA_ORIGINATING_URI
- */
- public void setOriginatingUri(@Nullable Uri originatingUri) {
- this.originatingUri = originatingUri;
- }
-
- /**
- * Optionally set the URI that referred you to install this package. Used
- * for verification purposes.
- *
- * @see Intent#EXTRA_REFERRER
- */
- public void setReferrerUri(@Nullable Uri referrerUri) {
- this.referrerUri = referrerUri;
- }
-
- /** {@hide} */
- public void dump(IndentingPrintWriter pw) {
- pw.printPair("mode", mode);
- pw.printHexPair("installFlags", installFlags);
- pw.printPair("installLocation", installLocation);
- pw.printPair("sizeBytes", sizeBytes);
- pw.printPair("appPackageName", appPackageName);
- pw.printPair("appIcon", (appIcon != null));
- pw.printPair("appLabel", appLabel);
- pw.printPair("originatingUri", originatingUri);
- pw.printPair("referrerUri", referrerUri);
- pw.printPair("abiOverride", abiOverride);
- pw.println();
- }
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- @Override
- public void writeToParcel(Parcel dest, int flags) {
- dest.writeInt(mode);
- dest.writeInt(installFlags);
- dest.writeInt(installLocation);
- dest.writeLong(sizeBytes);
- dest.writeString(appPackageName);
- dest.writeParcelable(appIcon, flags);
- dest.writeString(appLabel);
- dest.writeParcelable(originatingUri, flags);
- dest.writeParcelable(referrerUri, flags);
- dest.writeString(abiOverride);
- }
-
- public static final Parcelable.Creator<InstallSessionParams>
- CREATOR = new Parcelable.Creator<InstallSessionParams>() {
- @Override
- public InstallSessionParams createFromParcel(Parcel p) {
- return new InstallSessionParams(p);
- }
-
- @Override
- public InstallSessionParams[] newArray(int size) {
- return new InstallSessionParams[size];
- }
- };
-}
diff --git a/core/java/android/content/pm/PackageInfo.java b/core/java/android/content/pm/PackageInfo.java
index 49ffef23afcf..a0e3c4a7f1fe 100644
--- a/core/java/android/content/pm/PackageInfo.java
+++ b/core/java/android/content/pm/PackageInfo.java
@@ -180,7 +180,7 @@ public class PackageInfo implements Parcelable {
* {@link android.R.styleable#AndroidManifestUsesConfiguration
* &lt;uses-configuration&gt;} tags included under &lt;manifest&gt;,
* or null if there were none. This is only filled in if the flag
- * {@link PackageManager#GET_CONFIGURATIONS} was set.
+ * {@link PackageManager#GET_CONFIGURATIONS} was set.
*/
public ConfigurationInfo[] configPreferences;
@@ -192,6 +192,16 @@ public class PackageInfo implements Parcelable {
public FeatureInfo[] reqFeatures;
/**
+ * Groups of features that this application has requested.
+ * Each group contains a set of features that are required.
+ * A device must match the features listed in {@link #reqFeatures} and one
+ * or more FeatureGroups in order to have satisfied the feature requirement.
+ *
+ * @see FeatureInfo#FLAG_REQUIRED
+ */
+ public FeatureGroupInfo[] featureGroups;
+
+ /**
* Constant corresponding to <code>auto</code> in
* the {@link android.R.attr#installLocation} attribute.
* @hide
@@ -300,6 +310,7 @@ public class PackageInfo implements Parcelable {
dest.writeTypedArray(signatures, parcelableFlags);
dest.writeTypedArray(configPreferences, parcelableFlags);
dest.writeTypedArray(reqFeatures, parcelableFlags);
+ dest.writeTypedArray(featureGroups, parcelableFlags);
dest.writeInt(installLocation);
dest.writeInt(requiredForAllUsers ? 1 : 0);
dest.writeInt(requiredForProfile);
@@ -344,6 +355,7 @@ public class PackageInfo implements Parcelable {
signatures = source.createTypedArray(Signature.CREATOR);
configPreferences = source.createTypedArray(ConfigurationInfo.CREATOR);
reqFeatures = source.createTypedArray(FeatureInfo.CREATOR);
+ featureGroups = source.createTypedArray(FeatureGroupInfo.CREATOR);
installLocation = source.readInt();
requiredForAllUsers = source.readInt() != 0;
requiredForProfile = source.readInt();
diff --git a/core/java/android/content/pm/InstallSessionInfo.aidl b/core/java/android/content/pm/PackageInstaller.aidl
index 3d21bbdf8249..270f870405f5 100644
--- a/core/java/android/content/pm/InstallSessionInfo.aidl
+++ b/core/java/android/content/pm/PackageInstaller.aidl
@@ -16,4 +16,5 @@
package android.content.pm;
-parcelable InstallSessionInfo;
+parcelable PackageInstaller.SessionParams;
+parcelable PackageInstaller.SessionInfo;
diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java
index d70e22caa64d..aa4ea454fc5c 100644
--- a/core/java/android/content/pm/PackageInstaller.java
+++ b/core/java/android/content/pm/PackageInstaller.java
@@ -20,17 +20,24 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
-import android.app.PackageDeleteObserver;
-import android.app.PackageInstallObserver;
+import android.app.ActivityManager;
+import android.content.Context;
import android.content.Intent;
-import android.os.Bundle;
+import android.content.IntentSender;
+import android.graphics.Bitmap;
+import android.net.Uri;
import android.os.FileBridge;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
+import android.os.Parcel;
import android.os.ParcelFileDescriptor;
+import android.os.Parcelable;
import android.os.RemoteException;
import android.util.ExceptionUtils;
+import android.util.Log;
+
+import com.android.internal.util.IndentingPrintWriter;
import java.io.Closeable;
import java.io.IOException;
@@ -67,13 +74,15 @@ import java.util.List;
* </ul>
*/
public class PackageInstaller {
+ private static final String TAG = "PackageInstaller";
+
/**
* Activity Action: Show details about a particular install session. This
* may surface actions such as pause, resume, or cancel.
* <p>
* This should always be scoped to the installer package that owns the
- * session. Clients should use {@link InstallSessionInfo#getDetailsIntent()}
- * to build this intent correctly.
+ * session. Clients should use {@link SessionInfo#getDetailsIntent()} to
+ * build this intent correctly.
* <p>
* In some cases, a matching Activity may not exist, so ensure you safeguard
* against this.
@@ -92,9 +101,110 @@ public class PackageInstaller {
*/
public static final String EXTRA_SESSION_ID = "android.content.pm.extra.SESSION_ID";
+ public static final String EXTRA_STATUS = "android.content.pm.extra.STATUS";
+ public static final String EXTRA_STATUS_MESSAGE = "android.content.pm.extra.STATUS_MESSAGE";
+
+ /**
+ * List of package names that are relevant to a status.
+ *
+ * @see Intent#getStringArrayExtra(String)
+ */
+ public static final String EXTRA_PACKAGE_NAMES = "android.content.pm.extra.PACKAGE_NAMES";
+
+ /** {@hide} */
+ public static final String EXTRA_LEGACY_STATUS = "android.content.pm.extra.LEGACY_STATUS";
+ /** {@hide} */
+ public static final String EXTRA_LEGACY_BUNDLE = "android.content.pm.extra.LEGACY_BUNDLE";
/** {@hide} */
public static final String EXTRA_CALLBACK = "android.content.pm.extra.CALLBACK";
+ /**
+ * User action is currently required to proceed. You can launch the intent
+ * activity described by {@link Intent#EXTRA_INTENT} to involve the user and
+ * continue.
+ * <p>
+ * You may choose to immediately launch the intent if the user is actively
+ * using your app. Otherwise, you should use a notification to guide the
+ * user back into your app before launching.
+ *
+ * @see Intent#getParcelableExtra(String)
+ */
+ public static final int STATUS_USER_ACTION_REQUIRED = -1;
+
+ /**
+ * The operation succeeded.
+ */
+ public static final int STATUS_SUCCESS = 0;
+
+ /**
+ * The operation failed in a generic way. The system will always try to
+ * provide a more specific failure reason, but in some rare cases this may
+ * be delivered.
+ *
+ * @see #EXTRA_STATUS_MESSAGE
+ */
+ public static final int STATUS_FAILURE = 1;
+
+ /**
+ * The operation failed because it was blocked. For example, a device policy
+ * may be blocking the operation, a package verifier may have blocked the
+ * operation, or the app may be required for core system operation.
+ *
+ * @see #EXTRA_STATUS_MESSAGE
+ */
+ public static final int STATUS_FAILURE_BLOCKED = 1;
+
+ /**
+ * The operation failed because it was actively aborted. For example, the
+ * user actively declined requested permissions, or the session was
+ * abandoned.
+ *
+ * @see #EXTRA_STATUS_MESSAGE
+ */
+ public static final int STATUS_FAILURE_ABORTED = 2;
+
+ /**
+ * The operation failed because one or more of the APKs was invalid. For
+ * example, they might be malformed, corrupt, incorrectly signed,
+ * mismatched, etc.
+ *
+ * @see #EXTRA_STATUS_MESSAGE
+ */
+ public static final int STATUS_FAILURE_INVALID = 3;
+
+ /**
+ * The operation failed because it conflicts (or is inconsistent with) with
+ * another package already installed on the device. For example, an existing
+ * permission, incompatible certificates, etc. The user may be able to
+ * uninstall another app to fix the issue.
+ * <p>
+ * The result may also contain {@link #EXTRA_PACKAGE_NAMES} with the
+ * specific packages identified as the cause of the conflict.
+ *
+ * @see #EXTRA_STATUS_MESSAGE
+ */
+ public static final int STATUS_FAILURE_CONFLICT = 4;
+
+ /**
+ * The operation failed because of storage issues. For example, the device
+ * may be running low on space, or external media may be unavailable. The
+ * user may be able to help free space or insert different external media.
+ *
+ * @see #EXTRA_STATUS_MESSAGE
+ */
+ public static final int STATUS_FAILURE_STORAGE = 5;
+
+ /**
+ * The operation failed because it is fundamentally incompatible with this
+ * device. For example, the app may require a hardware feature that doesn't
+ * exist, it may be missing native code for the ABIs supported by the
+ * device, or it requires a newer SDK version, etc.
+ *
+ * @see #EXTRA_STATUS_MESSAGE
+ */
+ public static final int STATUS_FAILURE_INCOMPATIBLE = 6;
+
+ private final Context mContext;
private final PackageManager mPm;
private final IPackageInstaller mInstaller;
private final int mUserId;
@@ -103,8 +213,9 @@ public class PackageInstaller {
private final ArrayList<SessionCallbackDelegate> mDelegates = new ArrayList<>();
/** {@hide} */
- public PackageInstaller(PackageManager pm, IPackageInstaller installer,
+ public PackageInstaller(Context context, PackageManager pm, IPackageInstaller installer,
String installerPackageName, int userId) {
+ mContext = context;
mPm = pm;
mInstaller = installer;
mInstallerPackageName = installerPackageName;
@@ -126,7 +237,7 @@ public class PackageInstaller {
* This ID remains consistent across device reboots until the
* session is finalized. IDs are not reused during a given boot.
*/
- public int createSession(@NonNull InstallSessionParams params) throws IOException {
+ public int createSession(@NonNull SessionParams params) throws IOException {
try {
return mInstaller.createSession(params, mInstallerPackageName, mUserId);
} catch (RuntimeException e) {
@@ -153,7 +264,7 @@ public class PackageInstaller {
* Return details for a specific session. To succeed, the caller must either
* own this session, or be the current home app.
*/
- public @Nullable InstallSessionInfo getSessionInfo(int sessionId) {
+ public @Nullable SessionInfo getSessionInfo(int sessionId) {
try {
return mInstaller.getSessionInfo(sessionId);
} catch (RemoteException e) {
@@ -165,7 +276,7 @@ public class PackageInstaller {
* Return list of all active install sessions, regardless of the installer.
* To succeed, the caller must be the current home app.
*/
- public @NonNull List<InstallSessionInfo> getAllSessions() {
+ public @NonNull List<SessionInfo> getAllSessions() {
try {
return mInstaller.getAllSessions(mUserId);
} catch (RemoteException e) {
@@ -176,7 +287,7 @@ public class PackageInstaller {
/**
* Return list of all install sessions owned by the calling app.
*/
- public @NonNull List<InstallSessionInfo> getMySessions() {
+ public @NonNull List<SessionInfo> getMySessions() {
try {
return mInstaller.getMySessions(mInstallerPackageName, mUserId);
} catch (RemoteException e) {
@@ -189,25 +300,9 @@ public class PackageInstaller {
* method is only available to the current "installer of record" for the
* package.
*/
- public void uninstall(@NonNull String packageName, @NonNull UninstallCallback callback) {
- try {
- mInstaller.uninstall(packageName, 0,
- new UninstallCallbackDelegate(callback).getBinder(), mUserId);
- } catch (RemoteException e) {
- throw e.rethrowAsRuntimeException();
- }
- }
-
- /**
- * Uninstall only a specific split from the given package.
- *
- * @hide
- */
- public void uninstall(@NonNull String packageName, @NonNull String splitName,
- @NonNull UninstallCallback callback) {
+ public void uninstall(@NonNull String packageName, @NonNull IntentSender statusReceiver) {
try {
- mInstaller.uninstallSplit(packageName, splitName, 0,
- new UninstallCallbackDelegate(callback).getBinder(), mUserId);
+ mInstaller.uninstall(packageName, 0, statusReceiver, mUserId);
} catch (RemoteException e) {
throw e.rethrowAsRuntimeException();
}
@@ -353,6 +448,14 @@ public class PackageInstaller {
* calling thread.
*/
public void addSessionCallback(@NonNull SessionCallback callback, @NonNull Handler handler) {
+ // TODO: remove this temporary guard once we have new prebuilts
+ final ApplicationInfo info = mContext.getApplicationInfo();
+ if ("com.google.android.googlequicksearchbox".equals(info.packageName)
+ && info.versionCode <= 300400070) {
+ Log.d(TAG, "Ignoring callback request from old prebuilt");
+ return;
+ }
+
synchronized (mDelegates) {
final SessionCallbackDelegate delegate = new SessionCallbackDelegate(callback,
handler.getLooper());
@@ -436,7 +539,7 @@ public class PackageInstaller {
* You can write data into the returned stream, optionally call
* {@link #fsync(OutputStream)} as needed to ensure bytes have been
* persisted to disk, and then close when finished. All streams must be
- * closed before calling {@link #commit(CommitCallback)}.
+ * closed before calling {@link #commit(IntentSender)}.
*
* @param name arbitrary, unique name of your choosing to identify the
* APK being written. You can open a file again for
@@ -476,14 +579,14 @@ public class PackageInstaller {
}
/**
- * List all APK names contained in this session.
+ * Return all APK names contained in this session.
* <p>
* This returns all names which have been previously written through
* {@link #openWrite(String, long, long)} as part of this session.
*/
- public @NonNull String[] list() {
+ public @NonNull String[] getNames() {
try {
- return mSession.list();
+ return mSession.getNames();
} catch (RemoteException e) {
throw e.rethrowAsRuntimeException();
}
@@ -518,9 +621,9 @@ public class PackageInstaller {
* on the session. If the device reboots before the session has been
* finalized, you may commit the session again.
*/
- public void commit(@NonNull CommitCallback callback) {
+ public void commit(@NonNull IntentSender statusReceiver) {
try {
- mSession.commit(new CommitCallbackDelegate(callback).getBinder());
+ mSession.commit(statusReceiver);
} catch (RemoteException e) {
throw e.rethrowAsRuntimeException();
}
@@ -553,169 +656,350 @@ public class PackageInstaller {
}
/**
- * Events for a specific uninstall request.
+ * Parameters for creating a new {@link PackageInstaller.Session}.
*/
- public static abstract class UninstallCallback {
+ public static class SessionParams implements Parcelable {
+
+ /** {@hide} */
+ public static final int MODE_INVALID = -1;
+
+ /**
+ * Mode for an install session whose staged APKs should fully replace any
+ * existing APKs for the target app.
+ */
+ public static final int MODE_FULL_INSTALL = 1;
+
+ /**
+ * Mode for an install session that should inherit any existing APKs for the
+ * target app, unless they have been explicitly overridden (based on split
+ * name) by the session. For example, this can be used to add one or more
+ * split APKs to an existing installation.
+ * <p>
+ * If there are no existing APKs for the target app, this behaves like
+ * {@link #MODE_FULL_INSTALL}.
+ */
+ public static final int MODE_INHERIT_EXISTING = 2;
+
+ /** {@hide} */
+ public int mode = MODE_INVALID;
+ /** {@hide} */
+ public int installFlags;
+ /** {@hide} */
+ public int installLocation = PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY;
+ /** {@hide} */
+ public long sizeBytes = -1;
+ /** {@hide} */
+ public String appPackageName;
+ /** {@hide} */
+ public Bitmap appIcon;
+ /** {@hide} */
+ public String appLabel;
+ /** {@hide} */
+ public Uri originatingUri;
+ /** {@hide} */
+ public Uri referrerUri;
+ /** {@hide} */
+ public String abiOverride;
+
/**
- * Generic unknown failure. The system will always try to provide a more
- * specific failure reason, but in some rare cases this may be
- * delivered.
+ * Construct parameters for a new package install session.
+ *
+ * @param mode one of {@link #MODE_FULL_INSTALL} or
+ * {@link #MODE_INHERIT_EXISTING} describing how the session
+ * should interact with an existing app.
*/
- public static final int FAILURE_UNKNOWN = 0;
+ public SessionParams(int mode) {
+ this.mode = mode;
+ }
+
+ /** {@hide} */
+ public SessionParams(Parcel source) {
+ mode = source.readInt();
+ installFlags = source.readInt();
+ installLocation = source.readInt();
+ sizeBytes = source.readLong();
+ appPackageName = source.readString();
+ appIcon = source.readParcelable(null);
+ appLabel = source.readString();
+ originatingUri = source.readParcelable(null);
+ referrerUri = source.readParcelable(null);
+ abiOverride = source.readString();
+ }
/**
- * This uninstall was blocked. The package may be required for core
- * system operation, or the user may be restricted. Attempting to
- * uninstall again will have the same result.
+ * Provide value of {@link PackageInfo#installLocation}, which may be used
+ * to determine where the app will be staged. Defaults to
+ * {@link PackageInfo#INSTALL_LOCATION_INTERNAL_ONLY}.
*/
- public static final int FAILURE_BLOCKED = 1;
+ public void setInstallLocation(int installLocation) {
+ this.installLocation = installLocation;
+ }
/**
- * This uninstall was actively aborted. For example, the user declined
- * to uninstall. You may try to uninstall again.
+ * Optionally indicate the total size (in bytes) of all APKs that will be
+ * delivered in this session. The system may use this to ensure enough disk
+ * space exists before proceeding, or to estimate container size for
+ * installations living on external storage.
+ *
+ * @see PackageInfo#INSTALL_LOCATION_AUTO
+ * @see PackageInfo#INSTALL_LOCATION_PREFER_EXTERNAL
*/
- public static final int FAILURE_ABORTED = 2;
+ public void setSize(long sizeBytes) {
+ this.sizeBytes = sizeBytes;
+ }
/**
- * User action is required to proceed. You can start the given intent
- * activity to involve the user and continue.
+ * Optionally set the package name of the app being installed. It's strongly
+ * recommended that you provide this value when known, so that observers can
+ * communicate installing apps to users.
* <p>
- * You may choose to immediately launch the intent if the user is
- * actively using your app. However, you should use a notification to
- * guide the user back into your app if not currently active.
+ * If the APKs staged in the session aren't consistent with this package
+ * name, the install will fail. Regardless of this value, all APKs in the
+ * app must have the same package name.
*/
- public abstract void onUserActionRequired(Intent intent);
+ public void setAppPackageName(@Nullable String appPackageName) {
+ this.appPackageName = appPackageName;
+ }
- public abstract void onSuccess();
- public abstract void onFailure(int failureReason, String msg, Bundle extras);
- }
+ /**
+ * Optionally set an icon representing the app being installed. This should
+ * be roughly {@link ActivityManager#getLauncherLargeIconSize()} in both
+ * dimensions.
+ */
+ public void setAppIcon(@Nullable Bitmap appIcon) {
+ this.appIcon = appIcon;
+ }
- /** {@hide} */
- private static class UninstallCallbackDelegate extends PackageDeleteObserver {
- private final UninstallCallback target;
+ /**
+ * Optionally set a label representing the app being installed.
+ */
+ public void setAppLabel(@Nullable CharSequence appLabel) {
+ this.appLabel = (appLabel != null) ? appLabel.toString() : null;
+ }
- public UninstallCallbackDelegate(UninstallCallback target) {
- this.target = target;
+ /**
+ * Optionally set the URI where this package was downloaded from. Used for
+ * verification purposes.
+ *
+ * @see Intent#EXTRA_ORIGINATING_URI
+ */
+ public void setOriginatingUri(@Nullable Uri originatingUri) {
+ this.originatingUri = originatingUri;
}
- @Override
- public void onUserActionRequired(Intent intent) {
- target.onUserActionRequired(intent);
+ /**
+ * Optionally set the URI that referred you to install this package. Used
+ * for verification purposes.
+ *
+ * @see Intent#EXTRA_REFERRER
+ */
+ public void setReferrerUri(@Nullable Uri referrerUri) {
+ this.referrerUri = referrerUri;
+ }
+
+ /** {@hide} */
+ public void dump(IndentingPrintWriter pw) {
+ pw.printPair("mode", mode);
+ pw.printHexPair("installFlags", installFlags);
+ pw.printPair("installLocation", installLocation);
+ pw.printPair("sizeBytes", sizeBytes);
+ pw.printPair("appPackageName", appPackageName);
+ pw.printPair("appIcon", (appIcon != null));
+ pw.printPair("appLabel", appLabel);
+ pw.printPair("originatingUri", originatingUri);
+ pw.printPair("referrerUri", referrerUri);
+ pw.printPair("abiOverride", abiOverride);
+ pw.println();
}
@Override
- public void onPackageDeleted(String basePackageName, int returnCode, String msg) {
- if (returnCode == PackageManager.DELETE_SUCCEEDED) {
- target.onSuccess();
- } else {
- final int failureReason = PackageManager.deleteStatusToFailureReason(returnCode);
- msg = PackageManager.deleteStatusToString(returnCode) + ": " + msg;
- target.onFailure(failureReason, msg, null);
- }
+ public int describeContents() {
+ return 0;
}
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(mode);
+ dest.writeInt(installFlags);
+ dest.writeInt(installLocation);
+ dest.writeLong(sizeBytes);
+ dest.writeString(appPackageName);
+ dest.writeParcelable(appIcon, flags);
+ dest.writeString(appLabel);
+ dest.writeParcelable(originatingUri, flags);
+ dest.writeParcelable(referrerUri, flags);
+ dest.writeString(abiOverride);
+ }
+
+ public static final Parcelable.Creator<SessionParams>
+ CREATOR = new Parcelable.Creator<SessionParams>() {
+ @Override
+ public SessionParams createFromParcel(Parcel p) {
+ return new SessionParams(p);
+ }
+
+ @Override
+ public SessionParams[] newArray(int size) {
+ return new SessionParams[size];
+ }
+ };
}
/**
- * Final result of a session commit request.
+ * Details for an active install session.
*/
- public static abstract class CommitCallback {
+ public static class SessionInfo implements Parcelable {
+
+ /** {@hide} */
+ public int sessionId;
+ /** {@hide} */
+ public String installerPackageName;
+ /** {@hide} */
+ public String resolvedBaseCodePath;
+ /** {@hide} */
+ public float progress;
+ /** {@hide} */
+ public boolean sealed;
+ /** {@hide} */
+ public boolean open;
+
+ /** {@hide} */
+ public int mode;
+ /** {@hide} */
+ public long sizeBytes;
+ /** {@hide} */
+ public String appPackageName;
+ /** {@hide} */
+ public Bitmap appIcon;
+ /** {@hide} */
+ public CharSequence appLabel;
+
+ /** {@hide} */
+ public SessionInfo() {
+ }
+
+ /** {@hide} */
+ public SessionInfo(Parcel source) {
+ sessionId = source.readInt();
+ installerPackageName = source.readString();
+ resolvedBaseCodePath = source.readString();
+ progress = source.readFloat();
+ sealed = source.readInt() != 0;
+ open = source.readInt() != 0;
+
+ mode = source.readInt();
+ sizeBytes = source.readLong();
+ appPackageName = source.readString();
+ appIcon = source.readParcelable(null);
+ appLabel = source.readString();
+ }
+
/**
- * Generic unknown failure. The system will always try to provide a more
- * specific failure reason, but in some rare cases this may be
- * delivered.
+ * Return the ID for this session.
*/
- public static final int FAILURE_UNKNOWN = 0;
+ public int getSessionId() {
+ return sessionId;
+ }
/**
- * One or more of the APKs included in the session was invalid. For
- * example, they might be malformed, corrupt, incorrectly signed,
- * mismatched, etc. The installer may want to try downloading and
- * installing again.
+ * Return the package name of the app that owns this session.
*/
- public static final int FAILURE_INVALID = 1;
+ public @Nullable String getInstallerPackageName() {
+ return installerPackageName;
+ }
/**
- * This install session conflicts (or is inconsistent with) with another
- * package already installed on the device. For example, an existing
- * permission, incompatible certificates, etc. The user may be able to
- * uninstall another app to fix the issue.
+ * Return current overall progress of this session, between 0 and 1.
* <p>
- * The extras bundle may contain {@link #EXTRA_PACKAGE_NAME} with the
- * specific packages identified as the cause of the conflict.
+ * Note that this progress may not directly correspond to the value reported
+ * by {@link PackageInstaller.Session#setProgress(float)}, as the system may
+ * carve out a portion of the overall progress to represent its own internal
+ * installation work.
*/
- public static final int FAILURE_CONFLICT = 2;
+ public float getProgress() {
+ return progress;
+ }
/**
- * This install session failed due to storage issues. For example,
- * the device may be running low on space, or the required external
- * media may be unavailable. The user may be able to help free space
- * or insert the correct media.
+ * Return if this session is currently open.
*/
- public static final int FAILURE_STORAGE = 3;
+ public boolean isOpen() {
+ return open;
+ }
/**
- * This install session is fundamentally incompatible with this
- * device. For example, the package may require a hardware feature
- * that doesn't exist, it may be missing native code for the device
- * ABI, or it requires a newer SDK version, etc. This install would
- * never succeed.
+ * Return the package name this session is working with. May be {@code null}
+ * if unknown.
*/
- public static final int FAILURE_INCOMPATIBLE = 4;
+ public @Nullable String getAppPackageName() {
+ return appPackageName;
+ }
/**
- * This install session failed because it was actively aborted. For
- * example, the user declined requested permissions, or a verifier
- * rejected the session.
- *
- * @see PackageManager#VERIFICATION_REJECT
+ * Return an icon representing the app being installed. May be {@code null}
+ * if unavailable.
*/
- public static final int FAILURE_ABORTED = 5;
+ public @Nullable Bitmap getAppIcon() {
+ return appIcon;
+ }
- public static final String EXTRA_PACKAGE_NAME = "android.content.pm.extra.PACKAGE_NAME";
+ /**
+ * Return a label representing the app being installed. May be {@code null}
+ * if unavailable.
+ */
+ public @Nullable CharSequence getAppLabel() {
+ return appLabel;
+ }
/**
- * User action is required to proceed. You can start the given intent
- * activity to involve the user and continue.
+ * Return an Intent that can be started to view details about this install
+ * session. This may surface actions such as pause, resume, or cancel.
* <p>
- * You may choose to immediately launch the intent if the user is
- * actively using your app. However, you should use a notification to
- * guide the user back into your app if not currently active.
+ * In some cases, a matching Activity may not exist, so ensure you safeguard
+ * against this.
+ *
+ * @see PackageInstaller#ACTION_SESSION_DETAILS
*/
- public abstract void onUserActionRequired(Intent intent);
-
- public abstract void onSuccess();
- public abstract void onFailure(int failureReason, String msg, Bundle extras);
- }
-
- /** {@hide} */
- private static class CommitCallbackDelegate extends PackageInstallObserver {
- private final CommitCallback target;
-
- public CommitCallbackDelegate(CommitCallback target) {
- this.target = target;
+ public @Nullable Intent getDetailsIntent() {
+ final Intent intent = new Intent(PackageInstaller.ACTION_SESSION_DETAILS);
+ intent.putExtra(PackageInstaller.EXTRA_SESSION_ID, sessionId);
+ intent.setPackage(installerPackageName);
+ intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ return intent;
}
@Override
- public void onUserActionRequired(Intent intent) {
- target.onUserActionRequired(intent);
+ public int describeContents() {
+ return 0;
}
@Override
- public void onPackageInstalled(String basePackageName, int returnCode, String msg,
- Bundle extras) {
- if (returnCode == PackageManager.INSTALL_SUCCEEDED) {
- target.onSuccess();
- } else {
- final int failureReason = PackageManager.installStatusToFailureReason(returnCode);
- msg = PackageManager.installStatusToString(returnCode) + ": " + msg;
-
- if (extras != null) {
- extras.putString(CommitCallback.EXTRA_PACKAGE_NAME,
- extras.getString(PackageManager.EXTRA_FAILURE_EXISTING_PACKAGE));
- }
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(sessionId);
+ dest.writeString(installerPackageName);
+ dest.writeString(resolvedBaseCodePath);
+ dest.writeFloat(progress);
+ dest.writeInt(sealed ? 1 : 0);
+ dest.writeInt(open ? 1 : 0);
+
+ dest.writeInt(mode);
+ dest.writeLong(sizeBytes);
+ dest.writeString(appPackageName);
+ dest.writeParcelable(appIcon, flags);
+ dest.writeString(appLabel != null ? appLabel.toString() : null);
+ }
+
+ public static final Parcelable.Creator<SessionInfo>
+ CREATOR = new Parcelable.Creator<SessionInfo>() {
+ @Override
+ public SessionInfo createFromParcel(Parcel p) {
+ return new SessionInfo(p);
+ }
- target.onFailure(failureReason, msg, extras);
- }
- }
+ @Override
+ public SessionInfo[] newArray(int size) {
+ return new SessionInfo[size];
+ }
+ };
}
}
diff --git a/core/java/android/content/pm/PackageInstallerParams.aidl b/core/java/android/content/pm/PackageInstallerParams.aidl
deleted file mode 100644
index b3dde21f0b86..000000000000
--- a/core/java/android/content/pm/PackageInstallerParams.aidl
+++ /dev/null
@@ -1,19 +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.content.pm;
-
-parcelable PackageInstallerParams;
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index b957a1555155..56b71643f5df 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -28,8 +28,6 @@ import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.IntentSender;
-import android.content.pm.PackageInstaller.CommitCallback;
-import android.content.pm.PackageInstaller.UninstallCallback;
import android.content.pm.PackageParser.PackageParserException;
import android.content.res.Resources;
import android.content.res.XmlResourceParser;
@@ -179,9 +177,9 @@ public abstract class PackageManager {
/**
* {@link PackageInfo} flag: return information about
* hardware preferences in
- * {@link PackageInfo#configPreferences PackageInfo.configPreferences} and
- * requested features in {@link PackageInfo#reqFeatures
- * PackageInfo.reqFeatures}.
+ * {@link PackageInfo#configPreferences PackageInfo.configPreferences},
+ * and requested features in {@link PackageInfo#reqFeatures} and
+ * {@link PackageInfo#featureGroups}.
*/
public static final int GET_CONFIGURATIONS = 0x00004000;
@@ -3797,6 +3795,16 @@ public abstract class PackageManager {
public abstract boolean isPackageAvailable(String packageName);
/** {@hide} */
+ public static String installStatusToString(int status, String msg) {
+ final String str = installStatusToString(status);
+ if (msg != null) {
+ return str + ": " + msg;
+ } else {
+ return str;
+ }
+ }
+
+ /** {@hide} */
public static String installStatusToString(int status) {
switch (status) {
case INSTALL_SUCCEEDED: return "INSTALL_SUCCEEDED";
@@ -3845,49 +3853,60 @@ public abstract class PackageManager {
}
/** {@hide} */
- public static int installStatusToFailureReason(int status) {
+ public static int installStatusToPublicStatus(int status) {
switch (status) {
- case INSTALL_FAILED_ALREADY_EXISTS: return CommitCallback.FAILURE_CONFLICT;
- case INSTALL_FAILED_INVALID_APK: return CommitCallback.FAILURE_INVALID;
- case INSTALL_FAILED_INVALID_URI: return CommitCallback.FAILURE_INVALID;
- case INSTALL_FAILED_INSUFFICIENT_STORAGE: return CommitCallback.FAILURE_STORAGE;
- case INSTALL_FAILED_DUPLICATE_PACKAGE: return CommitCallback.FAILURE_CONFLICT;
- case INSTALL_FAILED_NO_SHARED_USER: return CommitCallback.FAILURE_CONFLICT;
- case INSTALL_FAILED_UPDATE_INCOMPATIBLE: return CommitCallback.FAILURE_CONFLICT;
- case INSTALL_FAILED_SHARED_USER_INCOMPATIBLE: return CommitCallback.FAILURE_CONFLICT;
- case INSTALL_FAILED_MISSING_SHARED_LIBRARY: return CommitCallback.FAILURE_INCOMPATIBLE;
- case INSTALL_FAILED_REPLACE_COULDNT_DELETE: return CommitCallback.FAILURE_CONFLICT;
- case INSTALL_FAILED_DEXOPT: return CommitCallback.FAILURE_INVALID;
- case INSTALL_FAILED_OLDER_SDK: return CommitCallback.FAILURE_INCOMPATIBLE;
- case INSTALL_FAILED_CONFLICTING_PROVIDER: return CommitCallback.FAILURE_CONFLICT;
- case INSTALL_FAILED_NEWER_SDK: return CommitCallback.FAILURE_INCOMPATIBLE;
- case INSTALL_FAILED_TEST_ONLY: return CommitCallback.FAILURE_INVALID;
- case INSTALL_FAILED_CPU_ABI_INCOMPATIBLE: return CommitCallback.FAILURE_INCOMPATIBLE;
- case INSTALL_FAILED_MISSING_FEATURE: return CommitCallback.FAILURE_INCOMPATIBLE;
- case INSTALL_FAILED_CONTAINER_ERROR: return CommitCallback.FAILURE_STORAGE;
- case INSTALL_FAILED_INVALID_INSTALL_LOCATION: return CommitCallback.FAILURE_STORAGE;
- case INSTALL_FAILED_MEDIA_UNAVAILABLE: return CommitCallback.FAILURE_STORAGE;
- case INSTALL_FAILED_VERIFICATION_TIMEOUT: return CommitCallback.FAILURE_ABORTED;
- case INSTALL_FAILED_VERIFICATION_FAILURE: return CommitCallback.FAILURE_ABORTED;
- case INSTALL_FAILED_PACKAGE_CHANGED: return CommitCallback.FAILURE_INVALID;
- case INSTALL_FAILED_UID_CHANGED: return CommitCallback.FAILURE_INVALID;
- case INSTALL_FAILED_VERSION_DOWNGRADE: return CommitCallback.FAILURE_INVALID;
- case INSTALL_PARSE_FAILED_NOT_APK: return CommitCallback.FAILURE_INVALID;
- case INSTALL_PARSE_FAILED_BAD_MANIFEST: return CommitCallback.FAILURE_INVALID;
- case INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION: return CommitCallback.FAILURE_INVALID;
- case INSTALL_PARSE_FAILED_NO_CERTIFICATES: return CommitCallback.FAILURE_INVALID;
- case INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES: return CommitCallback.FAILURE_INVALID;
- case INSTALL_PARSE_FAILED_CERTIFICATE_ENCODING: return CommitCallback.FAILURE_INVALID;
- case INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME: return CommitCallback.FAILURE_INVALID;
- case INSTALL_PARSE_FAILED_BAD_SHARED_USER_ID: return CommitCallback.FAILURE_INVALID;
- case INSTALL_PARSE_FAILED_MANIFEST_MALFORMED: return CommitCallback.FAILURE_INVALID;
- case INSTALL_PARSE_FAILED_MANIFEST_EMPTY: return CommitCallback.FAILURE_INVALID;
- case INSTALL_FAILED_INTERNAL_ERROR: return CommitCallback.FAILURE_UNKNOWN;
- case INSTALL_FAILED_USER_RESTRICTED: return CommitCallback.FAILURE_INCOMPATIBLE;
- case INSTALL_FAILED_DUPLICATE_PERMISSION: return CommitCallback.FAILURE_CONFLICT;
- case INSTALL_FAILED_NO_MATCHING_ABIS: return CommitCallback.FAILURE_INCOMPATIBLE;
- case INSTALL_FAILED_ABORTED: return CommitCallback.FAILURE_ABORTED;
- default: return CommitCallback.FAILURE_UNKNOWN;
+ case INSTALL_SUCCEEDED: return PackageInstaller.STATUS_SUCCESS;
+ case INSTALL_FAILED_ALREADY_EXISTS: return PackageInstaller.STATUS_FAILURE_CONFLICT;
+ case INSTALL_FAILED_INVALID_APK: return PackageInstaller.STATUS_FAILURE_INVALID;
+ case INSTALL_FAILED_INVALID_URI: return PackageInstaller.STATUS_FAILURE_INVALID;
+ case INSTALL_FAILED_INSUFFICIENT_STORAGE: return PackageInstaller.STATUS_FAILURE_STORAGE;
+ case INSTALL_FAILED_DUPLICATE_PACKAGE: return PackageInstaller.STATUS_FAILURE_CONFLICT;
+ case INSTALL_FAILED_NO_SHARED_USER: return PackageInstaller.STATUS_FAILURE_CONFLICT;
+ case INSTALL_FAILED_UPDATE_INCOMPATIBLE: return PackageInstaller.STATUS_FAILURE_CONFLICT;
+ case INSTALL_FAILED_SHARED_USER_INCOMPATIBLE: return PackageInstaller.STATUS_FAILURE_CONFLICT;
+ case INSTALL_FAILED_MISSING_SHARED_LIBRARY: return PackageInstaller.STATUS_FAILURE_INCOMPATIBLE;
+ case INSTALL_FAILED_REPLACE_COULDNT_DELETE: return PackageInstaller.STATUS_FAILURE_CONFLICT;
+ case INSTALL_FAILED_DEXOPT: return PackageInstaller.STATUS_FAILURE_INVALID;
+ case INSTALL_FAILED_OLDER_SDK: return PackageInstaller.STATUS_FAILURE_INCOMPATIBLE;
+ case INSTALL_FAILED_CONFLICTING_PROVIDER: return PackageInstaller.STATUS_FAILURE_CONFLICT;
+ case INSTALL_FAILED_NEWER_SDK: return PackageInstaller.STATUS_FAILURE_INCOMPATIBLE;
+ case INSTALL_FAILED_TEST_ONLY: return PackageInstaller.STATUS_FAILURE_INVALID;
+ case INSTALL_FAILED_CPU_ABI_INCOMPATIBLE: return PackageInstaller.STATUS_FAILURE_INCOMPATIBLE;
+ case INSTALL_FAILED_MISSING_FEATURE: return PackageInstaller.STATUS_FAILURE_INCOMPATIBLE;
+ case INSTALL_FAILED_CONTAINER_ERROR: return PackageInstaller.STATUS_FAILURE_STORAGE;
+ case INSTALL_FAILED_INVALID_INSTALL_LOCATION: return PackageInstaller.STATUS_FAILURE_STORAGE;
+ case INSTALL_FAILED_MEDIA_UNAVAILABLE: return PackageInstaller.STATUS_FAILURE_STORAGE;
+ case INSTALL_FAILED_VERIFICATION_TIMEOUT: return PackageInstaller.STATUS_FAILURE_ABORTED;
+ case INSTALL_FAILED_VERIFICATION_FAILURE: return PackageInstaller.STATUS_FAILURE_ABORTED;
+ case INSTALL_FAILED_PACKAGE_CHANGED: return PackageInstaller.STATUS_FAILURE_INVALID;
+ case INSTALL_FAILED_UID_CHANGED: return PackageInstaller.STATUS_FAILURE_INVALID;
+ case INSTALL_FAILED_VERSION_DOWNGRADE: return PackageInstaller.STATUS_FAILURE_INVALID;
+ case INSTALL_PARSE_FAILED_NOT_APK: return PackageInstaller.STATUS_FAILURE_INVALID;
+ case INSTALL_PARSE_FAILED_BAD_MANIFEST: return PackageInstaller.STATUS_FAILURE_INVALID;
+ case INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION: return PackageInstaller.STATUS_FAILURE_INVALID;
+ case INSTALL_PARSE_FAILED_NO_CERTIFICATES: return PackageInstaller.STATUS_FAILURE_INVALID;
+ case INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES: return PackageInstaller.STATUS_FAILURE_INVALID;
+ case INSTALL_PARSE_FAILED_CERTIFICATE_ENCODING: return PackageInstaller.STATUS_FAILURE_INVALID;
+ case INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME: return PackageInstaller.STATUS_FAILURE_INVALID;
+ case INSTALL_PARSE_FAILED_BAD_SHARED_USER_ID: return PackageInstaller.STATUS_FAILURE_INVALID;
+ case INSTALL_PARSE_FAILED_MANIFEST_MALFORMED: return PackageInstaller.STATUS_FAILURE_INVALID;
+ case INSTALL_PARSE_FAILED_MANIFEST_EMPTY: return PackageInstaller.STATUS_FAILURE_INVALID;
+ case INSTALL_FAILED_INTERNAL_ERROR: return PackageInstaller.STATUS_FAILURE;
+ case INSTALL_FAILED_USER_RESTRICTED: return PackageInstaller.STATUS_FAILURE_INCOMPATIBLE;
+ case INSTALL_FAILED_DUPLICATE_PERMISSION: return PackageInstaller.STATUS_FAILURE_CONFLICT;
+ case INSTALL_FAILED_NO_MATCHING_ABIS: return PackageInstaller.STATUS_FAILURE_INCOMPATIBLE;
+ case INSTALL_FAILED_ABORTED: return PackageInstaller.STATUS_FAILURE_ABORTED;
+ default: return PackageInstaller.STATUS_FAILURE;
+ }
+ }
+
+ /** {@hide} */
+ public static String deleteStatusToString(int status, String msg) {
+ final String str = deleteStatusToString(status);
+ if (msg != null) {
+ return str + ": " + msg;
+ } else {
+ return str;
}
}
@@ -3905,14 +3924,15 @@ public abstract class PackageManager {
}
/** {@hide} */
- public static int deleteStatusToFailureReason(int status) {
+ public static int deleteStatusToPublicStatus(int status) {
switch (status) {
- case DELETE_FAILED_INTERNAL_ERROR: return UninstallCallback.FAILURE_UNKNOWN;
- case DELETE_FAILED_DEVICE_POLICY_MANAGER: return UninstallCallback.FAILURE_BLOCKED;
- case DELETE_FAILED_USER_RESTRICTED: return UninstallCallback.FAILURE_BLOCKED;
- case DELETE_FAILED_OWNER_BLOCKED: return UninstallCallback.FAILURE_BLOCKED;
- case DELETE_FAILED_ABORTED: return UninstallCallback.FAILURE_ABORTED;
- default: return UninstallCallback.FAILURE_UNKNOWN;
+ case DELETE_SUCCEEDED: return PackageInstaller.STATUS_SUCCESS;
+ case DELETE_FAILED_INTERNAL_ERROR: return PackageInstaller.STATUS_FAILURE;
+ case DELETE_FAILED_DEVICE_POLICY_MANAGER: return PackageInstaller.STATUS_FAILURE_BLOCKED;
+ case DELETE_FAILED_USER_RESTRICTED: return PackageInstaller.STATUS_FAILURE_BLOCKED;
+ case DELETE_FAILED_OWNER_BLOCKED: return PackageInstaller.STATUS_FAILURE_BLOCKED;
+ case DELETE_FAILED_ABORTED: return PackageInstaller.STATUS_FAILURE_ABORTED;
+ default: return PackageInstaller.STATUS_FAILURE;
}
}
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 44bf35dc2e10..cddefb509de1 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -434,6 +434,11 @@ public class PackageParser {
pi.reqFeatures = new FeatureInfo[N];
p.reqFeatures.toArray(pi.reqFeatures);
}
+ N = p.featureGroups != null ? p.featureGroups.size() : 0;
+ if (N > 0) {
+ pi.featureGroups = new FeatureGroupInfo[N];
+ p.featureGroups.toArray(pi.featureGroups);
+ }
}
if ((flags&PackageManager.GET_ACTIVITIES) != 0) {
int N = p.activities.size();
@@ -1502,24 +1507,7 @@ public class PackageParser {
XmlUtils.skipCurrentTag(parser);
} else if (tagName.equals("uses-feature")) {
- FeatureInfo fi = new FeatureInfo();
- sa = res.obtainAttributes(attrs,
- com.android.internal.R.styleable.AndroidManifestUsesFeature);
- // Note: don't allow this value to be a reference to a resource
- // that may change.
- fi.name = sa.getNonResourceString(
- com.android.internal.R.styleable.AndroidManifestUsesFeature_name);
- if (fi.name == null) {
- fi.reqGlEsVersion = sa.getInt(
- com.android.internal.R.styleable.AndroidManifestUsesFeature_glEsVersion,
- FeatureInfo.GL_ES_VERSION_UNDEFINED);
- }
- if (sa.getBoolean(
- com.android.internal.R.styleable.AndroidManifestUsesFeature_required,
- true)) {
- fi.flags |= FeatureInfo.FLAG_REQUIRED;
- }
- sa.recycle();
+ FeatureInfo fi = parseUsesFeature(res, attrs);
pkg.reqFeatures = ArrayUtils.add(pkg.reqFeatures, fi);
if (fi.name == null) {
@@ -1531,9 +1519,35 @@ public class PackageParser {
XmlUtils.skipCurrentTag(parser);
} else if (tagName.equals("feature-group")) {
- // Skip this for now until we know what to do with it.
+ FeatureGroupInfo group = new FeatureGroupInfo();
+ ArrayList<FeatureInfo> features = null;
+ final int innerDepth = parser.getDepth();
+ while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+ && (type != XmlPullParser.END_TAG || parser.getDepth() > innerDepth)) {
+ if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
+ continue;
+ }
- XmlUtils.skipCurrentTag(parser);
+ final String innerTagName = parser.getName();
+ if (innerTagName.equals("uses-feature")) {
+ FeatureInfo featureInfo = parseUsesFeature(res, attrs);
+ // FeatureGroups are stricter and mandate that
+ // any <uses-feature> declared are mandatory.
+ featureInfo.flags |= FeatureInfo.FLAG_REQUIRED;
+ features = ArrayUtils.add(features, featureInfo);
+ } else {
+ Slog.w(TAG, "Unknown element under <feature-group>: " + innerTagName +
+ " at " + mArchiveSourcePath + " " +
+ parser.getPositionDescription());
+ }
+ XmlUtils.skipCurrentTag(parser);
+ }
+
+ if (features != null) {
+ group.features = new FeatureInfo[features.size()];
+ group.features = features.toArray(group.features);
+ }
+ pkg.featureGroups = ArrayUtils.add(pkg.featureGroups, group);
} else if (tagName.equals("uses-sdk")) {
if (SDK_VERSION > 0) {
@@ -1851,6 +1865,28 @@ public class PackageParser {
return pkg;
}
+ private FeatureInfo parseUsesFeature(Resources res, AttributeSet attrs)
+ throws XmlPullParserException, IOException {
+ FeatureInfo fi = new FeatureInfo();
+ TypedArray sa = res.obtainAttributes(attrs,
+ com.android.internal.R.styleable.AndroidManifestUsesFeature);
+ // Note: don't allow this value to be a reference to a resource
+ // that may change.
+ fi.name = sa.getNonResourceString(
+ com.android.internal.R.styleable.AndroidManifestUsesFeature_name);
+ if (fi.name == null) {
+ fi.reqGlEsVersion = sa.getInt(
+ com.android.internal.R.styleable.AndroidManifestUsesFeature_glEsVersion,
+ FeatureInfo.GL_ES_VERSION_UNDEFINED);
+ }
+ if (sa.getBoolean(
+ com.android.internal.R.styleable.AndroidManifestUsesFeature_required, true)) {
+ fi.flags |= FeatureInfo.FLAG_REQUIRED;
+ }
+ sa.recycle();
+ return fi;
+ }
+
private boolean parseUsesPermission(Package pkg, Resources res, XmlResourceParser parser,
AttributeSet attrs, String[] outError)
throws XmlPullParserException, IOException {
@@ -4225,6 +4261,9 @@ public class PackageParser {
// Applications requested features
public ArrayList<FeatureInfo> reqFeatures = null;
+ // Applications requested feature groups
+ public ArrayList<FeatureGroupInfo> featureGroups = null;
+
public int installLocation;
/* An app that's required for all users and cannot be uninstalled for a user */
diff --git a/core/java/android/content/pm/VerificationParams.java b/core/java/android/content/pm/VerificationParams.java
index bf1f77f6826e..e5119b621ee5 100644
--- a/core/java/android/content/pm/VerificationParams.java
+++ b/core/java/android/content/pm/VerificationParams.java
@@ -24,7 +24,7 @@ import android.os.Parcelable;
/**
* Represents verification parameters used to verify packages to be installed.
*
- * @deprecated callers should migrate to {@link PackageInstallerParams}.
+ * @deprecated callers should migrate to {@link PackageInstaller}.
* @hide
*/
@Deprecated
diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java
index 52d1c7910b33..fff21aa759bb 100644
--- a/core/java/android/content/res/Resources.java
+++ b/core/java/android/content/res/Resources.java
@@ -715,7 +715,13 @@ public class Resources {
* @see #getDrawable(int, Theme)
*/
public Drawable getDrawable(int id) throws NotFoundException {
- return getDrawable(id, null);
+ final Drawable d = getDrawable(id, null);
+ if (d.canApplyTheme()) {
+ Log.w(TAG, "Drawable " + getResourceName(id) + " has unresolved theme "
+ + "attributes! Consider using Resources.getDrawable(int, Theme) or "
+ + "Context.getDrawable(int).", new RuntimeException());
+ }
+ return d;
}
/**
diff --git a/core/java/android/hardware/camera2/legacy/LegacyCameraDevice.java b/core/java/android/hardware/camera2/legacy/LegacyCameraDevice.java
index cbf4a3d1bb06..1cf7797044da 100644
--- a/core/java/android/hardware/camera2/legacy/LegacyCameraDevice.java
+++ b/core/java/android/hardware/camera2/legacy/LegacyCameraDevice.java
@@ -510,4 +510,6 @@ public class LegacyCameraDevice implements AutoCloseable {
/*out*/int[/*2*/] dimens);
private static native int nativeSetNextTimestamp(Surface surface, long timestamp);
+
+ static native int nativeGetJpegFooterSize();
}
diff --git a/core/java/android/hardware/camera2/legacy/LegacyMetadataMapper.java b/core/java/android/hardware/camera2/legacy/LegacyMetadataMapper.java
index 0337c96fc536..fbe26e52dffd 100644
--- a/core/java/android/hardware/camera2/legacy/LegacyMetadataMapper.java
+++ b/core/java/android/hardware/camera2/legacy/LegacyMetadataMapper.java
@@ -33,6 +33,7 @@ import android.hardware.camera2.params.StreamConfigurationDuration;
import android.hardware.camera2.utils.ArrayUtils;
import android.hardware.camera2.utils.ListUtils;
import android.hardware.camera2.utils.ParamsUtils;
+import android.hardware.camera2.utils.SizeAreaComparator;
import android.util.Log;
import android.util.Range;
import android.util.Size;
@@ -40,6 +41,8 @@ import android.util.SizeF;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collections;
+import java.util.Comparator;
import java.util.List;
import static com.android.internal.util.Preconditions.*;
@@ -187,8 +190,10 @@ public class LegacyMetadataMapper {
* flash.*
*/
mapFlash(m, p);
-
- // TODO: map other fields
+ /*
+ * jpeg.*
+ */
+ mapJpeg(m, p);
/*
* scaler.*
@@ -595,6 +600,16 @@ public class LegacyMetadataMapper {
m.set(FLASH_INFO_AVAILABLE, flashAvailable);
}
+ private static void mapJpeg(CameraMetadataNative m, Camera.Parameters p) {
+ List<Camera.Size> thumbnailSizes = p.getSupportedJpegThumbnailSizes();
+
+ if (thumbnailSizes != null) {
+ Size[] sizes = convertSizeListToArray(thumbnailSizes);
+ Arrays.sort(sizes, new SizeAreaComparator());
+ m.set(JPEG_AVAILABLE_THUMBNAIL_SIZES, sizes);
+ }
+ }
+
private static void mapRequest(CameraMetadataNative m, Parameters p) {
/*
* request.availableCapabilities
diff --git a/core/java/android/hardware/camera2/legacy/LegacyRequestMapper.java b/core/java/android/hardware/camera2/legacy/LegacyRequestMapper.java
index 35646fef504c..4c4ad0d207b2 100644
--- a/core/java/android/hardware/camera2/legacy/LegacyRequestMapper.java
+++ b/core/java/android/hardware/camera2/legacy/LegacyRequestMapper.java
@@ -24,6 +24,7 @@ import android.hardware.camera2.CaptureRequest;
import android.hardware.camera2.params.MeteringRectangle;
import android.hardware.camera2.utils.ListUtils;
import android.hardware.camera2.utils.ParamsUtils;
+import android.location.Location;
import android.util.Log;
import android.util.Range;
import android.util.Size;
@@ -44,6 +45,8 @@ public class LegacyRequestMapper {
private static final String TAG = "LegacyRequestMapper";
private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE);
+ private static final byte DEFAULT_JPEG_QUALITY = 85;
+
/**
* Set the legacy parameters using the {@link LegacyRequest legacy request}.
*
@@ -350,6 +353,70 @@ public class LegacyRequestMapper {
+ testPatternMode + "; only OFF is supported");
}
}
+
+ /*
+ * jpeg.*
+ */
+
+ // jpeg.gpsLocation
+ {
+ Location location = request.get(JPEG_GPS_LOCATION);
+ if (location != null) {
+ if (checkForCompleteGpsData(location)) {
+ params.setGpsAltitude(location.getAltitude());
+ params.setGpsLatitude(location.getLatitude());
+ params.setGpsLongitude(location.getLongitude());
+ params.setGpsProcessingMethod(location.getProvider().toUpperCase());
+ params.setGpsTimestamp(location.getTime());
+ } else {
+ Log.w(TAG, "Incomplete GPS parameters provided in location " + location);
+ }
+ } else {
+ params.removeGpsData();
+ }
+ }
+
+ // jpeg.orientation
+ {
+ int orientation = characteristics.get(CameraCharacteristics.SENSOR_ORIENTATION);
+ params.setRotation(ParamsUtils.getOrDefault(request, JPEG_ORIENTATION, orientation));
+ }
+
+ // jpeg.quality
+ {
+ params.setJpegQuality(0xFF & ParamsUtils.getOrDefault(request, JPEG_QUALITY,
+ DEFAULT_JPEG_QUALITY));
+ }
+
+ // jpeg.thumbnailQuality
+ {
+ params.setJpegQuality(0xFF & ParamsUtils.getOrDefault(request, JPEG_THUMBNAIL_QUALITY,
+ DEFAULT_JPEG_QUALITY));
+ }
+
+ // jpeg.thumbnailSize
+ {
+ List<Camera.Size> sizes = params.getSupportedJpegThumbnailSizes();
+
+ if (sizes != null && sizes.size() > 0) {
+ Size s = request.get(JPEG_THUMBNAIL_SIZE);
+ boolean invalidSize = (s == null) ? false : !ParameterUtils.containsSize(sizes,
+ s.getWidth(), s.getHeight());
+ if (invalidSize) {
+ Log.w(TAG, "Invalid JPEG thumbnail size set " + s + ", skipping thumbnail...");
+ }
+ if (s == null || invalidSize) {
+ // (0,0) = "no thumbnail" in Camera API 1
+ params.setJpegThumbnailSize(/*width*/0, /*height*/0);
+ } else {
+ params.setJpegThumbnailSize(s.getWidth(), s.getHeight());
+ }
+ }
+ }
+ }
+
+ private static boolean checkForCompleteGpsData(Location location) {
+ return location != null && location.getProvider() != null && location.getTime() != 0;
}
static int filterSupportedCaptureIntent(int captureIntent) {
diff --git a/core/java/android/hardware/camera2/legacy/LegacyResultMapper.java b/core/java/android/hardware/camera2/legacy/LegacyResultMapper.java
index a2f9b4caabef..090a8221a195 100644
--- a/core/java/android/hardware/camera2/legacy/LegacyResultMapper.java
+++ b/core/java/android/hardware/camera2/legacy/LegacyResultMapper.java
@@ -28,6 +28,7 @@ import android.hardware.camera2.legacy.ParameterUtils.ZoomData;
import android.hardware.camera2.params.MeteringRectangle;
import android.hardware.camera2.utils.ListUtils;
import android.hardware.camera2.utils.ParamsUtils;
+import android.location.Location;
import android.util.Log;
import android.util.Size;
@@ -250,6 +251,29 @@ public class LegacyResultMapper {
result.set(SENSOR_TEST_PATTERN_MODE, SENSOR_TEST_PATTERN_MODE_OFF);
}
+ /*
+ * jpeg
+ */
+ // jpeg.gpsLocation
+ result.set(JPEG_GPS_LOCATION, request.get(CaptureRequest.JPEG_GPS_LOCATION));
+
+ // jpeg.orientation
+ result.set(JPEG_ORIENTATION, request.get(CaptureRequest.JPEG_ORIENTATION));
+
+ // jpeg.quality
+ result.set(JPEG_QUALITY, (byte) params.getJpegQuality());
+
+ // jpeg.thumbnailQuality
+ result.set(JPEG_THUMBNAIL_QUALITY, (byte) params.getJpegThumbnailQuality());
+
+ // jpeg.thumbnailSize
+ Camera.Size s = params.getJpegThumbnailSize();
+ if (s != null) {
+ result.set(JPEG_THUMBNAIL_SIZE, ParameterUtils.convertSize(s));
+ } else {
+ Log.w(TAG, "Null thumbnail size received from parameters.");
+ }
+
// TODO: Remaining result metadata tags conversions.
return result;
}
diff --git a/core/java/android/hardware/camera2/legacy/ParameterUtils.java b/core/java/android/hardware/camera2/legacy/ParameterUtils.java
index 385f8440afb2..98adcea8cb97 100644
--- a/core/java/android/hardware/camera2/legacy/ParameterUtils.java
+++ b/core/java/android/hardware/camera2/legacy/ParameterUtils.java
@@ -253,6 +253,33 @@ public class ParameterUtils {
}
/**
+ * Convert a camera API1 list of sizes into an array of sizes
+ */
+ public static Size[] convertSizeListToArray(List<Camera.Size> sizeList) {
+ checkNotNull(sizeList, "sizeList must not be null");
+
+ Size[] array = new Size[sizeList.size()];
+ int ctr = 0;
+ for (Camera.Size s : sizeList) {
+ array[ctr++] = new Size(s.width, s.height);
+ }
+ return array;
+ }
+
+ /**
+ * Check if the camera API1 list of sizes contains a size with the given dimens.
+ */
+ public static boolean containsSize(List<Camera.Size> sizeList, int width, int height) {
+ checkNotNull(sizeList, "sizeList must not be null");
+ for (Camera.Size s : sizeList) {
+ if (s.height == height && s.width == width) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
* Returns the largest supported picture size, as compared by its area.
*/
public static Size getLargestSupportedJpegSizeByArea(Camera.Parameters params) {
diff --git a/core/java/android/hardware/camera2/legacy/RequestThreadManager.java b/core/java/android/hardware/camera2/legacy/RequestThreadManager.java
index 5c66753191c7..eb8debba0c9e 100644
--- a/core/java/android/hardware/camera2/legacy/RequestThreadManager.java
+++ b/core/java/android/hardware/camera2/legacy/RequestThreadManager.java
@@ -190,7 +190,8 @@ public class RequestThreadManager {
try {
if (RequestHolder.jpegType(s)) {
Log.i(TAG, "Producing jpeg buffer...");
- LegacyCameraDevice.setSurfaceDimens(s, data.length, /*height*/1);
+ LegacyCameraDevice.setSurfaceDimens(s, data.length +
+ LegacyCameraDevice.nativeGetJpegFooterSize(), /*height*/1);
LegacyCameraDevice.setNextTimestamp(s, timestamp);
LegacyCameraDevice.produceFrame(s, data, data.length, /*height*/1,
CameraMetadataNative.NATIVE_JPEG_FORMAT);
@@ -665,10 +666,6 @@ public class RequestThreadManager {
}
mReceivedJpeg.close();
doJpegCapturePrepare(holder);
- if (!mReceivedJpeg.block(JPEG_FRAME_TIMEOUT)) {
- // TODO: report error to CameraDevice
- Log.e(TAG, "Hit timeout for jpeg callback!");
- }
}
/*
diff --git a/core/java/android/hardware/camera2/legacy/SurfaceTextureRenderer.java b/core/java/android/hardware/camera2/legacy/SurfaceTextureRenderer.java
index 3f24b2c5f6f8..b1b0f9b485f3 100644
--- a/core/java/android/hardware/camera2/legacy/SurfaceTextureRenderer.java
+++ b/core/java/android/hardware/camera2/legacy/SurfaceTextureRenderer.java
@@ -16,6 +16,7 @@
package android.hardware.camera2.legacy;
import android.graphics.ImageFormat;
+import android.graphics.RectF;
import android.graphics.SurfaceTexture;
import android.os.Environment;
import android.opengl.EGL14;
@@ -194,6 +195,9 @@ public class SurfaceTextureRenderer {
checkGlError("onDrawFrame start");
st.getTransformMatrix(mSTMatrix);
+ Matrix.setIdentityM(mMVPMatrix, /*smOffset*/0);
+
+ // Find intermediate buffer dimensions
Size dimens;
try {
dimens = LegacyCameraDevice.getTextureSize(st);
@@ -201,9 +205,6 @@ public class SurfaceTextureRenderer {
// Should never hit this.
throw new IllegalStateException("Surface abandoned, skipping drawFrame...", e);
}
-
- Matrix.setIdentityM(mMVPMatrix, /*smOffset*/0);
-
float texWidth = dimens.getWidth();
float texHeight = dimens.getHeight();
@@ -211,32 +212,30 @@ public class SurfaceTextureRenderer {
throw new IllegalStateException("Illegal intermediate texture with dimension of 0");
}
- // Find largest scaling factor from the intermediate texture dimension to the
- // output surface dimension. Scaling the intermediate texture by this allows
- // us to letterbox/pillerbox the output surface into the intermediate texture.
- float widthRatio = width / texWidth;
- float heightRatio = height / texHeight;
- float actual = (widthRatio < heightRatio) ? heightRatio : widthRatio;
+ // Letterbox or pillerbox output dimensions into intermediate dimensions.
+ RectF intermediate = new RectF(/*left*/0, /*top*/0, /*right*/texWidth, /*bottom*/texHeight);
+ RectF output = new RectF(/*left*/0, /*top*/0, /*right*/width, /*bottom*/height);
+ android.graphics.Matrix boxingXform = new android.graphics.Matrix();
+ boxingXform.setRectToRect(output, intermediate, android.graphics.Matrix.ScaleToFit.CENTER);
+ boxingXform.mapRect(output);
- if (DEBUG) {
- Log.d(TAG, "Scaling factor " + actual + " used for " + width + "x" + height +
- " surface, intermediate buffer size is " + texWidth + "x" + texHeight);
- }
+ // Find scaling factor from pillerboxed/letterboxed output dimensions to intermediate
+ // buffer dimensions.
+ float scaleX = intermediate.width() / output.width();
+ float scaleY = intermediate.height() / output.height();
- // Set the viewport height and width to be the scaled intermediate texture dimensions.
- int viewportW = (int) (actual * texWidth);
- int viewportH = (int) (actual * texHeight);
-
- // Set the offset of the viewport so that the output surface is centered in the viewport.
- float dx = (width - viewportW) / 2f;
- float dy = (height - viewportH) / 2f;
+ // Scale opposite dimension in clip coordinates so output is letterboxed/pillerboxed into
+ // the intermediate dimensions (rather than vice-versa).
+ Matrix.scaleM(mMVPMatrix, /*offset*/0, /*x*/scaleY, /*y*/scaleX, /*z*/1);
if (DEBUG) {
- Log.d(TAG, "Translation " + dx + "," + dy + " used for " + width + "x" + height +
- " surface");
+ Log.d(TAG, "Scaling factors (S_x = " + scaleX + ",S_y = " + scaleY + ") used for " +
+ width + "x" + height + " surface, intermediate buffer size is " + texWidth +
+ "x" + texHeight);
}
- GLES20.glViewport((int) dx, (int) dy, viewportW, viewportH);
+ // Set viewport to be output buffer dimensions
+ GLES20.glViewport(0, 0, width, height);
if (DEBUG) {
GLES20.glClearColor(1.0f, 0.0f, 0.0f, 1.0f);
@@ -251,7 +250,7 @@ public class SurfaceTextureRenderer {
mTriangleVertices.position(TRIANGLE_VERTICES_DATA_POS_OFFSET);
GLES20.glVertexAttribPointer(maPositionHandle, VERTEX_POS_SIZE, GLES20.GL_FLOAT,
- /*normalized*/ false,TRIANGLE_VERTICES_DATA_STRIDE_BYTES, mTriangleVertices);
+ /*normalized*/ false, TRIANGLE_VERTICES_DATA_STRIDE_BYTES, mTriangleVertices);
checkGlError("glVertexAttribPointer maPosition");
GLES20.glEnableVertexAttribArray(maPositionHandle);
checkGlError("glEnableVertexAttribArray maPositionHandle");
@@ -654,6 +653,8 @@ public class SurfaceTextureRenderer {
if (LegacyCameraDevice.containsSurfaceId(holder.surface, targetSurfaceIds)) {
makeCurrent(holder.eglSurface);
try {
+ LegacyCameraDevice.setSurfaceDimens(holder.surface, holder.width,
+ holder.height);
LegacyCameraDevice.setNextTimestamp(holder.surface, captureHolder.second);
drawFrame(mSurfaceTexture, holder.width, holder.height);
swapBuffers(holder.eglSurface);
diff --git a/core/java/android/net/LinkProperties.java b/core/java/android/net/LinkProperties.java
index 6160bc2ad942..dcb28922ac78 100644
--- a/core/java/android/net/LinkProperties.java
+++ b/core/java/android/net/LinkProperties.java
@@ -56,6 +56,10 @@ public final class LinkProperties implements Parcelable {
private ProxyInfo mHttpProxy;
private int mMtu;
+ private static final int MIN_MTU = 68;
+ private static final int MIN_MTU_V6 = 1280;
+ private static final int MAX_MTU = 10000;
+
// Stores the properties of links that are "stacked" above this link.
// Indexed by interface name to allow modification and to prevent duplicates being added.
private Hashtable<String, LinkProperties> mStackedLinks =
@@ -996,4 +1000,17 @@ public final class LinkProperties implements Parcelable {
return new LinkProperties[size];
}
};
+
+ /**
+ * Check the valid MTU range based on IPv4 or IPv6.
+ * @hide
+ */
+ public static boolean isValidMtu(int mtu, boolean ipv6) {
+ if (ipv6) {
+ if ((mtu >= MIN_MTU_V6 && mtu <= MAX_MTU)) return true;
+ } else {
+ if ((mtu >= MIN_MTU && mtu <= MAX_MTU)) return true;
+ }
+ return false;
+ }
}
diff --git a/core/java/android/nfc/INfcAdapter.aidl b/core/java/android/nfc/INfcAdapter.aidl
index ee4d45e2c9f7..5815fa69973a 100644
--- a/core/java/android/nfc/INfcAdapter.aidl
+++ b/core/java/android/nfc/INfcAdapter.aidl
@@ -59,5 +59,5 @@ interface INfcAdapter
void registerLockscreenDispatch(INfcLockscreenDispatch lockscreenDispatch, in int[] techList);
void addNfcUnlockHandler(INfcUnlockHandler unlockHandler, in int[] techList);
- void removeNfcUnlockHandler(IBinder b);
+ void removeNfcUnlockHandler(INfcUnlockHandler unlockHandler);
}
diff --git a/core/java/android/nfc/NfcAdapter.java b/core/java/android/nfc/NfcAdapter.java
index dde2cf1abe5b..6bd5a3207a2f 100644
--- a/core/java/android/nfc/NfcAdapter.java
+++ b/core/java/android/nfc/NfcAdapter.java
@@ -311,7 +311,7 @@ public final class NfcAdapter {
final NfcActivityManager mNfcActivityManager;
final Context mContext;
- final HashMap<NfcUnlockHandler, IBinder> mNfcUnlockHandlers;
+ final HashMap<NfcUnlockHandler, INfcUnlockHandler> mNfcUnlockHandlers;
final Object mLock;
/**
@@ -542,7 +542,7 @@ public final class NfcAdapter {
NfcAdapter(Context context) {
mContext = context;
mNfcActivityManager = new NfcActivityManager(this);
- mNfcUnlockHandlers = new HashMap<NfcUnlockHandler, IBinder>();
+ mNfcUnlockHandlers = new HashMap<NfcUnlockHandler, INfcUnlockHandler>();
mLock = new Object();
}
@@ -1498,27 +1498,37 @@ public final class NfcAdapter {
* <p /> The parameter {@code tagTechnologies} determines which Tag technologies will be polled for
* at the lockscreen. Polling for less tag technologies reduces latency, and so it is
* strongly recommended to only provide the Tag technologies that the handler is expected to
- * receive.
+ * receive. There must be at least one tag technology provided, otherwise the unlock handler
+ * is ignored.
*
* @hide
*/
@SystemApi
public boolean addNfcUnlockHandler(final NfcUnlockHandler unlockHandler,
String[] tagTechnologies) {
- try {
- INfcUnlockHandler.Stub iHandler = new INfcUnlockHandler.Stub() {
- @Override
- public boolean onUnlockAttempted(Tag tag) throws RemoteException {
- return unlockHandler.onUnlockAttempted(tag);
- }
- };
+ // If there are no tag technologies, don't bother adding unlock handler
+ if (tagTechnologies.length == 0) {
+ return false;
+ }
+ try {
synchronized (mLock) {
if (mNfcUnlockHandlers.containsKey(unlockHandler)) {
- return true;
+ // update the tag technologies
+ sService.removeNfcUnlockHandler(mNfcUnlockHandlers.get(unlockHandler));
+ mNfcUnlockHandlers.remove(unlockHandler);
}
- sService.addNfcUnlockHandler(iHandler, Tag.getTechCodesFromStrings(tagTechnologies));
- mNfcUnlockHandlers.put(unlockHandler, iHandler.asBinder());
+
+ INfcUnlockHandler.Stub iHandler = new INfcUnlockHandler.Stub() {
+ @Override
+ public boolean onUnlockAttempted(Tag tag) throws RemoteException {
+ return unlockHandler.onUnlockAttempted(tag);
+ }
+ };
+
+ sService.addNfcUnlockHandler(iHandler,
+ Tag.getTechCodesFromStrings(tagTechnologies));
+ mNfcUnlockHandlers.put(unlockHandler, iHandler);
}
} catch (RemoteException e) {
attemptDeadServiceRecovery(e);
@@ -1542,8 +1552,7 @@ public final class NfcAdapter {
try {
synchronized (mLock) {
if (mNfcUnlockHandlers.containsKey(unlockHandler)) {
- sService.removeNfcUnlockHandler(mNfcUnlockHandlers.get(unlockHandler));
- mNfcUnlockHandlers.remove(unlockHandler);
+ sService.removeNfcUnlockHandler(mNfcUnlockHandlers.remove(unlockHandler));
}
return true;
diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java
index f381fdfc4c62..75f8279c6c12 100644
--- a/core/java/android/os/PowerManager.java
+++ b/core/java/android/os/PowerManager.java
@@ -773,6 +773,7 @@ public final class PowerManager {
private boolean mHeld;
private WorkSource mWorkSource;
private String mHistoryTag;
+ private final String mTraceName;
private final Runnable mReleaser = new Runnable() {
public void run() {
@@ -785,6 +786,7 @@ public final class PowerManager {
mTag = tag;
mPackageName = packageName;
mToken = new Binder();
+ mTraceName = "WakeLock (" + mTag + ")";
}
@Override
@@ -792,6 +794,7 @@ public final class PowerManager {
synchronized (mToken) {
if (mHeld) {
Log.wtf(TAG, "WakeLock finalized while still held: " + mTag);
+ Trace.asyncTraceEnd(Trace.TRACE_TAG_POWER, mTraceName, 0);
try {
mService.releaseWakeLock(mToken, 0);
} catch (RemoteException e) {
@@ -858,6 +861,7 @@ public final class PowerManager {
// should immediately acquire the wake lock once again despite never having
// been explicitly released by the keyguard.
mHandler.removeCallbacks(mReleaser);
+ Trace.asyncTraceBegin(Trace.TRACE_TAG_POWER, mTraceName, 0);
try {
mService.acquireWakeLock(mToken, mFlags, mTag, mPackageName, mWorkSource,
mHistoryTag);
@@ -897,6 +901,7 @@ public final class PowerManager {
if (!mRefCounted || --mCount == 0) {
mHandler.removeCallbacks(mReleaser);
if (mHeld) {
+ Trace.asyncTraceEnd(Trace.TRACE_TAG_POWER, mTraceName, 0);
try {
mService.releaseWakeLock(mToken, flags);
} catch (RemoteException e) {
diff --git a/core/java/android/os/Trace.java b/core/java/android/os/Trace.java
index 474192fd0c90..31b58490ba24 100644
--- a/core/java/android/os/Trace.java
+++ b/core/java/android/os/Trace.java
@@ -36,6 +36,7 @@ public final class Trace {
private static final String TAG = "Trace";
// These tags must be kept in sync with system/core/include/cutils/trace.h.
+ // They should also be added to frameworks/native/cmds/atrace/atrace.cpp.
/** @hide */
public static final long TRACE_TAG_NEVER = 0;
/** @hide */
@@ -72,6 +73,8 @@ public final class Trace {
public static final long TRACE_TAG_RS = 1L << 15;
/** @hide */
public static final long TRACE_TAG_BIONIC = 1L << 16;
+ /** @hide */
+ public static final long TRACE_TAG_POWER = 1L << 17;
private static final long TRACE_TAG_NOT_READY = 1L << 63;
private static final int MAX_SECTION_NAME_LEN = 127;
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index f9e7b786824f..9d1a7bc4f0ac 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -499,7 +499,12 @@ public class UserManager {
* Sets all the user-wide restrictions for this user.
* Requires the MANAGE_USERS permission.
* @param restrictions the Bundle containing all the restrictions.
+ * @deprecated use {@link android.app.admin.DevicePolicyManager#addUserRestriction(
+ * android.content.ComponentName, String)} or
+ * {@link android.app.admin.DevicePolicyManager#clearUserRestriction(
+ * android.content.ComponentName, String)} instead.
*/
+ @Deprecated
public void setUserRestrictions(Bundle restrictions) {
setUserRestrictions(restrictions, Process.myUserHandle());
}
@@ -509,7 +514,12 @@ public class UserManager {
* Requires the MANAGE_USERS permission.
* @param restrictions the Bundle containing all the restrictions.
* @param userHandle the UserHandle of the user for whom to set the restrictions.
+ * @deprecated use {@link android.app.admin.DevicePolicyManager#addUserRestriction(
+ * android.content.ComponentName, String)} or
+ * {@link android.app.admin.DevicePolicyManager#clearUserRestriction(
+ * android.content.ComponentName, String)} instead.
*/
+ @Deprecated
public void setUserRestrictions(Bundle restrictions, UserHandle userHandle) {
try {
mService.setUserRestrictions(restrictions, userHandle.getIdentifier());
@@ -523,7 +533,12 @@ public class UserManager {
* Requires the MANAGE_USERS permission.
* @param key the key of the restriction
* @param value the value for the restriction
+ * @deprecated use {@link android.app.admin.DevicePolicyManager#addUserRestriction(
+ * android.content.ComponentName, String)} or
+ * {@link android.app.admin.DevicePolicyManager#clearUserRestriction(
+ * android.content.ComponentName, String)} instead.
*/
+ @Deprecated
public void setUserRestriction(String key, boolean value) {
Bundle bundle = getUserRestrictions();
bundle.putBoolean(key, value);
@@ -537,7 +552,12 @@ public class UserManager {
* @param key the key of the restriction
* @param value the value for the restriction
* @param userHandle the user whose restriction is to be changed.
+ * @deprecated use {@link android.app.admin.DevicePolicyManager#addUserRestriction(
+ * android.content.ComponentName, String)} or
+ * {@link android.app.admin.DevicePolicyManager#clearUserRestriction(
+ * android.content.ComponentName, String)} instead.
*/
+ @Deprecated
public void setUserRestriction(String key, boolean value, UserHandle userHandle) {
Bundle bundle = getUserRestrictions(userHandle);
bundle.putBoolean(key, value);
@@ -718,7 +738,7 @@ public class UserManager {
/**
* Returns list of the profiles of userHandle including
* userHandle itself.
- * Note that it this returns both enabled and not enabled profiles. See
+ * Note that this returns both enabled and not enabled profiles. See
* {@link #getUserProfiles()} if you need only the enabled ones.
*
* Requires {@link android.Manifest.permission#MANAGE_USERS} permission.
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index b4fa972c7f47..cfa7ae772fce 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -2668,6 +2668,16 @@ public final class Settings {
};
/**
+ * These entries are considered common between the personal and the managed profile,
+ * since the managed profile doesn't get to change them.
+ * @hide
+ */
+ public static final String[] CLONE_TO_MANAGED_PROFILE = {
+ DATE_FORMAT,
+ TIME_12_24
+ };
+
+ /**
* When to use Wi-Fi calling
*
* @see android.telephony.TelephonyManager.WifiCallingChoices
@@ -4798,6 +4808,26 @@ public final class Settings {
};
/**
+ * These entries are considered common between the personal and the managed profile,
+ * since the managed profile doesn't get to change them.
+ * @hide
+ */
+ public static final String[] CLONE_TO_MANAGED_PROFILE = {
+ ACCESSIBILITY_ENABLED,
+ ALLOW_MOCK_LOCATION,
+ ALLOWED_GEOLOCATION_ORIGINS,
+ DEFAULT_INPUT_METHOD,
+ ENABLED_ACCESSIBILITY_SERVICES,
+ ENABLED_INPUT_METHODS,
+ LOCATION_MODE,
+ LOCATION_PROVIDERS_ALLOWED,
+ LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS,
+ SELECTED_INPUT_METHOD_SUBTYPE,
+ SELECTED_SPELL_CHECKER,
+ SELECTED_SPELL_CHECKER_SUBTYPE
+ };
+
+ /**
* Helper method for determining if a location provider is enabled.
*
* @param cr the content resolver to use
@@ -6441,6 +6471,14 @@ public final class Settings {
public static final String GUEST_USER_ENABLED = "guest_user_enabled";
/**
+ * Whether the NetworkScoringService has been first initialized.
+ * <p>
+ * Type: int (0 for false, 1 for true)
+ * @hide
+ */
+ public static final String NETWORK_SCORING_PROVISIONED = "network_scoring_provisioned";
+
+ /**
* Settings to backup. This is here so that it's in the same place as the settings
* keys and easy to update.
*
diff --git a/core/java/android/service/notification/ZenModeConfig.java b/core/java/android/service/notification/ZenModeConfig.java
index cc09653aa933..872f911c03ef 100644
--- a/core/java/android/service/notification/ZenModeConfig.java
+++ b/core/java/android/service/notification/ZenModeConfig.java
@@ -73,9 +73,14 @@ public class ZenModeConfig implements Parcelable {
private static final String CONDITION_TAG = "condition";
private static final String CONDITION_ATT_COMPONENT = "component";
private static final String CONDITION_ATT_ID = "id";
+ private static final String CONDITION_ATT_SUMMARY = "summary";
+ private static final String CONDITION_ATT_LINE1 = "line1";
+ private static final String CONDITION_ATT_LINE2 = "line2";
+ private static final String CONDITION_ATT_ICON = "icon";
+ private static final String CONDITION_ATT_STATE = "state";
+ private static final String CONDITION_ATT_FLAGS = "flags";
private static final String EXIT_CONDITION_TAG = "exitCondition";
- private static final String EXIT_CONDITION_ATT_ID = "id";
private static final String EXIT_CONDITION_ATT_COMPONENT = "component";
public boolean allowCalls;
@@ -83,13 +88,13 @@ public class ZenModeConfig implements Parcelable {
public int allowFrom = SOURCE_ANYONE;
public String sleepMode;
- public int sleepStartHour;
- public int sleepStartMinute;
+ public int sleepStartHour; // 0-23
+ public int sleepStartMinute; // 0-59
public int sleepEndHour;
public int sleepEndMinute;
public ComponentName[] conditionComponents;
public Uri[] conditionIds;
- public Uri exitConditionId;
+ public Condition exitCondition;
public ComponentName exitConditionComponent;
public ZenModeConfig() { }
@@ -115,7 +120,7 @@ public class ZenModeConfig implements Parcelable {
source.readTypedArray(conditionIds, Uri.CREATOR);
}
allowFrom = source.readInt();
- exitConditionId = source.readParcelable(null);
+ exitCondition = source.readParcelable(null);
exitConditionComponent = source.readParcelable(null);
}
@@ -146,7 +151,7 @@ public class ZenModeConfig implements Parcelable {
dest.writeInt(0);
}
dest.writeInt(allowFrom);
- dest.writeParcelable(exitConditionId, 0);
+ dest.writeParcelable(exitCondition, 0);
dest.writeParcelable(exitConditionComponent, 0);
}
@@ -163,7 +168,7 @@ public class ZenModeConfig implements Parcelable {
.append(conditionComponents == null ? null : TextUtils.join(",", conditionComponents))
.append(",conditionIds=")
.append(conditionIds == null ? null : TextUtils.join(",", conditionIds))
- .append(",exitConditionId=").append(exitConditionId)
+ .append(",exitCondition=").append(exitCondition)
.append(",exitConditionComponent=").append(exitConditionComponent)
.append(']').toString();
}
@@ -196,7 +201,7 @@ public class ZenModeConfig implements Parcelable {
&& other.sleepEndMinute == sleepEndMinute
&& Objects.deepEquals(other.conditionComponents, conditionComponents)
&& Objects.deepEquals(other.conditionIds, conditionIds)
- && Objects.equals(other.exitConditionId, exitConditionId)
+ && Objects.equals(other.exitCondition, exitCondition)
&& Objects.equals(other.exitConditionComponent, exitConditionComponent);
}
@@ -205,7 +210,7 @@ public class ZenModeConfig implements Parcelable {
return Objects.hash(allowCalls, allowMessages, allowFrom, sleepMode,
sleepStartHour, sleepStartMinute, sleepEndHour, sleepEndMinute,
Arrays.hashCode(conditionComponents), Arrays.hashCode(conditionIds),
- exitConditionId, exitConditionComponent);
+ exitCondition, exitConditionComponent);
}
public boolean isValid() {
@@ -294,9 +299,11 @@ public class ZenModeConfig implements Parcelable {
conditionIds.add(conditionId);
}
} else if (EXIT_CONDITION_TAG.equals(tag)) {
- rt.exitConditionId = safeUri(parser, EXIT_CONDITION_ATT_ID);
- rt.exitConditionComponent =
- safeComponentName(parser, EXIT_CONDITION_ATT_COMPONENT);
+ rt.exitCondition = readConditionXml(parser);
+ if (rt.exitCondition != null) {
+ rt.exitConditionComponent =
+ safeComponentName(parser, EXIT_CONDITION_ATT_COMPONENT);
+ }
}
}
}
@@ -333,16 +340,42 @@ public class ZenModeConfig implements Parcelable {
out.endTag(null, CONDITION_TAG);
}
}
- if (exitConditionId != null && exitConditionComponent != null) {
+ if (exitCondition != null && exitConditionComponent != null) {
out.startTag(null, EXIT_CONDITION_TAG);
- out.attribute(null, EXIT_CONDITION_ATT_ID, exitConditionId.toString());
out.attribute(null, EXIT_CONDITION_ATT_COMPONENT,
exitConditionComponent.flattenToString());
+ writeConditionXml(exitCondition, out);
out.endTag(null, EXIT_CONDITION_TAG);
}
out.endTag(null, ZEN_TAG);
}
+ public static Condition readConditionXml(XmlPullParser parser) {
+ final Uri id = safeUri(parser, CONDITION_ATT_ID);
+ final String summary = parser.getAttributeValue(null, CONDITION_ATT_SUMMARY);
+ final String line1 = parser.getAttributeValue(null, CONDITION_ATT_LINE1);
+ final String line2 = parser.getAttributeValue(null, CONDITION_ATT_LINE2);
+ final int icon = safeInt(parser, CONDITION_ATT_ICON, -1);
+ final int state = safeInt(parser, CONDITION_ATT_STATE, -1);
+ final int flags = safeInt(parser, CONDITION_ATT_FLAGS, -1);
+ try {
+ return new Condition(id, summary, line1, line2, icon, state, flags);
+ } catch (IllegalArgumentException e) {
+ Slog.w(TAG, "Unable to read condition xml", e);
+ return null;
+ }
+ }
+
+ public static void writeConditionXml(Condition c, XmlSerializer out) throws IOException {
+ out.attribute(null, CONDITION_ATT_ID, c.id.toString());
+ out.attribute(null, CONDITION_ATT_SUMMARY, c.summary);
+ out.attribute(null, CONDITION_ATT_LINE1, c.line1);
+ out.attribute(null, CONDITION_ATT_LINE2, c.line2);
+ out.attribute(null, CONDITION_ATT_ICON, Integer.toString(c.icon));
+ out.attribute(null, CONDITION_ATT_STATE, Integer.toString(c.state));
+ out.attribute(null, CONDITION_ATT_FLAGS, Integer.toString(c.flags));
+ }
+
public static boolean isValidHour(int val) {
return val >= 0 && val < 24;
}
@@ -403,21 +436,31 @@ public class ZenModeConfig implements Parcelable {
}
};
- // Built-in countdown conditions, e.g. condition://android/countdown/1399917958951
+ public DowntimeInfo toDowntimeInfo() {
+ final DowntimeInfo downtime = new DowntimeInfo();
+ downtime.startHour = sleepStartHour;
+ downtime.startMinute = sleepStartMinute;
+ downtime.endHour = sleepEndHour;
+ downtime.endMinute = sleepEndMinute;
+ return downtime;
+ }
+
+ // For built-in conditions
+ private static final String SYSTEM_AUTHORITY = "android";
- private static final String COUNTDOWN_AUTHORITY = "android";
+ // Built-in countdown conditions, e.g. condition://android/countdown/1399917958951
private static final String COUNTDOWN_PATH = "countdown";
public static Uri toCountdownConditionId(long time) {
return new Uri.Builder().scheme(Condition.SCHEME)
- .authority(COUNTDOWN_AUTHORITY)
+ .authority(SYSTEM_AUTHORITY)
.appendPath(COUNTDOWN_PATH)
.appendPath(Long.toString(time))
.build();
}
public static long tryParseCountdownConditionId(Uri conditionId) {
- if (!Condition.isValidId(conditionId, COUNTDOWN_AUTHORITY)) return 0;
+ if (!Condition.isValidId(conditionId, SYSTEM_AUTHORITY)) return 0;
if (conditionId.getPathSegments().size() != 2
|| !COUNTDOWN_PATH.equals(conditionId.getPathSegments().get(0))) return 0;
try {
@@ -431,4 +474,68 @@ public class ZenModeConfig implements Parcelable {
public static boolean isValidCountdownConditionId(Uri conditionId) {
return tryParseCountdownConditionId(conditionId) != 0;
}
+
+ // Built-in downtime conditions, e.g. condition://android/downtime?start=10.00&end=7.00
+ private static final String DOWNTIME_PATH = "downtime";
+
+ public static Uri toDowntimeConditionId(DowntimeInfo downtime) {
+ return new Uri.Builder().scheme(Condition.SCHEME)
+ .authority(SYSTEM_AUTHORITY)
+ .appendPath(DOWNTIME_PATH)
+ .appendQueryParameter("start", downtime.startHour + "." + downtime.startMinute)
+ .appendQueryParameter("end", downtime.endHour + "." + downtime.endMinute)
+ .build();
+ }
+
+ public static DowntimeInfo tryParseDowntimeConditionId(Uri conditionId) {
+ if (!Condition.isValidId(conditionId, SYSTEM_AUTHORITY)
+ || conditionId.getPathSegments().size() != 1
+ || !DOWNTIME_PATH.equals(conditionId.getPathSegments().get(0))) {
+ return null;
+ }
+ final int[] start = tryParseHourAndMinute(conditionId.getQueryParameter("start"));
+ final int[] end = tryParseHourAndMinute(conditionId.getQueryParameter("end"));
+ if (start == null || end == null) return null;
+ final DowntimeInfo downtime = new DowntimeInfo();
+ downtime.startHour = start[0];
+ downtime.startMinute = start[1];
+ downtime.endHour = end[0];
+ downtime.endMinute = end[1];
+ return downtime;
+ }
+
+ private static int[] tryParseHourAndMinute(String value) {
+ if (TextUtils.isEmpty(value)) return null;
+ final int i = value.indexOf('.');
+ if (i < 1 || i >= value.length() - 1) return null;
+ final int hour = tryParseInt(value.substring(0, i), -1);
+ final int minute = tryParseInt(value.substring(i + 1), -1);
+ return isValidHour(hour) && isValidMinute(minute) ? new int[] { hour, minute } : null;
+ }
+
+ public static boolean isValidDowntimeConditionId(Uri conditionId) {
+ return tryParseDowntimeConditionId(conditionId) != null;
+ }
+
+ public static class DowntimeInfo {
+ public int startHour; // 0-23
+ public int startMinute; // 0-59
+ public int endHour;
+ public int endMinute;
+
+ @Override
+ public int hashCode() {
+ return 0;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (!(o instanceof DowntimeInfo)) return false;
+ final DowntimeInfo other = (DowntimeInfo) o;
+ return startHour == other.startHour
+ && startMinute == other.startMinute
+ && endHour == other.endHour
+ && endMinute == other.endMinute;
+ }
+ }
}
diff --git a/core/java/android/service/trust/TrustAgentService.java b/core/java/android/service/trust/TrustAgentService.java
index 51f07ecf16bb..5fe9194d7401 100644
--- a/core/java/android/service/trust/TrustAgentService.java
+++ b/core/java/android/service/trust/TrustAgentService.java
@@ -69,12 +69,6 @@ public class TrustAgentService extends Service {
"[" + getClass().getSimpleName() + "]";
private static final boolean DEBUG = false;
- // Temporary workaround to allow current trust agent implementations to continue working.
- // This and the code guarded by this should be removed before shipping.
- // If true, calls setManagingTrust(true) after onCreate, if it wasn't already set.
- // TODO: Remove this once all agents are updated.
- private static final boolean SET_MANAGED_FOR_LEGACY_AGENTS = true;
-
/**
* The {@link Intent} that must be declared as handled by the service.
*/
@@ -130,11 +124,6 @@ public class TrustAgentService extends Service {
@Override
public void onCreate() {
- // TODO: Remove this once all agents are updated.
- if (SET_MANAGED_FOR_LEGACY_AGENTS) {
- setManagingTrust(true);
- }
-
super.onCreate();
ComponentName component = new ComponentName(this, getClass());
try {
@@ -175,7 +164,7 @@ public class TrustAgentService extends Service {
* set.
*
* @param options Option feature bundle.
- * @return true if the {@link #TrustAgentService()} supports this feature.
+ * @return true if the {@link TrustAgentService} supports this feature.
*/
public boolean onSetTrustAgentFeaturesEnabled(Bundle options) {
return false;
diff --git a/core/java/android/widget/DatePicker.java b/core/java/android/widget/DatePicker.java
index d0a2eabca962..26c1f960ff57 100644
--- a/core/java/android/widget/DatePicker.java
+++ b/core/java/android/widget/DatePicker.java
@@ -16,6 +16,7 @@
package android.widget;
+import android.annotation.Nullable;
import android.annotation.Widget;
import android.content.Context;
import android.content.res.Configuration;
@@ -123,7 +124,7 @@ public class DatePicker extends FrameLayout {
final TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.DatePicker,
defStyleAttr, defStyleRes);
- int mode = a.getInt(R.styleable.DatePicker_datePickerMode, MODE_SPINNER);
+ final int mode = a.getInt(R.styleable.DatePicker_datePickerMode, MODE_SPINNER);
a.recycle();
switch (mode) {
@@ -149,20 +150,6 @@ public class DatePicker extends FrameLayout {
}
/**
- * @hide
- */
- public void setShowDoneButton(boolean showDoneButton) {
- mDelegate.setShowDoneButton(showDoneButton);
- }
-
- /**
- * @hide
- */
- public void setDismissCallback(DatePickerDismissCallback callback) {
- mDelegate.setDismissCallback(callback);
- }
-
- /**
* Initialize the state. If the provided values designate an inconsistent
* date the values are normalized before updating the spinners.
*
@@ -259,6 +246,16 @@ public class DatePicker extends FrameLayout {
mDelegate.setMaxDate(maxDate);
}
+ /**
+ * Sets the callback that indicates the current date is valid.
+ *
+ * @param callback the callback, may be null
+ * @hide
+ */
+ public void setValidationCallback(@Nullable ValidationCallback callback) {
+ mDelegate.setValidationCallback(callback);
+ }
+
@Override
public void setEnabled(boolean enabled) {
if (mDelegate.isEnabled() == enabled) {
@@ -402,8 +399,7 @@ public class DatePicker extends FrameLayout {
void setSpinnersShown(boolean shown);
boolean getSpinnersShown();
- void setShowDoneButton(boolean showDoneButton);
- void setDismissCallback(DatePickerDismissCallback callback);
+ void setValidationCallback(ValidationCallback callback);
void onConfigurationChanged(Configuration newConfig);
@@ -431,7 +427,8 @@ public class DatePicker extends FrameLayout {
protected Locale mCurrentLocale;
// Callbacks
- protected OnDateChangedListener mOnDateChangedListener;
+ protected OnDateChangedListener mOnDateChangedListener;
+ protected ValidationCallback mValidationCallback;
public AbstractDatePickerDelegate(DatePicker delegator, Context context) {
mDelegator = delegator;
@@ -447,15 +444,27 @@ public class DatePicker extends FrameLayout {
}
mCurrentLocale = locale;
}
+
+ @Override
+ public void setValidationCallback(ValidationCallback callback) {
+ mValidationCallback = callback;
+ }
+
+ protected void onValidationChanged(boolean valid) {
+ if (mValidationCallback != null) {
+ mValidationCallback.onValidationChanged(valid);
+ }
+ }
}
/**
- * A callback interface for dismissing the DatePicker when included into a Dialog
+ * A callback interface for updating input validity when the date picker
+ * when included into a dialog.
*
* @hide
*/
- public static interface DatePickerDismissCallback {
- void dismiss(DatePicker view, boolean isCancel, int year, int month, int dayOfMonth);
+ public static interface ValidationCallback {
+ void onValidationChanged(boolean valid);
}
/**
@@ -775,16 +784,6 @@ public class DatePicker extends FrameLayout {
}
@Override
- public void setShowDoneButton(boolean showDoneButton) {
- // Nothing to do
- }
-
- @Override
- public void setDismissCallback(DatePickerDismissCallback callback) {
- // Nothing to do
- }
-
- @Override
public void onConfigurationChanged(Configuration newConfig) {
setCurrentLocale(newConfig.locale);
}
diff --git a/core/java/android/widget/DatePickerCalendarDelegate.java b/core/java/android/widget/DatePickerCalendarDelegate.java
index c0c76acc9db1..f4a478a30727 100644
--- a/core/java/android/widget/DatePickerCalendarDelegate.java
+++ b/core/java/android/widget/DatePickerCalendarDelegate.java
@@ -31,11 +31,9 @@ import android.text.format.DateFormat;
import android.text.format.DateUtils;
import android.util.AttributeSet;
import android.util.SparseArray;
-import android.util.StateSet;
import android.view.HapticFeedbackConstants;
import android.view.LayoutInflater;
import android.view.View;
-import android.view.ViewGroup;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityNodeInfo;
import android.view.animation.AlphaAnimation;
@@ -83,8 +81,6 @@ class DatePickerCalendarDelegate extends DatePicker.AbstractDatePickerDelegate i
private DayPickerView mDayPickerView;
private YearPickerView mYearPickerView;
- private ViewGroup mLayoutButtons;
-
private boolean mIsEnabled = true;
// Accessibility strings.
@@ -106,11 +102,6 @@ class DatePickerCalendarDelegate extends DatePicker.AbstractDatePickerDelegate i
private Calendar mMinDate;
private Calendar mMaxDate;
- // For showing the done button when in a Dialog
- private Button mDoneButton;
- private boolean mShowDoneButton;
- private DatePicker.DatePickerDismissCallback mDismissCallback;
-
private HashSet<OnDateChangedListener> mListeners = new HashSet<OnDateChangedListener>();
public DatePickerCalendarDelegate(DatePicker delegator, Context context, AttributeSet attrs,
@@ -165,7 +156,7 @@ class DatePickerCalendarDelegate extends DatePicker.AbstractDatePickerDelegate i
R.styleable.DatePicker_headerSelectedTextColor, defaultHighlightColor);
final int headerBackgroundColor = a.getColor(R.styleable.DatePicker_headerBackgroundColor,
Color.TRANSPARENT);
- mMonthAndDayLayout.setBackgroundColor(headerBackgroundColor);
+ mDateLayout.setBackgroundColor(headerBackgroundColor);
final int monthTextAppearanceResId = a.getResourceId(
R.styleable.DatePicker_headerMonthTextAppearance, -1);
@@ -221,20 +212,6 @@ class DatePickerCalendarDelegate extends DatePicker.AbstractDatePickerDelegate i
animation2.setDuration(ANIMATION_DURATION);
mAnimator.setOutAnimation(animation2);
- mLayoutButtons = (ViewGroup) mainView.findViewById(R.id.layout_buttons);
- mDoneButton = (Button) mainView.findViewById(R.id.done);
- mDoneButton.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- tryVibrate();
- if (mDismissCallback != null) {
- mDismissCallback.dismiss(mDelegator, false, mCurrentDate.get(Calendar.YEAR),
- mCurrentDate.get(Calendar.MONTH),
- mCurrentDate.get(Calendar.DAY_OF_MONTH));
- }
- }
- });
-
updateDisplay(false);
setCurrentView(MONTH_AND_DAY_VIEW);
}
@@ -311,9 +288,9 @@ class DatePickerCalendarDelegate extends DatePicker.AbstractDatePickerDelegate i
// Position the Year View at the correct location
if (viewIndices[YEAR_INDEX] == 0) {
- mDateLayout.addView(mHeaderYearTextView, 0);
- } else {
mDateLayout.addView(mHeaderYearTextView, 1);
+ } else {
+ mDateLayout.addView(mHeaderYearTextView, 2);
}
// Position Day and Month Views
@@ -545,21 +522,6 @@ class DatePickerCalendarDelegate extends DatePicker.AbstractDatePickerDelegate i
}
@Override
- public void setShowDoneButton(boolean showDoneButton) {
- mShowDoneButton = showDoneButton;
- updateDoneButtonVisibility();
- }
-
- private void updateDoneButtonVisibility() {
- mLayoutButtons.setVisibility(mShowDoneButton ? View.VISIBLE : View.GONE);
- }
-
- @Override
- public void setDismissCallback(DatePicker.DatePickerDismissCallback callback) {
- mDismissCallback = callback;
- }
-
- @Override
public void onConfigurationChanged(Configuration newConfig) {
mYearFormat = new SimpleDateFormat("y", newConfig.locale);
mDayFormat = new SimpleDateFormat("d", newConfig.locale);
@@ -640,7 +602,6 @@ class DatePickerCalendarDelegate extends DatePicker.AbstractDatePickerDelegate i
updatePickers();
setCurrentView(MONTH_AND_DAY_VIEW);
updateDisplay(true);
- updateDoneButtonEnableState();
}
// If the newly selected month / year does not contain the currently selected day number,
@@ -684,16 +645,6 @@ class DatePickerCalendarDelegate extends DatePicker.AbstractDatePickerDelegate i
mCurrentDate.set(Calendar.DAY_OF_MONTH, day);
updatePickers();
updateDisplay(true);
- updateDoneButtonEnableState();
- }
-
- private void updateDoneButtonEnableState() {
- if (mShowDoneButton) {
- final boolean enabled = mCurrentDate.equals(mMinDate) ||
- mCurrentDate.equals(mMaxDate) ||
- (mCurrentDate.after(mMinDate) && mCurrentDate.before(mMaxDate));
- mDoneButton.setEnabled(enabled);
- }
}
private void updatePickers() {
diff --git a/core/java/android/widget/ListView.java b/core/java/android/widget/ListView.java
index 9db1e057ee7e..1368cd38869a 100644
--- a/core/java/android/widget/ListView.java
+++ b/core/java/android/widget/ListView.java
@@ -1161,7 +1161,7 @@ public class ListView extends AbsListView {
if (recycleOnMeasure() && mRecycler.shouldRecycleViewType(
((LayoutParams) child.getLayoutParams()).viewType)) {
- mRecycler.addScrapView(child, -1);
+ mRecycler.addScrapView(child, 0);
}
}
diff --git a/core/java/android/widget/RadialTimePickerView.java b/core/java/android/widget/RadialTimePickerView.java
index 3d2f67f7c115..adca4ccdaaed 100644
--- a/core/java/android/widget/RadialTimePickerView.java
+++ b/core/java/android/widget/RadialTimePickerView.java
@@ -85,7 +85,7 @@ public class RadialTimePickerView extends View implements View.OnTouchListener {
private static final int ALPHA_TRANSPARENT = 0;
// Alpha level of color for selector.
- private static final int ALPHA_SELECTOR = 255; // was 51
+ private static final int ALPHA_SELECTOR = 60; // was 51
// Alpha level of color for selected circle.
private static final int ALPHA_AMPM_SELECTED = ALPHA_SELECTOR;
@@ -105,7 +105,7 @@ public class RadialTimePickerView extends View implements View.OnTouchListener {
private static final int CENTER_RADIUS = 2;
- private static final int[] STATE_SET_SELECTED = new int[] { R.attr.state_selected };
+ private static final int[] STATE_SET_SELECTED = new int[] {R.attr.state_selected};
private static int[] sSnapPrefer30sMap = new int[361];
@@ -337,6 +337,9 @@ public class RadialTimePickerView extends View implements View.OnTouchListener {
// list doesn't have a state for selected, we'll use this color.
final int amPmSelectedColor = a.getColor(R.styleable.TimePicker_amPmSelectedBackgroundColor,
res.getColor(R.color.timepicker_default_ampm_selected_background_color_material));
+ amPmBackgroundColor = ColorStateList.addFirstIfMissing(
+ amPmBackgroundColor, R.attr.state_selected, amPmSelectedColor);
+
mAmPmSelectedColor = amPmBackgroundColor.getColorForState(
STATE_SET_SELECTED, amPmSelectedColor);
mAmPmUnselectedColor = amPmBackgroundColor.getDefaultColor();
diff --git a/core/java/android/widget/SimpleMonthView.java b/core/java/android/widget/SimpleMonthView.java
index ab6da7c7c5ea..a0d94750aca6 100644
--- a/core/java/android/widget/SimpleMonthView.java
+++ b/core/java/android/widget/SimpleMonthView.java
@@ -38,10 +38,8 @@ import android.view.accessibility.AccessibilityNodeInfo;
import com.android.internal.R;
import com.android.internal.widget.ExploreByTouchHelper;
-import java.security.InvalidParameterException;
import java.util.Calendar;
import java.util.Formatter;
-import java.util.HashMap;
import java.util.List;
import java.util.Locale;
@@ -52,8 +50,8 @@ import java.util.Locale;
class SimpleMonthView extends View {
private static final String TAG = "SimpleMonthView";
- private static int DEFAULT_HEIGHT = 32;
- private static int MIN_HEIGHT = 10;
+ private static final int DEFAULT_HEIGHT = 32;
+ private static final int MIN_HEIGHT = 10;
private static final int DEFAULT_SELECTED_DAY = -1;
private static final int DEFAULT_WEEK_START = Calendar.SUNDAY;
@@ -63,13 +61,13 @@ class SimpleMonthView extends View {
private static final int SELECTED_CIRCLE_ALPHA = 60;
- private static int DAY_SEPARATOR_WIDTH = 1;
+ private static final int DAY_SEPARATOR_WIDTH = 1;
- private int mMiniDayNumberTextSize;
- private int mMonthLabelTextSize;
- private int mMonthDayLabelTextSize;
- private int mMonthHeaderSize;
- private int mDaySelectedCircleSize;
+ private final int mMiniDayNumberTextSize;
+ private final int mMonthLabelTextSize;
+ private final int mMonthDayLabelTextSize;
+ private final int mMonthHeaderSize;
+ private final int mDaySelectedCircleSize;
// used for scaling to the device density
private static float mScale = 0;
@@ -289,7 +287,7 @@ class SimpleMonthView extends View {
drawDays(canvas);
}
- private static boolean isValidDay(int day) {
+ private static boolean isValidDayOfWeek(int day) {
return (day >= Time.SUNDAY && day <= Time.SATURDAY);
}
@@ -299,7 +297,7 @@ class SimpleMonthView extends View {
* default to no focus month if no value is passed in. The only required parameter is the
* week start.
*
- * @param selectedDay the selected day.
+ * @param selectedDay the selected day of the month, or -1 for no selection.
* @param month the month.
* @param year the year.
* @param weekStart which day the week should start on. {@link Time#SUNDAY} through
@@ -313,9 +311,7 @@ class SimpleMonthView extends View {
mRowHeight = MIN_HEIGHT;
}
- if (isValidDay(selectedDay)) {
- mSelectedDay = selectedDay;
- }
+ mSelectedDay = selectedDay;
if (month >= Calendar.JANUARY && month <= Calendar.DECEMBER) {
mMonth = month;
@@ -333,7 +329,7 @@ class SimpleMonthView extends View {
mCalendar.set(Calendar.DAY_OF_MONTH, 1);
mDayOfWeekStart = mCalendar.get(Calendar.DAY_OF_WEEK);
- if (isValidDay(weekStart)) {
+ if (isValidDayOfWeek(weekStart)) {
mWeekStart = weekStart;
} else {
mWeekStart = mCalendar.getFirstDayOfWeek();
@@ -424,8 +420,8 @@ class SimpleMonthView extends View {
}
private void drawMonthTitle(Canvas canvas) {
- int x = (mWidth + 2 * mPadding) / 2;
- int y = (mMonthHeaderSize - mMonthDayLabelTextSize) / 2 + (mMonthLabelTextSize / 3);
+ final float x = (mWidth + 2 * mPadding) / 2f;
+ final float y = (mMonthHeaderSize - mMonthDayLabelTextSize) / 2f;
canvas.drawText(getMonthAndYearString(), x, y, mMonthTitlePaint);
}
@@ -437,9 +433,9 @@ class SimpleMonthView extends View {
int calendarDay = (i + mWeekStart) % mNumDays;
int x = (2 * i + 1) * dayWidthHalf + mPadding;
mDayLabelCalendar.set(Calendar.DAY_OF_WEEK, calendarDay);
- canvas.drawText(mDayLabelCalendar.getDisplayName(Calendar.DAY_OF_WEEK, Calendar.SHORT,
- Locale.getDefault()).toUpperCase(Locale.getDefault()), x, y,
- mMonthDayLabelPaint);
+ canvas.drawText("" + mDayLabelCalendar.getDisplayName(Calendar.DAY_OF_WEEK,
+ Calendar.SHORT, Locale.getDefault()).toUpperCase(Locale.getDefault()).charAt(0),
+ x, y, mMonthDayLabelPaint);
}
}
diff --git a/core/java/android/widget/TimePicker.java b/core/java/android/widget/TimePicker.java
index c48866692190..85cf67b90e5e 100644
--- a/core/java/android/widget/TimePicker.java
+++ b/core/java/android/widget/TimePicker.java
@@ -16,6 +16,7 @@
package android.widget;
+import android.annotation.Nullable;
import android.annotation.Widget;
import android.content.Context;
import android.content.res.Configuration;
@@ -80,7 +81,7 @@ public class TimePicker extends FrameLayout {
final TypedArray a = context.obtainStyledAttributes(
attrs, R.styleable.TimePicker, defStyleAttr, defStyleRes);
- int mode = a.getInt(R.styleable.TimePicker_timePickerMode, MODE_SPINNER);
+ final int mode = a.getInt(R.styleable.TimePicker_timePickerMode, MODE_SPINNER);
a.recycle();
switch (mode) {
@@ -149,6 +150,16 @@ public class TimePicker extends FrameLayout {
mDelegate.setOnTimeChangedListener(onTimeChangedListener);
}
+ /**
+ * Sets the callback that indicates the current time is valid.
+ *
+ * @param callback the callback, may be null
+ * @hide
+ */
+ public void setValidationCallback(@Nullable ValidationCallback callback) {
+ mDelegate.setValidationCallback(callback);
+ }
+
@Override
public void setEnabled(boolean enabled) {
super.setEnabled(enabled);
@@ -160,27 +171,6 @@ public class TimePicker extends FrameLayout {
return mDelegate.isEnabled();
}
- /**
- * @hide
- */
- public void setShowDoneButton(boolean showDoneButton) {
- mDelegate.setShowDoneButton(showDoneButton);
- }
-
- /**
- * @hide
- */
- public boolean isShowDoneButton() {
- return mDelegate.isShowDoneButton();
- }
-
- /**
- * @hide
- */
- public void setDismissCallback(TimePickerDismissCallback callback) {
- mDelegate.setDismissCallback(callback);
- }
-
@Override
public int getBaseline() {
return mDelegate.getBaseline();
@@ -244,14 +234,11 @@ public class TimePicker extends FrameLayout {
boolean is24HourView();
void setOnTimeChangedListener(OnTimeChangedListener onTimeChangedListener);
+ void setValidationCallback(ValidationCallback callback);
void setEnabled(boolean enabled);
boolean isEnabled();
- boolean isShowDoneButton();
- void setShowDoneButton(boolean showDoneButton);
- void setDismissCallback(TimePickerDismissCallback callback);
-
int getBaseline();
void onConfigurationChanged(Configuration newConfig);
@@ -266,12 +253,13 @@ public class TimePicker extends FrameLayout {
}
/**
- * A callback interface for dismissing the TimePicker when included into a Dialog
+ * A callback interface for updating input validity when the TimePicker
+ * when included into a Dialog.
*
* @hide
*/
- public static interface TimePickerDismissCallback {
- void dismiss(TimePicker view, boolean isCancel, int hourOfDay, int minute);
+ public static interface ValidationCallback {
+ void onValidationChanged(boolean valid);
}
/**
@@ -288,7 +276,8 @@ public class TimePicker extends FrameLayout {
protected Locale mCurrentLocale;
// Callbacks
- protected OnTimeChangedListener mOnTimeChangedListener;
+ protected OnTimeChangedListener mOnTimeChangedListener;
+ protected ValidationCallback mValidationCallback;
public AbstractTimePickerDelegate(TimePicker delegator, Context context) {
mDelegator = delegator;
@@ -304,5 +293,16 @@ public class TimePicker extends FrameLayout {
}
mCurrentLocale = locale;
}
+
+ @Override
+ public void setValidationCallback(ValidationCallback callback) {
+ mValidationCallback = callback;
+ }
+
+ protected void onValidationChanged(boolean valid) {
+ if (mValidationCallback != null) {
+ mValidationCallback.onValidationChanged(valid);
+ }
+ }
}
}
diff --git a/core/java/android/widget/TimePickerClockDelegate.java b/core/java/android/widget/TimePickerClockDelegate.java
index 8102c4acf364..376e5b443f5b 100644
--- a/core/java/android/widget/TimePickerClockDelegate.java
+++ b/core/java/android/widget/TimePickerClockDelegate.java
@@ -20,7 +20,6 @@ import android.content.Context;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.content.res.TypedArray;
-import android.graphics.Color;
import android.os.Parcel;
import android.os.Parcelable;
import android.text.format.DateFormat;
@@ -35,7 +34,6 @@ import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputMethodManager;
import com.android.internal.R;
-import java.text.DateFormatSymbols;
import java.util.Calendar;
import java.util.Locale;
@@ -46,29 +44,20 @@ import static android.view.View.IMPORTANT_FOR_ACCESSIBILITY_YES;
* A delegate implementing the basic TimePicker
*/
class TimePickerClockDelegate extends TimePicker.AbstractTimePickerDelegate {
-
private static final boolean DEFAULT_ENABLED_STATE = true;
-
private static final int HOURS_IN_HALF_DAY = 12;
// state
private boolean mIs24HourView;
-
private boolean mIsAm;
// ui components
private final NumberPicker mHourSpinner;
-
private final NumberPicker mMinuteSpinner;
-
private final NumberPicker mAmPmSpinner;
-
private final EditText mHourSpinnerInput;
-
private final EditText mMinuteSpinnerInput;
-
private final EditText mAmPmSpinnerInput;
-
private final TextView mDivider;
// Note that the legacy implementation of the TimePicker is
@@ -77,17 +66,10 @@ class TimePickerClockDelegate extends TimePicker.AbstractTimePickerDelegate {
// accommodates these two cases to be backwards compatible.
private final Button mAmPmButton;
- // May be null if layout has no done button
- private final View mDoneButton;
- private boolean mShowDoneButton;
- private TimePicker.TimePickerDismissCallback mDismissCallback;
-
private final String[] mAmPmStrings;
private boolean mIsEnabled = DEFAULT_ENABLED_STATE;
-
private Calendar mTempCalendar;
-
private boolean mHourWithTwoDigit;
private char mHourFormat;
@@ -227,20 +209,6 @@ class TimePickerClockDelegate extends TimePicker.AbstractTimePickerDelegate {
}
}
- mDoneButton = delegator.findViewById(R.id.done_button);
- mShowDoneButton = (mDoneButton != null);
- if (mShowDoneButton) {
- mDoneButton.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- if (mDismissCallback != null) {
- mDismissCallback.dismiss(mDelegator, false, getCurrentHour(),
- getCurrentMinute());
- }
- }
- });
- }
-
getHourFormatData();
// update controls to initial state
@@ -265,8 +233,6 @@ class TimePickerClockDelegate extends TimePicker.AbstractTimePickerDelegate {
if (mDelegator.getImportantForAccessibility() == IMPORTANT_FOR_ACCESSIBILITY_AUTO) {
mDelegator.setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_YES);
}
-
- updateDoneButton();
}
private void getHourFormatData() {
@@ -432,30 +398,6 @@ class TimePickerClockDelegate extends TimePicker.AbstractTimePickerDelegate {
}
@Override
- public void setShowDoneButton(boolean showDoneButton) {
- if (mDoneButton != null) {
- mShowDoneButton = showDoneButton;
- updateDoneButton();
- }
- }
-
- @Override
- public boolean isShowDoneButton() {
- return mShowDoneButton;
- }
-
- private void updateDoneButton() {
- if (mDoneButton != null) {
- mDoneButton.setVisibility(mShowDoneButton ? View.VISIBLE : View.GONE);
- }
- }
-
- @Override
- public void setDismissCallback(TimePicker.TimePickerDismissCallback callback) {
- mDismissCallback = callback;
- }
-
- @Override
public int getBaseline() {
return mHourSpinner.getBaseline();
}
@@ -467,8 +409,7 @@ class TimePickerClockDelegate extends TimePicker.AbstractTimePickerDelegate {
@Override
public Parcelable onSaveInstanceState(Parcelable superState) {
- return new SavedState(superState, getCurrentHour(), getCurrentMinute(),
- isShowDoneButton());
+ return new SavedState(superState, getCurrentHour(), getCurrentMinute());
}
@Override
@@ -476,7 +417,6 @@ class TimePickerClockDelegate extends TimePicker.AbstractTimePickerDelegate {
SavedState ss = (SavedState) state;
setCurrentHour(ss.getHour());
setCurrentMinute(ss.getMinute());
- setShowDoneButton(ss.isShowDoneButton());
}
@Override
@@ -632,25 +572,19 @@ class TimePickerClockDelegate extends TimePicker.AbstractTimePickerDelegate {
* Used to save / restore state of time picker
*/
private static class SavedState extends View.BaseSavedState {
-
private final int mHour;
-
private final int mMinute;
- private final boolean mShowDoneButton;
-
- private SavedState(Parcelable superState, int hour, int minute, boolean showDoneButton) {
+ private SavedState(Parcelable superState, int hour, int minute) {
super(superState);
mHour = hour;
mMinute = minute;
- mShowDoneButton = showDoneButton;
}
private SavedState(Parcel in) {
super(in);
mHour = in.readInt();
mMinute = in.readInt();
- mShowDoneButton = (in.readInt() == 1);
}
public int getHour() {
@@ -661,16 +595,11 @@ class TimePickerClockDelegate extends TimePicker.AbstractTimePickerDelegate {
return mMinute;
}
- public boolean isShowDoneButton() {
- return mShowDoneButton;
- }
-
@Override
public void writeToParcel(Parcel dest, int flags) {
super.writeToParcel(dest, flags);
dest.writeInt(mHour);
dest.writeInt(mMinute);
- dest.writeInt(mShowDoneButton ? 1 : 0);
}
@SuppressWarnings({"unused", "hiding"})
diff --git a/core/java/android/widget/TimePickerSpinnerDelegate.java b/core/java/android/widget/TimePickerSpinnerDelegate.java
index 523965c96e9e..9a50250587cf 100644
--- a/core/java/android/widget/TimePickerSpinnerDelegate.java
+++ b/core/java/android/widget/TimePickerSpinnerDelegate.java
@@ -43,7 +43,6 @@ import android.view.accessibility.AccessibilityNodeInfo;
import com.android.internal.R;
-import java.text.DateFormatSymbols;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Locale;
@@ -86,8 +85,6 @@ class TimePickerSpinnerDelegate extends TimePicker.AbstractTimePickerDelegate im
private RadialTimePickerView mRadialTimePickerView;
private TextView mSeparatorView;
- private ViewGroup mLayoutButtons;
-
private String mAmText;
private String mPmText;
@@ -101,16 +98,12 @@ class TimePickerSpinnerDelegate extends TimePicker.AbstractTimePickerDelegate im
private String mDoublePlaceholderText;
private String mDeletedKeyFormat;
private boolean mInKbMode;
+ private boolean mIsTimeValid = true;
private ArrayList<Integer> mTypedTimes = new ArrayList<Integer>();
private Node mLegalTimesTree;
private int mAmKeyCode;
private int mPmKeyCode;
- // For showing the done button when in a Dialog
- private Button mDoneButton;
- private boolean mShowDoneButton;
- private TimePicker.TimePickerDismissCallback mDismissCallback;
-
// Accessibility strings.
private String mHourPickerDescription;
private String mSelectHours;
@@ -146,7 +139,6 @@ class TimePickerSpinnerDelegate extends TimePicker.AbstractTimePickerDelegate im
mSeparatorView = (TextView) mainView.findViewById(R.id.separator);
mMinuteView = (TextView) mainView.findViewById(R.id.minutes);
mAmPmTextView = (TextView) mainView.findViewById(R.id.ampm_label);
- mLayoutButtons = (ViewGroup) mainView.findViewById(R.id.layout_buttons);
// Set up text appearances from style.
final int headerTimeTextAppearance = a.getResourceId(
@@ -174,7 +166,6 @@ class TimePickerSpinnerDelegate extends TimePicker.AbstractTimePickerDelegate im
final int headerBackgroundColor = a.getColor(
R.styleable.TimePicker_headerBackgroundColor, Color.TRANSPARENT);
if (headerBackgroundColor != Color.TRANSPARENT) {
- mLayoutButtons.setBackgroundColor(headerBackgroundColor);
mainView.findViewById(R.id.time_header).setBackgroundColor(headerBackgroundColor);
}
@@ -182,7 +173,6 @@ class TimePickerSpinnerDelegate extends TimePicker.AbstractTimePickerDelegate im
mRadialTimePickerView = (RadialTimePickerView) mainView.findViewById(
R.id.radial_picker);
- mDoneButton = (Button) mainView.findViewById(R.id.done_button);
setupListeners();
@@ -199,16 +189,14 @@ class TimePickerSpinnerDelegate extends TimePicker.AbstractTimePickerDelegate im
final Calendar calendar = Calendar.getInstance(mCurrentLocale);
final int currentHour = calendar.get(Calendar.HOUR_OF_DAY);
final int currentMinute = calendar.get(Calendar.MINUTE);
- initialize(currentHour, currentMinute, false /* 12h */, HOUR_INDEX, false);
+ initialize(currentHour, currentMinute, false /* 12h */, HOUR_INDEX);
}
- private void initialize(int hourOfDay, int minute, boolean is24HourView, int index,
- boolean showDoneButton) {
+ private void initialize(int hourOfDay, int minute, boolean is24HourView, int index) {
mInitialHourOfDay = hourOfDay;
mInitialMinute = minute;
mIs24HourView = is24HourView;
mInKbMode = false;
- mShowDoneButton = showDoneButton;
updateUI(index);
}
@@ -236,21 +224,6 @@ class TimePickerSpinnerDelegate extends TimePicker.AbstractTimePickerDelegate im
tryVibrate();
}
});
- mDoneButton.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- if (mInKbMode && isTypedTimeFullyLegal()) {
- finishKbMode(false);
- } else {
- tryVibrate();
- }
- if (mDismissCallback != null) {
- mDismissCallback.dismiss(mDelegator, false, getCurrentHour(),
- getCurrentMinute());
- }
- }
- });
- mDoneButton.setOnKeyListener(keyboardListener);
}
private void updateUI(int index) {
@@ -258,8 +231,6 @@ class TimePickerSpinnerDelegate extends TimePicker.AbstractTimePickerDelegate im
updateRadialPicker(index);
// Enable or disable the AM/PM view.
updateHeaderAmPm();
- // Show or hide Done button
- updateDoneButton();
// Update Hour and Minutes
updateHeaderHour(mInitialHourOfDay, true);
// Update time separator
@@ -336,10 +307,6 @@ class TimePickerSpinnerDelegate extends TimePicker.AbstractTimePickerDelegate im
}
}
- private void updateDoneButton() {
- mLayoutButtons.setVisibility(mShowDoneButton ? View.VISIBLE : View.GONE);
- }
-
/**
* Set the current hour.
*/
@@ -447,17 +414,6 @@ class TimePickerSpinnerDelegate extends TimePicker.AbstractTimePickerDelegate im
}
@Override
- public void setShowDoneButton(boolean showDoneButton) {
- mShowDoneButton = showDoneButton;
- updateDoneButton();
- }
-
- @Override
- public void setDismissCallback(TimePicker.TimePickerDismissCallback callback) {
- mDismissCallback = callback;
- }
-
- @Override
public int getBaseline() {
// does not support baseline alignment
return -1;
@@ -471,8 +427,7 @@ class TimePickerSpinnerDelegate extends TimePicker.AbstractTimePickerDelegate im
@Override
public Parcelable onSaveInstanceState(Parcelable superState) {
return new SavedState(superState, getCurrentHour(), getCurrentMinute(),
- is24HourView(), inKbMode(), getTypedTimes(), getCurrentItemShowing(),
- isShowDoneButton());
+ is24HourView(), inKbMode(), getTypedTimes(), getCurrentItemShowing());
}
@Override
@@ -480,8 +435,7 @@ class TimePickerSpinnerDelegate extends TimePicker.AbstractTimePickerDelegate im
SavedState ss = (SavedState) state;
setInKbMode(ss.inKbMode());
setTypedTimes(ss.getTypesTimes());
- initialize(ss.getHour(), ss.getMinute(), ss.is24HourMode(), ss.getCurrentItemShowing(),
- ss.isShowDoneButton());
+ initialize(ss.getHour(), ss.getMinute(), ss.is24HourMode(), ss.getCurrentItemShowing());
mRadialTimePickerView.invalidate();
if (mInKbMode) {
tryStartingKbMode(-1);
@@ -560,11 +514,6 @@ class TimePickerSpinnerDelegate extends TimePicker.AbstractTimePickerDelegate im
return mRadialTimePickerView.getCurrentItemShowing();
}
- @Override
- public boolean isShowDoneButton() {
- return mShowDoneButton;
- }
-
/**
* Propagate the time change
*/
@@ -587,11 +536,10 @@ class TimePickerSpinnerDelegate extends TimePicker.AbstractTimePickerDelegate im
private final boolean mInKbMode;
private final ArrayList<Integer> mTypedTimes;
private final int mCurrentItemShowing;
- private final boolean mShowDoneButton;
private SavedState(Parcelable superState, int hour, int minute, boolean is24HourMode,
boolean isKbMode, ArrayList<Integer> typedTimes,
- int currentItemShowing, boolean showDoneButton) {
+ int currentItemShowing) {
super(superState);
mHour = hour;
mMinute = minute;
@@ -599,7 +547,6 @@ class TimePickerSpinnerDelegate extends TimePicker.AbstractTimePickerDelegate im
mInKbMode = isKbMode;
mTypedTimes = typedTimes;
mCurrentItemShowing = currentItemShowing;
- mShowDoneButton = showDoneButton;
}
private SavedState(Parcel in) {
@@ -610,7 +557,6 @@ class TimePickerSpinnerDelegate extends TimePicker.AbstractTimePickerDelegate im
mInKbMode = (in.readInt() == 1);
mTypedTimes = in.readArrayList(getClass().getClassLoader());
mCurrentItemShowing = in.readInt();
- mShowDoneButton = (in.readInt() == 1);
}
public int getHour() {
@@ -637,10 +583,6 @@ class TimePickerSpinnerDelegate extends TimePicker.AbstractTimePickerDelegate im
return mCurrentItemShowing;
}
- public boolean isShowDoneButton() {
- return mShowDoneButton;
- }
-
@Override
public void writeToParcel(Parcel dest, int flags) {
super.writeToParcel(dest, flags);
@@ -650,7 +592,6 @@ class TimePickerSpinnerDelegate extends TimePicker.AbstractTimePickerDelegate im
dest.writeInt(mInKbMode ? 1 : 0);
dest.writeList(mTypedTimes);
dest.writeInt(mCurrentItemShowing);
- dest.writeInt(mShowDoneButton ? 1 : 0);
}
@SuppressWarnings({"unused", "hiding"})
@@ -852,12 +793,7 @@ class TimePickerSpinnerDelegate extends TimePicker.AbstractTimePickerDelegate im
* @return true if the key was successfully processed, false otherwise.
*/
private boolean processKeyUp(int keyCode) {
- if (keyCode == KeyEvent.KEYCODE_ESCAPE || keyCode == KeyEvent.KEYCODE_BACK) {
- if (mDismissCallback != null) {
- mDismissCallback.dismiss(mDelegator, true, getCurrentHour(), getCurrentMinute());
- }
- return true;
- } else if (keyCode == KeyEvent.KEYCODE_TAB) {
+ if (keyCode == KeyEvent.KEYCODE_ESCAPE || keyCode == KeyEvent.KEYCODE_TAB) {
if(mInKbMode) {
if (isTypedTimeFullyLegal()) {
finishKbMode(true);
@@ -876,9 +812,6 @@ class TimePickerSpinnerDelegate extends TimePicker.AbstractTimePickerDelegate im
mRadialTimePickerView.getCurrentHour(),
mRadialTimePickerView.getCurrentMinute());
}
- if (mDismissCallback != null) {
- mDismissCallback.dismiss(mDelegator, false, getCurrentHour(), getCurrentMinute());
- }
return true;
} else if (keyCode == KeyEvent.KEYCODE_DEL) {
if (mInKbMode) {
@@ -933,7 +866,7 @@ class TimePickerSpinnerDelegate extends TimePicker.AbstractTimePickerDelegate im
private void tryStartingKbMode(int keyCode) {
if (keyCode == -1 || addKeyIfLegal(keyCode)) {
mInKbMode = true;
- mDoneButton.setEnabled(false);
+ onValidationChanged(false);
updateDisplay(false);
mRadialTimePickerView.setInputEnabled(false);
}
@@ -961,7 +894,7 @@ class TimePickerSpinnerDelegate extends TimePicker.AbstractTimePickerDelegate im
mTypedTimes.add(mTypedTimes.size() - 1, KeyEvent.KEYCODE_0);
mTypedTimes.add(mTypedTimes.size() - 1, KeyEvent.KEYCODE_0);
}
- mDoneButton.setEnabled(true);
+ onValidationChanged(true);
}
return true;
@@ -1002,7 +935,7 @@ class TimePickerSpinnerDelegate extends TimePicker.AbstractTimePickerDelegate im
private int deleteLastTypedKey() {
int deleted = mTypedTimes.remove(mTypedTimes.size() - 1);
if (!isTypedTimeFullyLegal()) {
- mDoneButton.setEnabled(false);
+ onValidationChanged(false);
}
return deleted;
}
@@ -1046,7 +979,7 @@ class TimePickerSpinnerDelegate extends TimePicker.AbstractTimePickerDelegate im
updateAmPmDisplay(hour < 12 ? AM : PM);
}
setCurrentItemShowing(mRadialTimePickerView.getCurrentItemShowing(), true, true, true);
- mDoneButton.setEnabled(true);
+ onValidationChanged(true);
} else {
boolean[] enteredZeros = {false, false};
int[] values = getEnteredTime(enteredZeros);
diff --git a/core/java/android/widget/YearPickerView.java b/core/java/android/widget/YearPickerView.java
index b67fa552752b..94c21dc5b9bc 100644
--- a/core/java/android/widget/YearPickerView.java
+++ b/core/java/android/widget/YearPickerView.java
@@ -45,7 +45,7 @@ class YearPickerView extends ListView implements AdapterView.OnItemClickListener
}
public YearPickerView(Context context, AttributeSet attrs) {
- this(context, attrs, 0);
+ this(context, attrs, R.attr.listViewStyle);
}
public YearPickerView(Context context, AttributeSet attrs, int defStyleAttr) {
diff --git a/core/java/com/android/internal/os/InstallerConnection.java b/core/java/com/android/internal/os/InstallerConnection.java
new file mode 100644
index 000000000000..e3f229fc659f
--- /dev/null
+++ b/core/java/com/android/internal/os/InstallerConnection.java
@@ -0,0 +1,207 @@
+/*
+ * 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
+ */
+
+package com.android.internal.os;
+
+import android.net.LocalSocket;
+import android.net.LocalSocketAddress;
+import android.util.Slog;
+import libcore.io.IoUtils;
+import libcore.io.Streams;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+/**
+ * Represents a connection to {@code installd}. Allows multiple connect and
+ * disconnect cycles.
+ *
+ * @hide for internal use only
+ */
+public class InstallerConnection {
+ private static final String TAG = "InstallerConnection";
+ private static final boolean LOCAL_DEBUG = false;
+
+ private InputStream mIn;
+ private OutputStream mOut;
+ private LocalSocket mSocket;
+
+ private final byte buf[] = new byte[1024];
+
+ public InstallerConnection() {
+ }
+
+ public synchronized String transact(String cmd) {
+ if (!connect()) {
+ Slog.e(TAG, "connection failed");
+ return "-1";
+ }
+
+ if (!writeCommand(cmd)) {
+ /*
+ * If installd died and restarted in the background (unlikely but
+ * possible) we'll fail on the next write (this one). Try to
+ * reconnect and write the command one more time before giving up.
+ */
+ Slog.e(TAG, "write command failed? reconnect!");
+ if (!connect() || !writeCommand(cmd)) {
+ return "-1";
+ }
+ }
+ if (LOCAL_DEBUG) {
+ Slog.i(TAG, "send: '" + cmd + "'");
+ }
+
+ final int replyLength = readReply();
+ if (replyLength > 0) {
+ String s = new String(buf, 0, replyLength);
+ if (LOCAL_DEBUG) {
+ Slog.i(TAG, "recv: '" + s + "'");
+ }
+ return s;
+ } else {
+ if (LOCAL_DEBUG) {
+ Slog.i(TAG, "fail");
+ }
+ return "-1";
+ }
+ }
+
+ public int execute(String cmd) {
+ String res = transact(cmd);
+ try {
+ return Integer.parseInt(res);
+ } catch (NumberFormatException ex) {
+ return -1;
+ }
+ }
+
+ public int dexopt(String apkPath, int uid, boolean isPublic, String instructionSet) {
+ StringBuilder builder = new StringBuilder("dexopt");
+ builder.append(' ');
+ builder.append(apkPath);
+ builder.append(' ');
+ builder.append(uid);
+ builder.append(isPublic ? " 1" : " 0");
+ builder.append(" *"); // No pkgName arg present
+ builder.append(' ');
+ builder.append(instructionSet);
+ return execute(builder.toString());
+ }
+
+ public int patchoat(String apkPath, int uid, boolean isPublic, String instructionSet) {
+ StringBuilder builder = new StringBuilder("patchoat");
+ builder.append(' ');
+ builder.append(apkPath);
+ builder.append(' ');
+ builder.append(uid);
+ builder.append(isPublic ? " 1" : " 0");
+ builder.append(" *"); // No pkgName arg present
+ builder.append(' ');
+ builder.append(instructionSet);
+ return execute(builder.toString());
+ }
+
+ private boolean connect() {
+ if (mSocket != null) {
+ return true;
+ }
+ Slog.i(TAG, "connecting...");
+ try {
+ mSocket = new LocalSocket();
+
+ LocalSocketAddress address = new LocalSocketAddress("installd",
+ LocalSocketAddress.Namespace.RESERVED);
+
+ mSocket.connect(address);
+
+ mIn = mSocket.getInputStream();
+ mOut = mSocket.getOutputStream();
+ } catch (IOException ex) {
+ disconnect();
+ return false;
+ }
+ return true;
+ }
+
+ public void disconnect() {
+ Slog.i(TAG, "disconnecting...");
+ IoUtils.closeQuietly(mSocket);
+ IoUtils.closeQuietly(mIn);
+ IoUtils.closeQuietly(mOut);
+
+ mSocket = null;
+ mIn = null;
+ mOut = null;
+ }
+
+
+ private boolean readFully(byte[] buffer, int len) {
+ try {
+ Streams.readFully(mIn, buffer, 0, len);
+ } catch (IOException ioe) {
+ Slog.e(TAG, "read exception");
+ disconnect();
+ return false;
+ }
+
+ if (LOCAL_DEBUG) {
+ Slog.i(TAG, "read " + len + " bytes");
+ }
+
+ return true;
+ }
+
+ private int readReply() {
+ if (!readFully(buf, 2)) {
+ return -1;
+ }
+
+ final int len = (((int) buf[0]) & 0xff) | ((((int) buf[1]) & 0xff) << 8);
+ if ((len < 1) || (len > buf.length)) {
+ Slog.e(TAG, "invalid reply length (" + len + ")");
+ disconnect();
+ return -1;
+ }
+
+ if (!readFully(buf, len)) {
+ return -1;
+ }
+
+ return len;
+ }
+
+ private boolean writeCommand(String cmdString) {
+ final byte[] cmd = cmdString.getBytes();
+ final int len = cmd.length;
+ if ((len < 1) || (len > buf.length)) {
+ return false;
+ }
+
+ buf[0] = (byte) (len & 0xff);
+ buf[1] = (byte) ((len >> 8) & 0xff);
+ try {
+ mOut.write(buf, 0, 2);
+ mOut.write(cmd, 0, len);
+ } catch (IOException ex) {
+ Slog.e(TAG, "write error");
+ disconnect();
+ return false;
+ }
+ return true;
+ }
+}
diff --git a/core/java/com/android/internal/os/RuntimeInit.java b/core/java/com/android/internal/os/RuntimeInit.java
index 4a26b4b17b6f..d35fce453891 100644
--- a/core/java/com/android/internal/os/RuntimeInit.java
+++ b/core/java/com/android/internal/os/RuntimeInit.java
@@ -192,13 +192,14 @@ public class RuntimeInit {
*
* @param className Fully-qualified class name
* @param argv Argument vector for main()
+ * @param classLoader the classLoader to load {@className} with
*/
- private static void invokeStaticMain(String className, String[] argv)
+ private static void invokeStaticMain(String className, String[] argv, ClassLoader classLoader)
throws ZygoteInit.MethodAndArgsCaller {
Class<?> cl;
try {
- cl = Class.forName(className);
+ cl = Class.forName(className, true, classLoader);
} catch (ClassNotFoundException ex) {
throw new RuntimeException(
"Missing class when invoking static main " + className,
@@ -263,7 +264,7 @@ public class RuntimeInit {
* @param targetSdkVersion target SDK version
* @param argv arg strings
*/
- public static final void zygoteInit(int targetSdkVersion, String[] argv)
+ public static final void zygoteInit(int targetSdkVersion, String[] argv, ClassLoader classLoader)
throws ZygoteInit.MethodAndArgsCaller {
if (DEBUG) Slog.d(TAG, "RuntimeInit: Starting application from zygote");
@@ -272,7 +273,7 @@ public class RuntimeInit {
commonInit();
nativeZygoteInit();
- applicationInit(targetSdkVersion, argv);
+ applicationInit(targetSdkVersion, argv, classLoader);
}
/**
@@ -290,10 +291,10 @@ public class RuntimeInit {
throws ZygoteInit.MethodAndArgsCaller {
if (DEBUG) Slog.d(TAG, "RuntimeInit: Starting application from wrapper");
- applicationInit(targetSdkVersion, argv);
+ applicationInit(targetSdkVersion, argv, null);
}
- private static void applicationInit(int targetSdkVersion, String[] argv)
+ private static void applicationInit(int targetSdkVersion, String[] argv, ClassLoader classLoader)
throws ZygoteInit.MethodAndArgsCaller {
// If the application calls System.exit(), terminate the process
// immediately without running any shutdown hooks. It is not possible to
@@ -317,7 +318,7 @@ public class RuntimeInit {
}
// Remaining arguments are passed to the start class's static main
- invokeStaticMain(args.startClass, args.startArgs);
+ invokeStaticMain(args.startClass, args.startArgs, classLoader);
}
/**
diff --git a/core/java/com/android/internal/os/ZygoteConnection.java b/core/java/com/android/internal/os/ZygoteConnection.java
index 0c4836854ace..43ebb3d10912 100644
--- a/core/java/com/android/internal/os/ZygoteConnection.java
+++ b/core/java/com/android/internal/os/ZygoteConnection.java
@@ -863,7 +863,7 @@ class ZygoteConnection {
pipeFd, parsedArgs.remainingArgs);
} else {
RuntimeInit.zygoteInit(parsedArgs.targetSdkVersion,
- parsedArgs.remainingArgs);
+ parsedArgs.remainingArgs, null /* classLoader */);
}
} else {
String className;
diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java
index eea420133f4e..051de6e5d1f8 100644
--- a/core/java/com/android/internal/os/ZygoteInit.java
+++ b/core/java/com/android/internal/os/ZygoteInit.java
@@ -34,8 +34,11 @@ import android.system.Os;
import android.system.OsConstants;
import android.util.EventLog;
import android.util.Log;
+import android.util.Slog;
import android.webkit.WebViewFactory;
+import dalvik.system.DexFile;
+import dalvik.system.PathClassLoader;
import dalvik.system.VMRuntime;
import libcore.io.IoUtils;
@@ -493,21 +496,69 @@ public class ZygoteInit {
Process.setArgV0(parsedArgs.niceName);
}
+ final String systemServerClasspath = Os.getenv("SYSTEMSERVERCLASSPATH");
+ if (systemServerClasspath != null) {
+ performSystemServerDexOpt(systemServerClasspath);
+ }
+
if (parsedArgs.invokeWith != null) {
+ String[] args = parsedArgs.remainingArgs;
+ // If we have a non-null system server class path, we'll have to duplicate the
+ // existing arguments and append the classpath to it. ART will handle the classpath
+ // correctly when we exec a new process.
+ if (systemServerClasspath != null) {
+ String[] amendedArgs = new String[args.length + 2];
+ amendedArgs[0] = "-cp";
+ amendedArgs[1] = systemServerClasspath;
+ System.arraycopy(parsedArgs.remainingArgs, 0, amendedArgs, 2, parsedArgs.remainingArgs.length);
+ }
+
WrapperInit.execApplication(parsedArgs.invokeWith,
parsedArgs.niceName, parsedArgs.targetSdkVersion,
- null, parsedArgs.remainingArgs);
+ null, args);
} else {
+ ClassLoader cl = null;
+ if (systemServerClasspath != null) {
+ cl = new PathClassLoader(systemServerClasspath, ClassLoader.getSystemClassLoader());
+ Thread.currentThread().setContextClassLoader(cl);
+ }
+
/*
* Pass the remaining arguments to SystemServer.
*/
- RuntimeInit.zygoteInit(parsedArgs.targetSdkVersion, parsedArgs.remainingArgs);
+ RuntimeInit.zygoteInit(parsedArgs.targetSdkVersion, parsedArgs.remainingArgs, cl);
}
/* should never reach here */
}
/**
+ * Performs dex-opt on the elements of {@code classPath}, if needed. We
+ * choose the instruction set of the current runtime.
+ */
+ private static void performSystemServerDexOpt(String classPath) {
+ final String[] classPathElements = classPath.split(":");
+ final InstallerConnection installer = new InstallerConnection();
+ final String instructionSet = VMRuntime.getRuntime().vmInstructionSet();
+
+ try {
+ for (String classPathElement : classPathElements) {
+ final byte dexopt = DexFile.isDexOptNeededInternal(classPathElement, "*", instructionSet,
+ false /* defer */);
+ if (dexopt == DexFile.DEXOPT_NEEDED) {
+ installer.dexopt(classPathElement, Process.SYSTEM_UID, false, instructionSet);
+ } else if (dexopt == DexFile.PATCHOAT_NEEDED) {
+ installer.patchoat(classPathElement, Process.SYSTEM_UID, false, instructionSet);
+ }
+ }
+ } catch (IOException ioe) {
+ throw new RuntimeException("Error starting system_server", ioe);
+ } finally {
+ installer.disconnect();
+ }
+ }
+
+ /**
* Prepare the arguments and fork for the system server process.
*/
private static boolean startSystemServer(String abiList, String socketName)
diff --git a/services/core/java/com/android/server/BootReceiver.java b/core/java/com/android/server/BootReceiver.java
index 724998570cb0..724998570cb0 100644
--- a/services/core/java/com/android/server/BootReceiver.java
+++ b/core/java/com/android/server/BootReceiver.java
diff --git a/core/jni/Android.mk b/core/jni/Android.mk
index 480383b4443e..2106d38ef944 100644
--- a/core/jni/Android.mk
+++ b/core/jni/Android.mk
@@ -246,6 +246,7 @@ LOCAL_SHARED_LIBRARIES := \
libminikin \
libstlport \
libprocessgroup \
+ libnativebridge \
ifeq ($(USE_OPENGL_RENDERER),true)
LOCAL_SHARED_LIBRARIES += libhwui
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index 90c66d7f2a00..79b85421c940 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -161,10 +161,8 @@ extern int register_android_text_AndroidCharacter(JNIEnv *env);
extern int register_android_text_StaticLayout(JNIEnv *env);
extern int register_android_text_AndroidBidi(JNIEnv *env);
extern int register_android_opengl_classes(JNIEnv *env);
-extern int register_android_server_fingerprint_FingerprintService(JNIEnv* env);
-extern int register_android_server_NetworkManagementSocketTagger(JNIEnv* env);
-extern int register_android_server_Watchdog(JNIEnv* env);
extern int register_android_ddm_DdmHandleNativeHeap(JNIEnv *env);
+extern int register_android_server_NetworkManagementSocketTagger(JNIEnv* env);
extern int register_com_android_internal_os_ZygoteInit(JNIEnv* env);
extern int register_android_backup_BackupDataInput(JNIEnv *env);
extern int register_android_backup_BackupDataOutput(JNIEnv *env);
@@ -804,7 +802,7 @@ int AndroidRuntime::startVm(JavaVM** pJavaVM, JNIEnv** pEnv)
"-Xmx", "-Xcompiler-option");
if (skip_compilation) {
addOption("-Xcompiler-option");
- addOption("--compiler-filter=interpret-only");
+ addOption("--compiler-filter=verify-none");
} else {
parseCompilerOption("dalvik.vm.dex2oat-filter", dex2oatCompilerFilterBuf,
"--compiler-filter=", "-Xcompiler-option");
@@ -1338,9 +1336,7 @@ static const RegJNIRec gRegJNI[] = {
REG_JNI(register_android_media_ToneGenerator),
REG_JNI(register_android_opengl_classes),
- REG_JNI(register_android_server_fingerprint_FingerprintService),
REG_JNI(register_android_server_NetworkManagementSocketTagger),
- REG_JNI(register_android_server_Watchdog),
REG_JNI(register_android_ddm_DdmHandleNativeHeap),
REG_JNI(register_android_backup_BackupDataInput),
REG_JNI(register_android_backup_BackupDataOutput),
diff --git a/core/jni/android_app_NativeActivity.cpp b/core/jni/android_app_NativeActivity.cpp
index 9c44093904fb..633a207f8ad8 100644
--- a/core/jni/android_app_NativeActivity.cpp
+++ b/core/jni/android_app_NativeActivity.cpp
@@ -38,6 +38,8 @@
#include "android_view_InputChannel.h"
#include "android_view_KeyEvent.h"
+#include "nativebridge/native_bridge.h"
+
#define LOG_TRACE(...)
//#define LOG_TRACE(...) ALOG(LOG_DEBUG, LOG_TAG, __VA_ARGS__)
@@ -251,17 +253,29 @@ loadNativeCode_native(JNIEnv* env, jobject clazz, jstring path, jstring funcName
const char* pathStr = env->GetStringUTFChars(path, NULL);
NativeCode* code = NULL;
-
+ bool needNativeBridge = false;
+
void* handle = dlopen(pathStr, RTLD_LAZY);
-
+ if (handle == NULL) {
+ if (NativeBridgeIsSupported(pathStr)) {
+ handle = NativeBridgeLoadLibrary(pathStr, RTLD_LAZY);
+ needNativeBridge = true;
+ }
+ }
env->ReleaseStringUTFChars(path, pathStr);
-
+
if (handle != NULL) {
+ void* funcPtr = NULL;
const char* funcStr = env->GetStringUTFChars(funcName, NULL);
- code = new NativeCode(handle, (ANativeActivity_createFunc*)
- dlsym(handle, funcStr));
+ if (needNativeBridge) {
+ funcPtr = NativeBridgeGetTrampoline(handle, funcStr, NULL, 0);
+ } else {
+ funcPtr = dlsym(handle, funcStr);
+ }
+
+ code = new NativeCode(handle, (ANativeActivity_createFunc*)funcPtr);
env->ReleaseStringUTFChars(funcName, funcStr);
-
+
if (code->createActivityFunc == NULL) {
ALOGW("ANativeActivity_onCreate not found");
delete code;
diff --git a/core/jni/android_hardware_camera2_legacy_LegacyCameraDevice.cpp b/core/jni/android_hardware_camera2_legacy_LegacyCameraDevice.cpp
index 697cdc686514..980ead0c8fc1 100644
--- a/core/jni/android_hardware_camera2_legacy_LegacyCameraDevice.cpp
+++ b/core/jni/android_hardware_camera2_legacy_LegacyCameraDevice.cpp
@@ -541,6 +541,15 @@ static jint LegacyCameraDevice_nativeSetSurfaceDimens(JNIEnv* env, jobject thiz,
ALOGE("%s: Error while setting surface dimens %s (%d).", __FUNCTION__, strerror(-err), err);
return err;
}
+
+ // WAR - Set user dimensions also to avoid incorrect scaling after TextureView orientation
+ // change.
+ err = native_window_set_buffers_user_dimensions(anw.get(), width, height);
+ if (err != NO_ERROR) {
+ ALOGE("%s: Error while setting surface user dimens %s (%d).", __FUNCTION__, strerror(-err),
+ err);
+ return err;
+ }
return NO_ERROR;
}
@@ -624,6 +633,11 @@ static jint LegacyCameraDevice_nativeSetNextTimestamp(JNIEnv* env, jobject thiz,
return NO_ERROR;
}
+static jint LegacyCameraDevice_nativeGetJpegFooterSize(JNIEnv* env, jobject thiz) {
+ ALOGV("nativeGetJpegFooterSize");
+ return static_cast<jint>(sizeof(struct camera3_jpeg_blob));
+}
+
} // extern "C"
static JNINativeMethod gCameraDeviceMethods[] = {
@@ -657,6 +671,9 @@ static JNINativeMethod gCameraDeviceMethods[] = {
{ "nativeSetNextTimestamp",
"(Landroid/view/Surface;J)I",
(void *)LegacyCameraDevice_nativeSetNextTimestamp },
+ { "nativeGetJpegFooterSize",
+ "()I",
+ (void *)LegacyCameraDevice_nativeGetJpegFooterSize },
};
// Get all the required offsets in java class and register native functions
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 931d1c656f6f..aee30909182d 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -1257,6 +1257,14 @@
android:description="@string/permdesc_bind_call_service"
android:label="@string/permlab_bind_call_service" />
+ <!-- @SystemApi Allows an application to bind to ConnectionService implementations.
+ @hide -->
+ <permission android:name="android.permission.BIND_CONNECTION_SERVICE"
+ android:permissionGroup="android.permission-group.PHONE_CALLS"
+ android:protectionLevel="system|signature"
+ android:description="@string/permdesc_bind_connection_service"
+ android:label="@string/permlab_bind_connection_service" />
+
<!-- ================================== -->
<!-- Permissions for sdcard interaction -->
<!-- ================================== -->
diff --git a/core/res/res/animator/leanback_setup_fragment_close_enter.xml b/core/res/res/animator/leanback_setup_fragment_close_enter.xml
new file mode 100644
index 000000000000..1626dd34f7b7
--- /dev/null
+++ b/core/res/res/animator/leanback_setup_fragment_close_enter.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** 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.
+*/
+-->
+<set xmlns:android="http://schemas.android.com/apk/res/android">
+ <objectAnimator
+ android:propertyName="alpha"
+ android:valueType="floatType"
+ android:valueFrom="@dimen/leanback_setup_alpha_backward_in_content_start"
+ android:valueTo="@dimen/leanback_setup_alpha_backward_in_content_end"
+ android:duration="@integer/leanback_setup_alpha_backward_in_content_duration"
+ android:startOffset="@integer/leanback_setup_alpha_backward_in_content_delay"/>
+</set>
diff --git a/core/res/res/animator/leanback_setup_fragment_close_exit.xml b/core/res/res/animator/leanback_setup_fragment_close_exit.xml
new file mode 100644
index 000000000000..a827df40213d
--- /dev/null
+++ b/core/res/res/animator/leanback_setup_fragment_close_exit.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** 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.
+*/
+-->
+<set xmlns:android="http://schemas.android.com/apk/res/android">
+ <objectAnimator
+ android:propertyName="alpha"
+ android:valueType="floatType"
+ android:valueFrom="@dimen/leanback_setup_alpha_backward_out_content_start"
+ android:valueTo="@dimen/leanback_setup_alpha_backward_out_content_end"
+ android:duration="@integer/leanback_setup_alpha_backward_out_content_duration"
+ android:startOffset="@integer/leanback_setup_alpha_backward_out_content_delay"/>
+ <objectAnimator
+ android:propertyName="x"
+ android:valueType="floatType"
+ android:valueFrom="@dimen/leanback_setup_translation_backward_out_content_start"
+ android:valueTo="@dimen/leanback_setup_translation_backward_out_content_end"
+ android:duration="@integer/leanback_setup_translation_backward_out_content_duration"
+ android:startOffset="@integer/leanback_setup_translation_backward_out_content_delay"/>
+</set>
diff --git a/core/res/res/animator/leanback_setup_fragment_open_enter.xml b/core/res/res/animator/leanback_setup_fragment_open_enter.xml
new file mode 100644
index 000000000000..34b9a579e6f4
--- /dev/null
+++ b/core/res/res/animator/leanback_setup_fragment_open_enter.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** 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.
+*/
+-->
+<set xmlns:android="http://schemas.android.com/apk/res/android" >
+ <objectAnimator
+ android:propertyName="alpha"
+ android:valueType="floatType"
+ android:valueFrom="@dimen/leanback_setup_alpha_forward_in_content_start"
+ android:valueTo="@dimen/leanback_setup_alpha_forward_in_content_end"
+ android:duration="@integer/leanback_setup_alpha_forward_in_content_duration"
+ android:startOffset="@integer/leanback_setup_alpha_forward_in_content_delay"/>
+ <objectAnimator
+ android:propertyName="x"
+ android:valueType="floatType"
+ android:valueFrom="@dimen/leanback_setup_translation_forward_in_content_start"
+ android:valueTo="@dimen/leanback_setup_translation_forward_in_content_end"
+ android:duration="@integer/leanback_setup_translation_forward_in_content_duration"
+ android:startOffset="@integer/leanback_setup_translation_forward_in_content_delay" />
+</set>
diff --git a/core/res/res/animator/leanback_setup_fragment_open_exit.xml b/core/res/res/animator/leanback_setup_fragment_open_exit.xml
new file mode 100644
index 000000000000..5622db488981
--- /dev/null
+++ b/core/res/res/animator/leanback_setup_fragment_open_exit.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** 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.
+*/
+-->
+<set xmlns:android="http://schemas.android.com/apk/res/android">
+ <objectAnimator
+ android:propertyName="alpha"
+ android:valueType="floatType"
+ android:valueFrom="@dimen/leanback_setup_alpha_forward_out_content_start"
+ android:valueTo="@dimen/leanback_setup_alpha_forward_out_content_end"
+ android:duration="@integer/leanback_setup_alpha_forward_out_content_duration"
+ android:startOffset="@integer/leanback_setup_alpha_forward_out_content_delay"/>
+</set>
diff --git a/core/res/res/drawable-hdpi/spinner_textfield_activated_mtrl_alpha.9.png b/core/res/res/drawable-hdpi/spinner_textfield_activated_mtrl_alpha.9.png
new file mode 100644
index 000000000000..8af9ceb4bacf
--- /dev/null
+++ b/core/res/res/drawable-hdpi/spinner_textfield_activated_mtrl_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/spinner_textfield_default_mtrl_alpha.9.png b/core/res/res/drawable-hdpi/spinner_textfield_default_mtrl_alpha.9.png
new file mode 100644
index 000000000000..81c78c66ac41
--- /dev/null
+++ b/core/res/res/drawable-hdpi/spinner_textfield_default_mtrl_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/spinner_textfield_activated_mtrl_alpha.9.png b/core/res/res/drawable-mdpi/spinner_textfield_activated_mtrl_alpha.9.png
new file mode 100644
index 000000000000..22992c047c98
--- /dev/null
+++ b/core/res/res/drawable-mdpi/spinner_textfield_activated_mtrl_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/spinner_textfield_default_mtrl_alpha.9.png b/core/res/res/drawable-mdpi/spinner_textfield_default_mtrl_alpha.9.png
new file mode 100644
index 000000000000..f44a2c252deb
--- /dev/null
+++ b/core/res/res/drawable-mdpi/spinner_textfield_default_mtrl_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/spinner_textfield_activated_mtrl_alpha.9.png b/core/res/res/drawable-xhdpi/spinner_textfield_activated_mtrl_alpha.9.png
new file mode 100644
index 000000000000..2d79d596cb29
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/spinner_textfield_activated_mtrl_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/spinner_textfield_default_mtrl_alpha.9.png b/core/res/res/drawable-xhdpi/spinner_textfield_default_mtrl_alpha.9.png
new file mode 100644
index 000000000000..36f975390ef5
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/spinner_textfield_default_mtrl_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/spinner_textfield_activated_mtrl_alpha.9.png b/core/res/res/drawable-xxhdpi/spinner_textfield_activated_mtrl_alpha.9.png
new file mode 100644
index 000000000000..9c0b19e0674f
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/spinner_textfield_activated_mtrl_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/spinner_textfield_default_mtrl_alpha.9.png b/core/res/res/drawable-xxhdpi/spinner_textfield_default_mtrl_alpha.9.png
new file mode 100644
index 000000000000..0edb4b8ceaa6
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/spinner_textfield_default_mtrl_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/spinner_textfield_activated_mtrl_alpha.9.png b/core/res/res/drawable-xxxhdpi/spinner_textfield_activated_mtrl_alpha.9.png
new file mode 100644
index 000000000000..78c5ebd597e8
--- /dev/null
+++ b/core/res/res/drawable-xxxhdpi/spinner_textfield_activated_mtrl_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/spinner_textfield_default_mtrl_alpha.9.png b/core/res/res/drawable-xxxhdpi/spinner_textfield_default_mtrl_alpha.9.png
new file mode 100644
index 000000000000..36974b7c1508
--- /dev/null
+++ b/core/res/res/drawable-xxxhdpi/spinner_textfield_default_mtrl_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable/spinner_textfield_background_material.xml b/core/res/res/drawable/spinner_textfield_background_material.xml
new file mode 100644
index 000000000000..f818baf13089
--- /dev/null
+++ b/core/res/res/drawable/spinner_textfield_background_material.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:autoMirrored="true">
+ <item android:state_checked="true">
+ <nine-patch android:src="@drawable/spinner_textfield_activated_mtrl_alpha"
+ android:tint="?attr/colorControlActivated" />
+ </item>
+ <item android:state_pressed="true">
+ <nine-patch android:src="@drawable/spinner_textfield_activated_mtrl_alpha"
+ android:tint="?attr/colorControlActivated" />
+ </item>
+ <item>
+ <nine-patch android:src="@drawable/spinner_textfield_default_mtrl_alpha"
+ android:tint="?attr/colorControlNormal" />
+ </item>
+</selector>
diff --git a/core/res/res/layout-land/date_picker_holo.xml b/core/res/res/layout-land/date_picker_holo.xml
index af8f59853462..9a9b8b0ec380 100644
--- a/core/res/res/layout-land/date_picker_holo.xml
+++ b/core/res/res/layout-land/date_picker_holo.xml
@@ -20,26 +20,11 @@
android:gravity="center"
android:orientation="horizontal" >
- <LinearLayout
- android:layout_width="wrap_content"
- android:layout_height="match_parent"
- android:layout_gravity="center"
- android:orientation="vertical" >
-
- <LinearLayout
- android:layout_width="wrap_content"
- android:layout_height="0dip"
- android:layout_weight="1"
- android:orientation="vertical" >
-
- <include layout="@layout/date_picker_header_view" />
-
- <include layout="@layout/date_picker_selected_date" />
- </LinearLayout>
-
- <include layout="@layout/date_picker_done_button" />
- </LinearLayout>
+ <include
+ layout="@layout/date_picker_selected_date"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent" />
<include layout="@layout/date_picker_view_animator" />
-</LinearLayout> \ No newline at end of file
+</LinearLayout>
diff --git a/core/res/res/layout-land/time_picker_holo.xml b/core/res/res/layout-land/time_picker_holo.xml
index 1725ddc26365..3b3d63c0b14c 100644
--- a/core/res/res/layout-land/time_picker_holo.xml
+++ b/core/res/res/layout-land/time_picker_holo.xml
@@ -30,39 +30,18 @@
android:layout_width="@dimen/timepicker_left_side_width"
android:layout_height="match_parent"
android:orientation="vertical">
- <FrameLayout
+ <include
+ layout="@layout/time_header_label"
android:layout_width="match_parent"
android:layout_height="0dip"
- android:layout_weight="1">
- <include
- layout="@layout/time_header_label"
- android:layout_width="match_parent"
- android:layout_height="@dimen/timepicker_header_height"
- android:layout_gravity="center" />
- </FrameLayout>
- <LinearLayout
- android:id="@+id/layout_buttons"
- style="?android:attr/buttonBarStyle"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="vertical"
- android:divider="?android:attr/dividerHorizontal"
- android:showDividers="beginning">
- <Button
- android:id="@+id/done_button"
- style="?android:attr/buttonBarButtonStyle"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:minHeight="48dp"
- android:text="@string/done_label"
- android:textSize="@dimen/timepicker_done_label_size" />
- </LinearLayout>
+ android:layout_weight="1"
+ android:layout_gravity="center" />
</LinearLayout>
<android.widget.RadialTimePickerView
- android:id="@+id/radial_picker"
- android:layout_width="@dimen/timepicker_radial_picker_dimen"
- android:layout_height="match_parent"
- android:layout_gravity="center"
- android:focusable="true"
- android:focusableInTouchMode="true" />
-</LinearLayout> \ No newline at end of file
+ android:id="@+id/radial_picker"
+ android:layout_width="@dimen/timepicker_radial_picker_dimen"
+ android:layout_height="match_parent"
+ android:layout_gravity="center"
+ android:focusable="true"
+ android:focusableInTouchMode="true" />
+</LinearLayout>
diff --git a/core/res/res/layout-sw600dp/date_picker_holo.xml b/core/res/res/layout-sw600dp/date_picker_holo.xml
index 847aa3226ca1..e5c886bbd0c7 100644
--- a/core/res/res/layout-sw600dp/date_picker_holo.xml
+++ b/core/res/res/layout-sw600dp/date_picker_holo.xml
@@ -17,22 +17,14 @@
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="match_parent"
- android:background="@color/datepicker_default_view_animator_color_holo_light"
android:gravity="center"
android:orientation="vertical" >
- <LinearLayout
- android:layout_width="wrap_content"
- android:layout_height="@dimen/datepicker_selected_calendar_layout_height"
- android:orientation="vertical" >
-
- <include layout="@layout/date_picker_header_view" />
-
- <include layout="@layout/date_picker_selected_date" />
- </LinearLayout>
+ <include
+ layout="@layout/date_picker_selected_date"
+ android:layout_width="wrap_content"
+ android:layout_height="@dimen/datepicker_selected_calendar_layout_height" />
<include layout="@layout/date_picker_view_animator" />
- <include layout="@layout/date_picker_done_button" />
-
-</LinearLayout> \ No newline at end of file
+</LinearLayout>
diff --git a/core/res/res/layout/alert_dialog_material.xml b/core/res/res/layout/alert_dialog_material.xml
index 6a435b25d927..c3f9c769f547 100644
--- a/core/res/res/layout/alert_dialog_material.xml
+++ b/core/res/res/layout/alert_dialog_material.xml
@@ -68,7 +68,8 @@
android:layout_height="wrap_content"
android:paddingStart="16dip"
android:paddingEnd="16dip"
- android:paddingTop="16dip" />
+ android:paddingTop="16dip"
+ android:paddingBottom="16dip" />
</ScrollView>
</LinearLayout>
@@ -83,14 +84,12 @@
</FrameLayout>
<LinearLayout android:id="@+id/buttonPanel"
+ style="?attr/buttonBarStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:minHeight="@dimen/alert_dialog_button_bar_height"
android:orientation="vertical"
- android:gravity="end"
- android:padding="16dip">
+ android:gravity="end">
<LinearLayout
- style="?attr/buttonBarStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layoutDirection="locale">
diff --git a/core/res/res/layout/date_picker_done_button.xml b/core/res/res/layout/date_picker_done_button.xml
deleted file mode 100644
index b8e8c03b64f8..000000000000
--- a/core/res/res/layout/date_picker_done_button.xml
+++ /dev/null
@@ -1,33 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- 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.
--->
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/layout_buttons"
- style="?android:attr/buttonBarStyle"
- android:layout_width="@dimen/datepicker_component_width"
- android:layout_height="wrap_content"
- android:orientation="vertical"
- android:divider="?android:attr/dividerHorizontal"
- android:showDividers="beginning" >
-
- <Button
- android:id="@+id/done"
- style="?android:attr/buttonBarButtonStyle"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:minHeight="48dp"
- android:text="@string/done_label"
- android:textSize="@dimen/datepicker_done_label_size" />
-</LinearLayout>
diff --git a/core/res/res/layout/date_picker_header_view.xml b/core/res/res/layout/date_picker_header_view.xml
deleted file mode 100644
index 66d5e1bf30dc..000000000000
--- a/core/res/res/layout/date_picker_header_view.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- 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.
--->
-<TextView xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/date_picker_header"
- android:layout_width="@dimen/datepicker_component_width"
- android:layout_height="@dimen/datepicker_header_height"
- android:gravity="center"
- android:importantForAccessibility="no"
- android:textAllCaps="true" />
diff --git a/core/res/res/layout/date_picker_holo.xml b/core/res/res/layout/date_picker_holo.xml
index 1199a7205649..72030ea209a5 100644
--- a/core/res/res/layout/date_picker_holo.xml
+++ b/core/res/res/layout/date_picker_holo.xml
@@ -20,18 +20,11 @@
android:gravity="center"
android:orientation="vertical">
- <LinearLayout
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:orientation="vertical">
-
- <include layout="@layout/date_picker_header_view" />
-
- <include layout="@layout/date_picker_selected_date" />
- </LinearLayout>
+ <include
+ layout="@layout/date_picker_selected_date"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content" />
<include layout="@layout/date_picker_view_animator" />
- <include layout="@layout/date_picker_done_button" />
-
</LinearLayout>
diff --git a/core/res/res/layout/date_picker_selected_date.xml b/core/res/res/layout/date_picker_selected_date.xml
index c5afddc1d326..23ae08f90cc0 100644
--- a/core/res/res/layout/date_picker_selected_date.xml
+++ b/core/res/res/layout/date_picker_selected_date.xml
@@ -16,46 +16,53 @@
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/day_picker_selector_layout"
- android:layout_width="@dimen/datepicker_component_width"
- android:layout_height="0dip"
- android:layout_weight="1"
- android:paddingTop="8dip"
- android:paddingBottom="8dip"
- android:gravity="center"
- android:orientation="vertical">
+ android:id="@+id/day_picker_selector_layout"
+ android:layout_width="@dimen/datepicker_component_width"
+ android:layout_height="wrap_content"
+ android:gravity="center"
+ android:paddingBottom="8dp"
+ android:orientation="vertical">
+
+ <TextView
+ android:id="@+id/date_picker_header"
+ android:layout_width="@dimen/datepicker_component_width"
+ android:layout_height="@dimen/datepicker_header_height"
+ android:gravity="center"
+ android:importantForAccessibility="no"
+ android:layout_marginBottom="8dp" />
<LinearLayout
- android:id="@+id/date_picker_month_and_day_layout"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_gravity="center"
- android:clickable="true"
- android:orientation="vertical">
+ android:id="@+id/date_picker_month_and_day_layout"
+ android:layout_width="match_parent"
+ android:layout_height="0dp"
+ android:layout_weight="1"
+ android:layout_gravity="center"
+ android:clickable="true"
+ android:orientation="vertical">
<TextView
- android:id="@+id/date_picker_month"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:duplicateParentState="true"
- android:gravity="center_horizontal|bottom" />
+ android:id="@+id/date_picker_month"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:duplicateParentState="true"
+ android:gravity="center_horizontal|bottom" />
<TextView
- android:id="@+id/date_picker_day"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_gravity="center"
- android:layout_marginBottom="-10dip"
- android:layout_marginTop="-10dip"
- android:duplicateParentState="true"
- android:gravity="center" />
- </LinearLayout>
-
- <TextView
- android:id="@+id/date_picker_year"
+ android:id="@+id/date_picker_day"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
- android:gravity="center_horizontal|top" />
+ android:layout_marginBottom="-10dip"
+ android:layout_marginTop="-10dip"
+ android:duplicateParentState="true"
+ android:gravity="center" />
+ </LinearLayout>
+
+ <TextView
+ android:id="@+id/date_picker_year"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"
+ android:gravity="center_horizontal|top" />
</LinearLayout>
diff --git a/core/res/res/layout/time_header_label.xml b/core/res/res/layout/time_header_label.xml
index 45c62413f4bf..5c970402cc12 100644
--- a/core/res/res/layout/time_header_label.xml
+++ b/core/res/res/layout/time_header_label.xml
@@ -14,20 +14,21 @@
~ See the License for the specific language governing permissions and
~ limitations under the License
-->
-<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/time_header"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:layout_gravity="center" >
-
- <TextView
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/time_header"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+ <RelativeLayout
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_gravity="center">
+ <TextView
android:id="@+id/hours"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toLeftOf="@+id/separator"
- android:layout_alignBaseline="@+id/separator"/>
-
- <TextView
+ android:layout_alignBaseline="@+id/separator" />
+ <TextView
android:id="@+id/separator"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
@@ -35,15 +36,13 @@
android:paddingRight="@dimen/timepicker_separator_padding"
android:layout_centerInParent="true"
android:importantForAccessibility="no" />
-
- <TextView
+ <TextView
android:id="@+id/minutes"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toRightOf="@+id/separator"
android:layout_alignBaseline="@+id/separator" />
-
- <TextView
+ <TextView
android:id="@+id/ampm_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
@@ -51,5 +50,5 @@
android:paddingRight="@dimen/timepicker_ampm_left_padding"
android:layout_toRightOf="@+id/separator"
android:layout_alignBaseline="@+id/separator" />
-
-</RelativeLayout>
+ </RelativeLayout>
+</FrameLayout>
diff --git a/core/res/res/layout/time_picker_dialog.xml b/core/res/res/layout/time_picker_dialog.xml
index 09326c86c399..30fe91093c46 100644
--- a/core/res/res/layout/time_picker_dialog.xml
+++ b/core/res/res/layout/time_picker_dialog.xml
@@ -21,5 +21,4 @@
android:id="@+id/timePicker"
android:layout_gravity="center_horizontal"
android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- />
+ android:layout_height="wrap_content" />
diff --git a/core/res/res/layout/time_picker_holo.xml b/core/res/res/layout/time_picker_holo.xml
index 0890fe574367..483eb6db9f8d 100644
--- a/core/res/res/layout/time_picker_holo.xml
+++ b/core/res/res/layout/time_picker_holo.xml
@@ -34,21 +34,4 @@
android:layout_gravity="center"
android:focusable="true"
android:focusableInTouchMode="true" />
- <LinearLayout
- android:id="@+id/layout_buttons"
- style="?android:attr/buttonBarStyle"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="vertical"
- android:divider="?android:attr/dividerHorizontal"
- android:showDividers="beginning">
- <Button
- android:id="@+id/done_button"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:minHeight="48dp"
- android:text="@string/done_label"
- android:textSize="@dimen/timepicker_done_label_size"
- style="?android:attr/buttonBarButtonStyle" />
- </LinearLayout>
</LinearLayout>
diff --git a/core/res/res/layout/time_picker_legacy_leanback.xml b/core/res/res/layout/time_picker_legacy_leanback.xml
index 397f73344bd9..b4e5e3eb1879 100644
--- a/core/res/res/layout/time_picker_legacy_leanback.xml
+++ b/core/res/res/layout/time_picker_legacy_leanback.xml
@@ -79,14 +79,4 @@
android:focusableInTouchMode="true"
/>
- <!-- Width fixed here because TextView doesn't set MEASURED_STATE_TOO_SMALL -->
- <Button
- android:id="@+id/done_button"
- android:layout_width="100dp"
- android:layout_height="wrap_content"
- android:layout_gravity="center_vertical"
- android:text="@string/done_label"
- android:textSize="@dimen/timepicker_done_label_size"
- style="?android:attr/buttonBarButtonStyle" />
-
</LinearLayout>
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index c268d974c718..7d4c37ef3d6c 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -1250,7 +1250,9 @@
application.
<p>This appears as a child tag of the root
- {@link #AndroidManifest manifest} tag. -->
+ {@link #AndroidManifest manifest} tag.
+
+ @deprecated Use <code>feature-group</code> instead.-->
<declare-styleable name="AndroidManifestUsesConfiguration" parent="AndroidManifest">
<!-- The type of touch screen used by an application. -->
<attr name="reqTouchScreen" />
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index 9d6c36dd1c57..a29a34c2a45f 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -355,7 +355,6 @@
<dimen name="timepicker_time_label_size">60sp</dimen>
<dimen name="timepicker_extra_time_label_margin">-30dp</dimen>
<dimen name="timepicker_ampm_label_size">16sp</dimen>
- <dimen name="timepicker_done_label_size">14sp</dimen>
<dimen name="timepicker_ampm_left_padding">6dip</dimen>
<dimen name="timepicker_separator_padding">4dip</dimen>
<dimen name="timepicker_header_height">96dip</dimen>
@@ -363,13 +362,14 @@
<dimen name="timepicker_minimum_margin_top_bottom">24dip</dimen>
<dimen name="timepicker_radial_picker_dimen">270dip</dimen>
- <dimen name="datepicker_done_label_size">14sp</dimen>
- <dimen name="datepicker_day_number_size">16sp</dimen>
+ <!-- Used by SimpleMonthView -->
+ <dimen name="datepicker_day_number_size">12sp</dimen>
<dimen name="datepicker_month_label_size">16sp</dimen>
- <dimen name="datepicker_month_day_label_text_size">10sp</dimen>
+ <dimen name="datepicker_month_day_label_text_size">12sp</dimen>
+ <dimen name="datepicker_month_list_item_header_height">48dp</dimen>
<dimen name="datepicker_day_number_select_circle_radius">16dp</dimen>
- <dimen name="datepicker_month_list_item_header_height">50dp</dimen>
- <dimen name="datepicker_view_animator_height">270dp</dimen>
+ <dimen name="datepicker_view_animator_height">250dp</dimen>
+
<dimen name="datepicker_year_picker_padding_top">8dp</dimen>
<dimen name="datepicker_year_label_height">64dp</dimen>
<dimen name="datepicker_year_label_text_size">22dp</dimen>
diff --git a/core/res/res/values/dimens_leanback.xml b/core/res/res/values/dimens_leanback.xml
index fb5f8f09b51e..c824a2a79f83 100644
--- a/core/res/res/values/dimens_leanback.xml
+++ b/core/res/res/values/dimens_leanback.xml
@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="utf-8"?>
+<?xml version="1.0" encoding="UTF-8"?>
<!-- Copyright (C) 2014 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
@@ -13,7 +13,74 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<resources>
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android">
<!-- Default alpha value for disabled elements. -->
<item name="disabled_alpha_leanback_formwizard" format="float" type="dimen">0.2</item>
+ <!-- The duration of most animations related to screen content transitions -->
+ <integer name="leanback_setup_base_animation_duration">500</integer>
+ <item name="leanback_setup_alpha_animiation_max_opacity" format="float" type="dimen">1.0</item>
+ <item name="leanback_setup_alpha_animiation_min_opacity" format="float" type="dimen">0.0</item>
+ <!-- Where stable, on-screen content rests -->
+ <dimen name="leanback_setup_translation_content_resting_point">0dp</dimen>
+ <integer name="leanback_setup_translation_content_resting_point_v4">0</integer>
+ <!-- The screen position at which content enters/exits. If you're over the edge of the cliff, we can't see you. -->
+ <dimen name="leanback_setup_translation_content_cliff">100dp</dimen>
+ <integer name="leanback_setup_translation_content_cliff_v4">200</integer>
+
+ <!-- Opacity animation for activity background -->
+ <!-- The opacity of the background of the new activity background when the alpha animation starts-->
+ <item name="leanback_setup_alpha_activity_in_bkg_start" format="float" type="dimen">@dimen/leanback_setup_alpha_animiation_min_opacity</item>
+ <!-- The opacity of the background of the new activity background when the alpha animation ends-->
+ <item name="leanback_setup_alpha_activity_in_bkg_end" format="float" type="dimen">@dimen/leanback_setup_alpha_animiation_max_opacity</item>
+ <integer name="leanback_setup_alpha_activity_in_bkg_delay">0</integer>
+ <integer name="leanback_setup_alpha_activity_in_bkg_duration">@integer/leanback_setup_base_animation_duration</integer>
+
+ <item name="leanback_setup_alpha_activity_out_bkg_start" format="float" type="dimen">@dimen/leanback_setup_alpha_animiation_max_opacity</item>
+ <!-- The opacity of the background of the new activity background when the alpha animation ends-->
+ <item name="leanback_setup_alpha_activity_out_bkg_end" format="float" type="dimen">@dimen/leanback_setup_alpha_animiation_min_opacity</item>
+ <integer name="leanback_setup_alpha_activity_out_bkg_delay">0</integer>
+ <integer name="leanback_setup_alpha_activity_out_bkg_duration">@integer/leanback_setup_base_animation_duration</integer>
+
+ <!-- Content forward animation configuration values -->
+ <!-- Parameter for alpha animation of new content coming on to the screen when we're moving "forward" -->
+ <!-- Initial opacity of the new content that is coming on to the screen -->
+ <item name="leanback_setup_alpha_forward_in_content_start" format="float" type="dimen">@dimen/leanback_setup_alpha_animiation_min_opacity</item>
+ <item name="leanback_setup_alpha_forward_in_content_end" format="float" type="dimen">@dimen/leanback_setup_alpha_animiation_max_opacity</item>
+ <integer name="leanback_setup_alpha_forward_in_content_delay">0</integer>
+ <integer name="leanback_setup_alpha_forward_in_content_duration">@integer/leanback_setup_base_animation_duration</integer>
+
+ <item name="leanback_setup_alpha_forward_out_content_start" format="float" type="dimen">@dimen/leanback_setup_alpha_animiation_max_opacity</item>
+ <item name="leanback_setup_alpha_forward_out_content_end" format="float" type="dimen">@dimen/leanback_setup_alpha_animiation_min_opacity</item>
+ <integer name="leanback_setup_alpha_forward_out_content_delay">0</integer>
+ <integer name="leanback_setup_alpha_forward_out_content_duration">@integer/leanback_setup_base_animation_duration</integer>
+
+ <!-- Position animation of incoming content during a "forward" transition -->
+ <dimen name="leanback_setup_translation_forward_in_content_start">@dimen/leanback_setup_translation_content_cliff</dimen>
+ <dimen name="leanback_setup_translation_forward_in_content_start_v4">@integer/leanback_setup_translation_content_cliff_v4</dimen>
+ <dimen name="leanback_setup_translation_forward_in_content_end">@dimen/leanback_setup_translation_content_resting_point</dimen>
+ <dimen name="leanback_setup_translation_forward_in_content_end_v4">@integer/leanback_setup_translation_content_resting_point_v4</dimen>
+ <integer name="leanback_setup_translation_forward_in_content_delay">0</integer>
+ <integer name="leanback_setup_translation_forward_in_content_duration">@integer/leanback_setup_base_animation_duration</integer>
+
+ <!-- Content backward animation configuration values -->
+ <!-- Alpha animation values for the content that will be displayed after the transition is complete, this is the content coming in. -->
+ <item name="leanback_setup_alpha_backward_in_content_start" format="float" type="dimen">@dimen/leanback_setup_alpha_animiation_min_opacity</item>
+ <item name="leanback_setup_alpha_backward_in_content_end" format="float" type="dimen">@dimen/leanback_setup_alpha_animiation_max_opacity</item>
+ <integer name="leanback_setup_alpha_backward_in_content_delay">0</integer>
+ <integer name="leanback_setup_alpha_backward_in_content_duration">@integer/leanback_setup_base_animation_duration</integer>
+
+ <!-- Alpha animiation values for the content that is displayed when the transition starts, this is the content going away. -->
+ <item name="leanback_setup_alpha_backward_out_content_start" format="float" type="dimen">@dimen/leanback_setup_alpha_animiation_max_opacity</item>
+ <item name="leanback_setup_alpha_backward_out_content_end" format="float" type="dimen">@dimen/leanback_setup_alpha_animiation_min_opacity</item>
+ <integer name="leanback_setup_alpha_backward_out_content_delay">0</integer>
+ <integer name="leanback_setup_alpha_backward_out_content_duration">@integer/leanback_setup_base_animation_duration</integer>
+
+ <!-- Position animation for content that is displayed when the transition starts, this is the content going away. -->
+ <dimen name="leanback_setup_translation_backward_out_content_start">@dimen/leanback_setup_translation_content_resting_point</dimen>
+ <dimen name="leanback_setup_translation_backward_out_content_start_v4">@integer/leanback_setup_translation_content_resting_point_v4</dimen>
+ <dimen name="leanback_setup_translation_backward_out_content_end">@dimen/leanback_setup_translation_content_cliff</dimen>
+ <dimen name="leanback_setup_translation_backward_out_content_end_v4">@integer/leanback_setup_translation_content_cliff_v4</dimen>
+ <integer name="leanback_setup_translation_backward_out_content_delay">0</integer>
+ <integer name="leanback_setup_translation_backward_out_content_duration">@integer/leanback_setup_base_animation_duration</integer>
</resources>
diff --git a/core/res/res/values/dimens_material.xml b/core/res/res/values/dimens_material.xml
index c21dc59a28c7..e5a3c17ea8fd 100644
--- a/core/res/res/values/dimens_material.xml
+++ b/core/res/res/values/dimens_material.xml
@@ -42,10 +42,10 @@
<dimen name="text_size_headline_material">24sp</dimen>
<dimen name="text_size_title_material">20sp</dimen>
<dimen name="text_size_subhead_material">16sp</dimen>
+ <dimen name="text_size_menu_material">16sp</dimen>
<dimen name="text_size_body_2_material">14sp</dimen>
<dimen name="text_size_body_1_material">14sp</dimen>
<dimen name="text_size_caption_material">12sp</dimen>
- <dimen name="text_size_menu_material">14sp</dimen>
<dimen name="text_size_button_material">14sp</dimen>
<dimen name="text_size_large_material">22sp</dimen>
diff --git a/core/res/res/values/donottranslate_material.xml b/core/res/res/values/donottranslate_material.xml
index 9ed955368524..9cf9f6cfa86d 100644
--- a/core/res/res/values/donottranslate_material.xml
+++ b/core/res/res/values/donottranslate_material.xml
@@ -23,10 +23,10 @@
<string name="font_family_headline_material">sans-serif</string>
<string name="font_family_title_material">sans-serif-medium</string>
<string name="font_family_subhead_material">sans-serif</string>
+ <string name="font_family_menu_material">sans-serif</string>
<string name="font_family_body_2_material">sans-serif-medium</string>
<string name="font_family_body_1_material">sans-serif</string>
<string name="font_family_caption_material">sans-serif</string>
- <string name="font_family_menu_material">sans-serif-medium</string>
<string name="font_family_button_material">sans-serif-medium</string>
</resources>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index e894a9cb47e9..c8edad045be3 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2518,6 +2518,19 @@
<public type="style" name="Widget.Material.Button.Borderless.Colored" />
<public type="style" name="Widget.Material.Light.Button.Borderless.Colored" />
+ <public type="style" name="Theme.Leanback.FormWizard"/>
+
+ <public type="style" name="TextAppearance.StatusBar.Material" />
+ <public type="style" name="TextAppearance.StatusBar.Material.EventContent" />
+ <public type="style" name="TextAppearance.StatusBar.Material.EventContent.Title" />
+ <public type="style" name="TextAppearance.StatusBar.Material.EventContent.Line2" />
+ <public type="style" name="TextAppearance.StatusBar.Material.EventContent.Info" />
+ <public type="style" name="TextAppearance.StatusBar.Material.EventContent.Time" />
+ <public type="style" name="TextAppearance.StatusBar.Material.EventContent.Emphasis" />
+
+ <public type="style" name="Widget.Material.Spinner.Form" />
+ <public type="style" name="Widget.Material.Light.Spinner.Form" />
+
<public-padding type="string" name="l_resource_pad" end="0x01040030" />
<public type="string" name="config_webSettingsDefaultTextEncoding" />
@@ -2528,8 +2541,6 @@
<public-padding type="interpolator" name="l_resource_pad" end="0x010c0010" />
- <public type="style" name="Theme.Leanback.FormWizard"/>
-
<!-- An interpolator which accelerates fast but decelerates slowly. -->
<public type="interpolator" name="fast_out_slow_in" />
<!-- An interpolator which starts with a peak non-zero velocity and decelerates slowly. -->
@@ -2564,23 +2575,4 @@
<public type="raw" name="loaderror" id="0x01100000"/>
<!-- WebView error page for when domain lookup fails. @hide @SystemApi -->
<public type="raw" name="nodomain"/>
-
- <!-- Base text appearance for SystemUI elements -->
- <public type="style" name="TextAppearance.StatusBar.Material" />
- <!-- Base text appearance for notifications -->
- <public type="style" name="TextAppearance.StatusBar.Material.EventContent" />
- <!-- Notification text appearance: title -->
- <public type="style" name="TextAppearance.StatusBar.Material.EventContent.Title" />
- <!-- Notification text appearance: additional line of text sandwiched
- between the title and content -->
- <public type="style" name="TextAppearance.StatusBar.Material.EventContent.Line2" />
- <!-- Notification text appearance: an annotation, e.g. the
- number of messages in your inbox -->
- <public type="style" name="TextAppearance.StatusBar.Material.EventContent.Info" />
- <!-- Notification text appearance: timestamp -->
- <public type="style" name="TextAppearance.StatusBar.Material.EventContent.Time" />
- <!-- Notification text appearance: a way to highlight a bit of text (for
- example, to separate the sender from the subject of an email if they
- are all on the same line) -->
- <public type="style" name="TextAppearance.StatusBar.Material.EventContent.Emphasis" />
</resources>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 74992ed4a82e..6262f13e7814 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -2117,6 +2117,11 @@
<string name="permdesc_bind_call_service">Allows the app to control when and how the user sees the in-call screen.</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_bind_connection_service">interact with telephony services</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_bind_connection_service">Allows the app to interact with telephony services to make/receive calls.</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_readNetworkUsageHistory">read historical network usage</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_readNetworkUsageHistory">Allows the app to read historical network usage for specific networks and apps.</string>
@@ -5523,4 +5528,7 @@
<!-- [CHAR_LIMIT=NONE] Battery saver: Feature description -->
<string name="battery_saver_description">To help improve battery life, battery saver reduces your device’s performance and limits vibration and most background data. Email, messaging, and other apps that rely on syncing may not update unless you open them.\n\nBattery saver turns off automatically when your device is charging</string>
+
+ <!-- [CHAR_LIMIT=NONE] Zen mode: Condition summary for built-in downtime condition, if active -->
+ <string name="downtime_condition_summary">Until your downtime ends at <xliff:g id="formattedTime" example="10.00 PM">%1$s</xliff:g></string>
</resources>
diff --git a/core/res/res/values/styles_leanback.xml b/core/res/res/values/styles_leanback.xml
index 72735f759f43..da83c363a517 100644
--- a/core/res/res/values/styles_leanback.xml
+++ b/core/res/res/values/styles_leanback.xml
@@ -65,4 +65,10 @@
<item name="fontFamily">sans-serif-condensed</item>
</style>
+ <style name="WindowAnimationStyle.Leanback.Setup" parent="@style/Animation.Material.Activity">
+ <item name="android:fragmentOpenEnterAnimation">@animator/leanback_setup_fragment_open_enter</item>
+ <item name="android:fragmentOpenExitAnimation">@animator/leanback_setup_fragment_open_exit</item>
+ <item name="android:fragmentCloseEnterAnimation">@animator/leanback_setup_fragment_close_enter</item>
+ <item name="android:fragmentCloseExitAnimation">@animator/leanback_setup_fragment_close_exit</item>
+ </style>
</resources>
diff --git a/core/res/res/values/styles_material.xml b/core/res/res/values/styles_material.xml
index f028222b50a7..0f2782454ef9 100644
--- a/core/res/res/values/styles_material.xml
+++ b/core/res/res/values/styles_material.xml
@@ -343,37 +343,37 @@ please see styles_device_defaults.xml.
<style name="TextAppearance.Material.TimePicker.TimeLabel" parent="TextAppearance.Material">
<item name="textSize">@dimen/timepicker_time_label_size</item>
- <item name="textColor">?attr/textColorPrimary</item>
+ <item name="textColor">?attr/textColorSecondaryInverse</item>
</style>
<style name="TextAppearance.Material.TimePicker.AmPmLabel" parent="TextAppearance.Material">
<item name="textSize">@dimen/timepicker_ampm_label_size</item>
<item name="textAllCaps">true</item>
- <item name="textColor">?attr/textColorPrimary</item>
+ <item name="textColor">?attr/textColorSecondaryInverse</item>
<item name="textStyle">bold</item>
</style>
<style name="TextAppearance.Material.DatePicker.DayOfWeekLabel" parent="TextAppearance.Material">
<item name="includeFontPadding">false</item>
- <item name="textColor">?attr/textColorPrimary</item>
+ <item name="textColor">?attr/textColorPrimaryInverse</item>
<item name="textSize">@dimen/datepicker_header_text_size</item>
</style>
<style name="TextAppearance.Material.DatePicker.MonthLabel" parent="TextAppearance.Material">
<item name="includeFontPadding">false</item>
- <item name="textColor">?attr/textColorPrimary</item> <!-- selected should be accent -->
+ <item name="textColor">?attr/textColorSecondaryInverse</item> <!-- selected should be accent -->
<item name="textSize">@dimen/datepicker_selected_date_month_size</item>
</style>
<style name="TextAppearance.Material.DatePicker.DayOfMonthLabel" parent="TextAppearance.Material">
<item name="includeFontPadding">false</item>
- <item name="textColor">?attr/textColorPrimary</item> <!-- selected should be accent -->
+ <item name="textColor">?attr/textColorSecondaryInverse</item> <!-- selected should be accent -->
<item name="textSize">@dimen/datepicker_selected_date_day_size</item>
</style>
<style name="TextAppearance.Material.DatePicker.YearLabel" parent="TextAppearance.Material">
<item name="includeFontPadding">false</item>
- <item name="textColor">?attr/textColorPrimary</item> <!-- selected should be accent -->
+ <item name="textColor">?attr/textColorSecondaryInverse</item> <!-- selected should be accent -->
<item name="textSize">@dimen/datepicker_selected_date_year_size</item>
</style>
@@ -471,6 +471,10 @@ please see styles_device_defaults.xml.
<style name="Widget.Material.ButtonBar.AlertDialog">
<item name="background">@null</item>
+ <item name="paddingStart">16dp</item>
+ <item name="paddingEnd">16dp</item>
+ <item name="paddingBottom">16dp</item>
+ <item name="minHeight">@dimen/alert_dialog_button_bar_height</item>
</style>
<style name="Widget.Material.SearchView">
@@ -592,10 +596,10 @@ please see styles_device_defaults.xml.
<item name="internalLayout">@layout/time_picker_holo</item>
<item name="headerTimeTextAppearance">@style/TextAppearance.Material.TimePicker.TimeLabel</item>
<item name="headerAmPmTextAppearance">@style/TextAppearance.Material.TimePicker.AmPmLabel</item>
- <item name="headerSelectedTextColor">?attr/colorControlActivated</item>
- <item name="headerBackgroundColor">@color/transparent</item>
+ <item name="headerSelectedTextColor">?attr/textColorPrimaryInverse</item>
+ <item name="headerBackgroundColor">?attr/colorAccent</item>
<item name="numbersTextColor">?attr/textColorSecondary</item>
- <item name="numbersBackgroundColor">@color/transparent</item>
+ <item name="numbersBackgroundColor">#10ffffff</item>
<item name="amPmTextColor">?attr/textColorSecondary</item>
<item name="amPmBackgroundColor">@color/transparent</item>
<item name="amPmSelectedBackgroundColor">?attr/colorControlActivated</item>
@@ -608,13 +612,13 @@ please see styles_device_defaults.xml.
<!-- Attributes for new-style DatePicker. -->
<item name="internalLayout">@layout/date_picker_holo</item>
<item name="calendarViewShown">true</item>
- <item name="dayOfWeekBackgroundColor">@color/transparent</item>
+ <item name="dayOfWeekBackgroundColor">#10000000</item>
<item name="dayOfWeekTextAppearance">@style/TextAppearance.Material.DatePicker.DayOfWeekLabel</item>
<item name="headerMonthTextAppearance">@style/TextAppearance.Material.DatePicker.MonthLabel</item>
<item name="headerDayOfMonthTextAppearance">@style/TextAppearance.Material.DatePicker.DayOfMonthLabel</item>
<item name="headerYearTextAppearance">@style/TextAppearance.Material.DatePicker.YearLabel</item>
- <item name="headerSelectedTextColor">?attr/colorControlActivated</item>
- <item name="headerBackgroundColor">@color/transparent</item>
+ <item name="headerSelectedTextColor">?attr/textColorPrimaryInverse</item>
+ <item name="headerBackgroundColor">?attr/colorAccent</item>
<item name="yearListItemTextAppearance">@style/TextAppearance.Material.DatePicker.List.YearLabel</item>
<item name="yearListSelectorColor">?attr/colorControlActivated</item>
<item name="calendarTextColor">?attr/textColorSecondary</item>
@@ -632,7 +636,10 @@ please see styles_device_defaults.xml.
<item name="listSelector">?attr/listChoiceBackgroundIndicator</item>
</style>
- <style name="Widget.Material.ListView.DropDown"/>
+ <style name="Widget.Material.ListView.DropDown">
+ <item name="divider">@null</item>
+ </style>
+
<style name="Widget.Material.ListView.White"/>
<style name="Widget.Material.PopupWindow" parent="Widget.PopupWindow"/>
@@ -724,6 +731,10 @@ please see styles_device_defaults.xml.
<item name="overlapAnchor">true</item>
</style>
+ <style name="Widget.Material.Spinner.Form">
+ <item name="background">@drawable/spinner_textfield_background_material</item>
+ </style>
+
<style name="Widget.Material.TabWidget" parent="Widget.TabWidget">
<item name="tabStripLeft">@null</item>
<item name="tabStripRight">@null</item>
@@ -935,7 +946,11 @@ please see styles_device_defaults.xml.
</style>
<style name="Widget.Material.Light.NumberPicker" parent="Widget.Material.NumberPicker"/>
- <style name="Widget.Material.Light.TimePicker" parent="Widget.Material.TimePicker" />
+
+ <style name="Widget.Material.Light.TimePicker" parent="Widget.Material.TimePicker">
+ <item name="numbersBackgroundColor">#10000000</item>
+ </style>
+
<style name="Widget.Material.Light.DatePicker" parent="Widget.Material.DatePicker" />
<style name="Widget.Material.Light.ActivityChooserView" parent="Widget.Material.ActivityChooserView" />
<style name="Widget.Material.Light.ImageWell" parent="Widget.Material.ImageWell"/>
@@ -973,6 +988,7 @@ please see styles_device_defaults.xml.
<style name="Widget.Material.Light.Spinner" parent="Widget.Material.Spinner" />
<style name="Widget.Material.Light.Spinner.DropDown" parent="Widget.Material.Spinner.DropDown"/>
<style name="Widget.Material.Light.Spinner.DropDown.ActionBar" parent="Widget.Material.Spinner.DropDown.ActionBar"/>
+ <style name="Widget.Material.Light.Spinner.Form" parent="Widget.Material.Spinner.Form" />
<style name="Widget.Material.Light.TabWidget" parent="Widget.Material.TabWidget"/>
<style name="Widget.Material.Light.WebTextView" parent="Widget.Material.WebTextView"/>
<style name="Widget.Material.Light.WebView" parent="Widget.Material.WebView"/>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index a4bec17d3112..426a82d59829 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -1870,8 +1870,6 @@
<java-symbol type="id" name="ampm_label" />
<java-symbol type="id" name="radial_picker" />
<java-symbol type="id" name="separator" />
- <java-symbol type="id" name="layout_buttons" />
- <java-symbol type="id" name="done_button" />
<java-symbol type="id" name="date_picker_header" />
<java-symbol type="id" name="date_picker_month_and_day_layout" />
<java-symbol type="id" name="day_picker_selector_layout" />
@@ -1879,7 +1877,6 @@
<java-symbol type="id" name="date_picker_day" />
<java-symbol type="id" name="date_picker_year" />
<java-symbol type="id" name="animator" />
- <java-symbol type="id" name="done" />
<java-symbol type="string" name="done_label" />
<java-symbol type="string" name="hour_picker_description" />
@@ -1903,6 +1900,7 @@
<java-symbol type="string" name="timepicker_transition_mid_radius_multiplier" />
<java-symbol type="string" name="timepicker_transition_end_radius_multiplier" />
<java-symbol type="string" name="battery_saver_description" />
+ <java-symbol type="string" name="downtime_condition_summary" />
<java-symbol type="string" name="item_is_selected" />
<java-symbol type="string" name="day_of_week_label_typeface" />
diff --git a/core/res/res/values/themes_leanback.xml b/core/res/res/values/themes_leanback.xml
index 1cda843becfb..0a2c0a4864ea 100644
--- a/core/res/res/values/themes_leanback.xml
+++ b/core/res/res/values/themes_leanback.xml
@@ -58,5 +58,6 @@
<item name="textAppearanceListItem">@style/TextAppearance.Leanback.FormWizard.ListItem</item>
<item name="textAppearance">@style/TextAppearance.Leanback.FormWizard</item>
<item name="textColorPrimary">@color/primary_text_leanback_formwizard_dark</item>
+ <item name="windowAnimationStyle">@style/WindowAnimationStyle.Leanback.Setup</item>
</style>
</resources>
diff --git a/core/res/res/values/themes_material.xml b/core/res/res/values/themes_material.xml
index 1376dfa3dae1..691ddb19c37d 100644
--- a/core/res/res/values/themes_material.xml
+++ b/core/res/res/values/themes_material.xml
@@ -354,10 +354,10 @@ please see themes_device_defaults.xml.
<item name="timePickerStyle">@style/Widget.Material.TimePicker</item>
<!-- TimePicker dialog theme -->
- <item name="timePickerDialogTheme">?attr/alertDialogTheme</item>
+ <item name="timePickerDialogTheme">?attr/dialogTheme</item>
<!-- DatePicker style -->
- <item name="datePickerStyle">?attr/alertDialogTheme</item>
+ <item name="datePickerStyle">?attr/dialogTheme</item>
<!-- DatePicker dialog theme -->
<item name="datePickerDialogTheme">@style/Theme.Material.Dialog.Alert</item>
@@ -697,13 +697,13 @@ please see themes_device_defaults.xml.
<item name="timePickerStyle">@style/Widget.Material.Light.TimePicker</item>
<!-- TimePicker dialog theme -->
- <item name="timePickerDialogTheme">?attr/alertDialogTheme</item>
+ <item name="timePickerDialogTheme">?attr/dialogTheme</item>
<!-- DatePicker style -->
<item name="datePickerStyle">@style/Widget.Material.Light.DatePicker</item>
<!-- DatePicker dialog theme -->
- <item name="datePickerDialogTheme">?attr/alertDialogTheme</item>
+ <item name="datePickerDialogTheme">?attr/dialogTheme</item>
<item name="fastScrollThumbDrawable">@drawable/fastscroll_thumb_material</item>
<item name="fastScrollPreviewBackgroundLeft">@drawable/fastscroll_label_left_holo_light</item>
@@ -1187,19 +1187,6 @@ please see themes_device_defaults.xml.
AlertDialog theme. -->
<style name="Theme.Material.Light.Dialog.Alert" parent="Theme.Material.Light.Dialog.BaseAlert"/>
- <!-- Base theme used to prevent circular references in Leanback overrides. -->
- <style name="Theme.Material.Light.Dialog.BaseTimePicker" />
-
- <!-- Material Light theme for the TimePicker dialog windows, which is used by the
- {@link android.app.TimePickerDialog} class. -->
- <style name="Theme.Material.Light.Dialog.TimePicker" parent="Theme.Material.Light.Dialog.BaseTimePicker" />
-
- <style name="Theme.Material.Light.Dialog.BaseDatePicker" />
-
- <!-- Material Light theme for the DatePicker dialog windows, which is used by the
- {@link android.app.DatePickerDialog} class. -->
- <style name="Theme.Material.Light.Dialog.DatePicker" parent="Theme.Material.Light.Dialog.BaseDatePicker"/>
-
<!-- Theme for a presentation window on a secondary display. -->
<style name="Theme.Material.Light.Dialog.Presentation" parent="@style/Theme.Material.Light.NoActionBar.Fullscreen" />
diff --git a/graphics/java/android/graphics/drawable/AnimatedStateListDrawable.java b/graphics/java/android/graphics/drawable/AnimatedStateListDrawable.java
index fc38e8a34dbf..14aa570aa828 100644
--- a/graphics/java/android/graphics/drawable/AnimatedStateListDrawable.java
+++ b/graphics/java/android/graphics/drawable/AnimatedStateListDrawable.java
@@ -119,11 +119,11 @@ public class AnimatedStateListDrawable extends StateListDrawable {
*
* @param fromId Unique identifier of the starting keyframe
* @param toId Unique identifier of the ending keyframe
- * @param transition An animatable drawable to use as a transition, may not be null
+ * @param transition An {@link Animatable} drawable to use as a transition, may not be null
* @param reversible Whether the transition can be reversed
*/
- public void addTransition(int fromId, int toId, @NonNull Drawable transition,
- boolean reversible) {
+ public <T extends Drawable & Animatable> void addTransition(int fromId, int toId,
+ @NonNull T transition, boolean reversible) {
if (transition == null) {
throw new IllegalArgumentException("Transition drawable must not be null");
}
diff --git a/graphics/java/android/graphics/drawable/RippleDrawable.java b/graphics/java/android/graphics/drawable/RippleDrawable.java
index ea9f7320d024..0447e1770179 100644
--- a/graphics/java/android/graphics/drawable/RippleDrawable.java
+++ b/graphics/java/android/graphics/drawable/RippleDrawable.java
@@ -395,8 +395,12 @@ public class RippleDrawable extends LayerDrawable {
mState.mColor = color;
}
- // If we're not waiting on a theme, verify required attributes.
- if (state.mTouchThemeAttrs == null && mState.mColor == null) {
+ verifyRequiredAttributes(a);
+ }
+
+ private void verifyRequiredAttributes(TypedArray a) throws XmlPullParserException {
+ if (mState.mColor == null && (mState.mTouchThemeAttrs == null
+ || mState.mTouchThemeAttrs[R.styleable.RippleDrawable_color] == 0)) {
throw new XmlPullParserException(a.getPositionDescription() +
": <ripple> requires a valid color attribute");
}
@@ -891,7 +895,7 @@ public class RippleDrawable extends LayerDrawable {
static class RippleState extends LayerState {
int[] mTouchThemeAttrs;
- ColorStateList mColor = null;
+ ColorStateList mColor = ColorStateList.valueOf(Color.MAGENTA);
int mMaxRadius = RADIUS_AUTO;
public RippleState(RippleState orig, RippleDrawable owner, Resources res) {
diff --git a/graphics/java/android/graphics/drawable/VectorDrawable.java b/graphics/java/android/graphics/drawable/VectorDrawable.java
index 766e681c9207..9ac6927ca6aa 100644
--- a/graphics/java/android/graphics/drawable/VectorDrawable.java
+++ b/graphics/java/android/graphics/drawable/VectorDrawable.java
@@ -49,7 +49,7 @@ import java.util.ArrayList;
import java.util.Stack;
/**
- * This lets you create a drawable based on an XML vector graphic It can be
+ * This lets you create a drawable based on an XML vector graphic. It can be
* defined in an XML file with the <code>&lt;vector></code> element.
* <p/>
* The vector drawable has the following elements:
diff --git a/graphics/java/android/graphics/drawable/shapes/Shape.java b/graphics/java/android/graphics/drawable/shapes/Shape.java
index 589fbaa0a88e..eab86662b18e 100644
--- a/graphics/java/android/graphics/drawable/shapes/Shape.java
+++ b/graphics/java/android/graphics/drawable/shapes/Shape.java
@@ -16,6 +16,7 @@
package android.graphics.drawable.shapes;
+import android.annotation.NonNull;
import android.graphics.Canvas;
import android.graphics.Outline;
import android.graphics.Paint;
@@ -93,11 +94,12 @@ public abstract class Shape implements Cloneable {
protected void onResize(float width, float height) {}
/**
- * Compute the Outline of the shape.
+ * 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.
*
- * The default implementation does not supply an outline.
+ * @param outline The Outline to be populated with the result. Should not be null.
*/
- public void getOutline(Outline outline) {}
+ public void getOutline(@NonNull Outline outline) {}
@Override
public Shape clone() throws CloneNotSupportedException {
diff --git a/libs/androidfw/ResourceTypes.cpp b/libs/androidfw/ResourceTypes.cpp
index 702f15070e25..2a4dec089243 100644
--- a/libs/androidfw/ResourceTypes.cpp
+++ b/libs/androidfw/ResourceTypes.cpp
@@ -802,11 +802,16 @@ const char* ResStringPool::string8At(size_t idx, size_t* outLen) const
const String8 ResStringPool::string8ObjectAt(size_t idx) const
{
size_t len;
- const char *str = (const char*)string8At(idx, &len);
+ const char *str = string8At(idx, &len);
if (str != NULL) {
- return String8(str);
+ return String8(str, len);
}
- return String8(stringAt(idx, &len));
+
+ const char16_t *str16 = stringAt(idx, &len);
+ if (str16 != NULL) {
+ return String8(str16, len);
+ }
+ return String8();
}
const ResStringPool_span* ResStringPool::styleAt(const ResStringPool_ref& ref) const
@@ -2855,16 +2860,17 @@ struct ResTable::Type
struct ResTable::Package
{
Package(ResTable* _owner, const Header* _header, const ResTable_package* _package)
- : owner(_owner), header(_header), typeIdOffset(0) {
- if (_package != NULL && dtohs(_package->header.headerSize) == sizeof(_package)) {
+ : owner(_owner), header(_header), package(_package), typeIdOffset(0) {
+ if (dtohs(package->header.headerSize) == sizeof(package)) {
// The package structure is the same size as the definition.
// This means it contains the typeIdOffset field.
- typeIdOffset = _package->typeIdOffset;
+ typeIdOffset = package->typeIdOffset;
}
}
const ResTable* const owner;
const Header* const header;
+ const ResTable_package* const package;
ResStringPool typeStrings;
ResStringPool keyStrings;
@@ -3363,10 +3369,6 @@ status_t ResTable::addEmpty(const int32_t cookie) {
header->header = (const ResTable_header*) resHeader;
mHeaders.add(header);
-
- PackageGroup* pg = new PackageGroup(this, String16(), 0);
- pg->packages.add(new Package(this, header, NULL));
- mPackageGroups.add(pg);
return (mError=NO_ERROR);
}
@@ -5935,7 +5937,7 @@ status_t ResTable::createIdmap(const ResTable& overlay,
*outSize += 2 * sizeof(uint16_t);
// overlay packages are assumed to contain only one package group
- const String16 overlayPackage(overlay.mPackageGroups[0]->name);
+ const String16 overlayPackage(overlay.mPackageGroups[0]->packages[0]->package->name);
for (size_t typeIndex = 0; typeIndex < pg->types.size(); ++typeIndex) {
const TypeList& typeList = pg->types[typeIndex];
@@ -6218,6 +6220,13 @@ void ResTable::print(bool inclValues) const
(int)pgIndex, pg->id, (int)pg->packages.size(),
String8(pg->name).string());
+ size_t pkgCount = pg->packages.size();
+ for (size_t pkgIndex=0; pkgIndex<pkgCount; pkgIndex++) {
+ const Package* pkg = pg->packages[pkgIndex];
+ printf(" Package %d id=%d name=%s\n", (int)pkgIndex,
+ pkg->package->id, String8(String16(pkg->package->name)).string());
+ }
+
for (size_t typeIndex=0; typeIndex < pg->types.size(); typeIndex++) {
const TypeList& typeList = pg->types[typeIndex];
if (typeList.isEmpty()) {
diff --git a/libs/androidfw/tests/ResTable_test.cpp b/libs/androidfw/tests/ResTable_test.cpp
index 68c228e0de72..89d271d0bcd6 100644
--- a/libs/androidfw/tests/ResTable_test.cpp
+++ b/libs/androidfw/tests/ResTable_test.cpp
@@ -196,17 +196,16 @@ TEST(ResTableTest, resourceIsOverridenWithBetterConfig) {
}
TEST(ResTableTest, emptyTableHasSensibleDefaults) {
- const int32_t expectedCookie = 1;
+ const int32_t assetCookie = 1;
ResTable table;
- ASSERT_EQ(NO_ERROR, table.addEmpty(expectedCookie));
+ ASSERT_EQ(NO_ERROR, table.addEmpty(assetCookie));
+ // Adding an empty table gives us one table!
ASSERT_EQ(uint32_t(1), table.getTableCount());
- ASSERT_EQ(uint32_t(1), table.getBasePackageCount());
- ASSERT_EQ(expectedCookie, table.getTableCookie(0));
- const DynamicRefTable* dynamicRefTable = table.getDynamicRefTableForCookie(expectedCookie);
- ASSERT_TRUE(dynamicRefTable != NULL);
+ // Adding an empty table doesn't mean we get packages.
+ ASSERT_EQ(uint32_t(0), table.getBasePackageCount());
Res_value val;
ASSERT_LT(table.getResource(base::R::integer::number1, &val, MAY_NOT_BE_BAG), 0);
diff --git a/libs/hwui/font/Font.cpp b/libs/hwui/font/Font.cpp
index 2ea6c8cbd185..ba878bac00a9 100644
--- a/libs/hwui/font/Font.cpp
+++ b/libs/hwui/font/Font.cpp
@@ -140,12 +140,12 @@ void Font::invalidateTextureCache(CacheTexture* cacheTexture) {
void Font::measureCachedGlyph(CachedGlyphInfo *glyph, int x, int y,
uint8_t* bitmap, uint32_t bitmapW, uint32_t bitmapH, Rect* bounds, const float* pos) {
- int nPenX = x + glyph->mBitmapLeft;
- int nPenY = y + glyph->mBitmapTop;
-
int width = (int) glyph->mBitmapWidth;
int height = (int) glyph->mBitmapHeight;
+ int nPenX = x + glyph->mBitmapLeft;
+ int nPenY = y + glyph->mBitmapTop;
+
if (bounds->bottom > nPenY) {
bounds->bottom = nPenY;
}
@@ -162,12 +162,12 @@ void Font::measureCachedGlyph(CachedGlyphInfo *glyph, int x, int y,
void Font::drawCachedGlyph(CachedGlyphInfo* glyph, int x, int y,
uint8_t* bitmap, uint32_t bitmapW, uint32_t bitmapH, Rect* bounds, const float* pos) {
- float nPenX = x + glyph->mBitmapLeft;
- float nPenY = y + glyph->mBitmapTop + glyph->mBitmapHeight;
-
float width = (float) glyph->mBitmapWidth;
float height = (float) glyph->mBitmapHeight;
+ float nPenX = x + glyph->mBitmapLeft;
+ float nPenY = y + glyph->mBitmapTop + height;
+
float u1 = glyph->mBitmapMinU;
float u2 = glyph->mBitmapMaxU;
float v1 = glyph->mBitmapMinV;
@@ -181,10 +181,13 @@ void Font::drawCachedGlyph(CachedGlyphInfo* glyph, int x, int y,
void Font::drawCachedGlyphTransformed(CachedGlyphInfo* glyph, int x, int y,
uint8_t* bitmap, uint32_t bitmapW, uint32_t bitmapH, Rect* bounds, const float* pos) {
+ float width = (float) glyph->mBitmapWidth;
+ float height = (float) glyph->mBitmapHeight;
+
SkPoint p[4];
- p[0].iset(glyph->mBitmapLeft, glyph->mBitmapTop + glyph->mBitmapHeight);
- p[1].iset(glyph->mBitmapLeft + glyph->mBitmapWidth, glyph->mBitmapTop + glyph->mBitmapHeight);
- p[2].iset(glyph->mBitmapLeft + glyph->mBitmapWidth, glyph->mBitmapTop);
+ p[0].iset(glyph->mBitmapLeft, glyph->mBitmapTop + height);
+ p[1].iset(glyph->mBitmapLeft + width, glyph->mBitmapTop + height);
+ p[2].iset(glyph->mBitmapLeft + width, glyph->mBitmapTop);
p[3].iset(glyph->mBitmapLeft, glyph->mBitmapTop);
mDescription.mInverseLookupTransform.mapPoints(p, 4);
diff --git a/media/java/android/media/AudioTrack.java b/media/java/android/media/AudioTrack.java
index 8bc249874d90..52bcbbba0246 100644
--- a/media/java/android/media/AudioTrack.java
+++ b/media/java/android/media/AudioTrack.java
@@ -94,6 +94,9 @@ public class AudioTrack
/** Maximum value for sample rate */
private static final int SAMPLE_RATE_HZ_MAX = 48000;
+ /** Maximum value for AudioTrack channel count */
+ private static final int CHANNEL_COUNT_MAX = 8;
+
/** indicates AudioTrack state is stopped */
public static final int PLAYSTATE_STOPPED = 1; // matches SL_PLAYSTATE_STOPPED
/** indicates AudioTrack state is paused */
@@ -465,7 +468,9 @@ public class AudioTrack
AudioFormat.CHANNEL_OUT_LOW_FREQUENCY |
AudioFormat.CHANNEL_OUT_BACK_LEFT |
AudioFormat.CHANNEL_OUT_BACK_RIGHT |
- AudioFormat.CHANNEL_OUT_BACK_CENTER;
+ AudioFormat.CHANNEL_OUT_BACK_CENTER |
+ AudioFormat.CHANNEL_OUT_SIDE_LEFT |
+ AudioFormat.CHANNEL_OUT_SIDE_RIGHT;
// Convenience method for the constructor's parameter checks.
// This is where constructor IllegalArgumentException-s are thrown
@@ -541,6 +546,12 @@ public class AudioTrack
loge("Channel configuration features unsupported channels");
return false;
}
+ final int channelCount = Integer.bitCount(channelConfig);
+ if (channelCount > CHANNEL_COUNT_MAX) {
+ loge("Channel configuration contains too many channels " +
+ channelCount + ">" + CHANNEL_COUNT_MAX);
+ return false;
+ }
// check for unsupported multichannel combinations:
// - FL/FR must be present
// - L/R channels must be paired (e.g. no single L channel)
@@ -558,6 +569,13 @@ public class AudioTrack
return false;
}
}
+ final int sidePair =
+ AudioFormat.CHANNEL_OUT_SIDE_LEFT | AudioFormat.CHANNEL_OUT_SIDE_RIGHT;
+ if ((channelConfig & sidePair) != 0
+ && (channelConfig & sidePair) != sidePair) {
+ loge("Side channels can't be used independently");
+ return false;
+ }
return true;
}
diff --git a/media/java/android/media/MediaCodecInfo.java b/media/java/android/media/MediaCodecInfo.java
index b6e03f5b973b..ae2d024073d8 100644
--- a/media/java/android/media/MediaCodecInfo.java
+++ b/media/java/android/media/MediaCodecInfo.java
@@ -450,10 +450,16 @@ public final class MediaCodecInfo {
}
private void applyLevelLimits() {
- if (mParent.getMime().equalsIgnoreCase(
- MediaFormat.MIMETYPE_AUDIO_FLAC)) {
+ String mime = mParent.getMime();
+ if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_FLAC)) {
mComplexityRange = Range.create(0, 8);
mBitControl = (1 << BITRATE_MODE_CQ);
+ } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_AMR_NB)
+ || mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_AMR_WB)
+ || mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_G711_ALAW)
+ || mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_G711_MLAW)
+ || mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_MSGSM)) {
+ mBitControl = (1 << BITRATE_MODE_CBR);
}
}
@@ -514,11 +520,12 @@ public final class MediaCodecInfo {
/** @hide */
public void setDefaultFormat(MediaFormat format) {
- if (mQualityRange.getUpper() != mQualityRange.getLower()
+ // don't list trivial quality/complexity as default for now
+ if (!mQualityRange.getUpper().equals(mQualityRange.getLower())
&& mDefaultQuality != null) {
format.setInteger(MediaFormat.KEY_QUALITY, mDefaultQuality);
}
- if (mComplexityRange.getUpper() != mComplexityRange.getLower()
+ if (!mComplexityRange.getUpper().equals(mComplexityRange.getLower())
&& mDefaultComplexity != null) {
format.setInteger(MediaFormat.KEY_COMPLEXITY, mDefaultComplexity);
}
@@ -985,34 +992,34 @@ public final class MediaCodecInfo {
if ((mParent.mError & ERROR_UNSUPPORTED) != 0) {
// codec supports profiles that we don't know.
- // Extend ranges clipped to platform limits.
+ // Use supplied values clipped to platform limits
if (widths != null) {
- mWidthRange = mWidthRange.extend(widths);
+ mWidthRange = SIZE_RANGE.intersect(widths);
}
if (heights != null) {
- mHeightRange = mHeightRange.extend(heights);
+ mHeightRange = SIZE_RANGE.intersect(heights);
}
if (counts != null) {
- mBlockCountRange = mBlockCountRange.extend(
+ mBlockCountRange = POSITIVE_INTEGERS.intersect(
Utils.factorRange(counts, mBlockWidth * mBlockHeight
/ blockSize.getWidth() / blockSize.getHeight()));
}
if (blockRates != null) {
- mBlocksPerSecondRange = mBlocksPerSecondRange.extend(
+ mBlocksPerSecondRange = POSITIVE_LONGS.intersect(
Utils.factorRange(blockRates, mBlockWidth * mBlockHeight
/ blockSize.getWidth() / blockSize.getHeight()));
}
if (blockRatios != null) {
- mBlockAspectRatioRange = mBlockAspectRatioRange.extend(
+ mBlockAspectRatioRange = POSITIVE_RATIONALS.intersect(
Utils.scaleRange(blockRatios,
mBlockHeight / blockSize.getHeight(),
mBlockWidth / blockSize.getWidth()));
}
if (ratios != null) {
- mAspectRatioRange = mAspectRatioRange.extend(ratios);
+ mAspectRatioRange = POSITIVE_RATIONALS.intersect(ratios);
}
if (frameRates != null) {
- mFrameRateRange = mFrameRateRange.extend(frameRates);
+ mFrameRateRange = FRAME_RATE_RANGE.intersect(frameRates);
}
} else {
// no unsupported profile/levels, so restrict values to known limits
@@ -1235,7 +1242,6 @@ public final class MediaCodecInfo {
Log.w(TAG, "Unrecognized level "
+ profileLevel.level + " for " + mime);
errors |= ERROR_UNRECOGNIZED;
- supported = false;
}
switch (profileLevel.profile) {
case CodecProfileLevel.AVCProfileHigh:
@@ -1245,7 +1251,7 @@ public final class MediaCodecInfo {
case CodecProfileLevel.AVCProfileExtended:
case CodecProfileLevel.AVCProfileHigh422:
case CodecProfileLevel.AVCProfileHigh444:
- Log.w(TAG, "Unrecognized profile "
+ Log.w(TAG, "Unsupported profile "
+ profileLevel.profile + " for " + mime);
errors |= ERROR_UNSUPPORTED;
supported = false;
@@ -1271,7 +1277,9 @@ public final class MediaCodecInfo {
int maxLengthInBlocks = (int)(Math.sqrt(maxBlocks * 8));
applyMacroBlockLimits(
maxLengthInBlocks, maxLengthInBlocks,
- maxBlocks, maxBlocksPerSecond, 16, 16, 1, 1);
+ maxBlocks, maxBlocksPerSecond,
+ 16 /* blockWidth */, 16 /* blockHeight */,
+ 1 /* widthAlignment */, 1 /* heightAlignment */);
} else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_MPEG4)) {
int maxWidth = 11, maxHeight = 9, maxRate = 15;
maxBlocks = 99;
@@ -1369,7 +1377,9 @@ public final class MediaCodecInfo {
maxRate = Math.max(FR, maxRate);
}
applyMacroBlockLimits(maxWidth, maxHeight,
- maxBlocks, maxBlocksPerSecond, 16, 16, 1, 1);
+ maxBlocks, maxBlocksPerSecond,
+ 16 /* blockWidth */, 16 /* blockHeight */,
+ 1 /* widthAlignment */, 1 /* heightAlignment */);
mFrameRateRange = mFrameRateRange.intersect(12, maxRate);
} else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_H263)) {
int maxWidth = 11, maxHeight = 9, maxRate = 15;
@@ -1432,7 +1442,9 @@ public final class MediaCodecInfo {
maxRate = Math.max(FR, maxRate);
}
applyMacroBlockLimits(maxWidth, maxHeight,
- maxBlocks, maxBlocksPerSecond, 16, 16, 1, 1);
+ maxBlocks, maxBlocksPerSecond,
+ 16 /* blockWidth */, 16 /* blockHeight */,
+ 1 /* widthAlignment */, 1 /* heightAlignment */);
mFrameRateRange = Range.create(1, maxRate);
} else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_VP8) ||
mime.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_VP9)) {
@@ -1465,6 +1477,12 @@ public final class MediaCodecInfo {
}
errors &= ~ERROR_NONE_SUPPORTED;
}
+
+ final int blockSize =
+ mime.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_VP8) ? 16 : 8;
+ applyMacroBlockLimits(Short.MAX_VALUE, Short.MAX_VALUE,
+ maxBlocks, maxBlocksPerSecond, blockSize, blockSize,
+ 1 /* widthAlignment */, 1 /* heightAlignment */);
} else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_HEVC)) {
maxBlocks = 36864;
maxBlocksPerSecond = maxBlocks * 15;
@@ -1493,17 +1511,17 @@ public final class MediaCodecInfo {
FR = 30; FS = 2228224; BR = 12000; break;
case CodecProfileLevel.HEVCHighTierLevel4:
FR = 30; FS = 2228224; BR = 30000; break;
- case CodecProfileLevel.HEVCHighTierLevel41:
- FR = 60; FS = 2228224; BR = 20000; break;
case CodecProfileLevel.HEVCMainTierLevel41:
+ FR = 60; FS = 2228224; BR = 20000; break;
+ case CodecProfileLevel.HEVCHighTierLevel41:
FR = 60; FS = 2228224; BR = 50000; break;
- case CodecProfileLevel.HEVCHighTierLevel5:
- FR = 30; FS = 8912896; BR = 25000; break;
case CodecProfileLevel.HEVCMainTierLevel5:
+ FR = 30; FS = 8912896; BR = 25000; break;
+ case CodecProfileLevel.HEVCHighTierLevel5:
FR = 30; FS = 8912896; BR = 100000; break;
- case CodecProfileLevel.HEVCHighTierLevel51:
- FR = 60; FS = 8912896; BR = 40000; break;
case CodecProfileLevel.HEVCMainTierLevel51:
+ FR = 60; FS = 8912896; BR = 40000; break;
+ case CodecProfileLevel.HEVCHighTierLevel51:
FR = 60; FS = 8912896; BR = 160000; break;
case CodecProfileLevel.HEVCMainTierLevel52:
FR = 120; FS = 8912896; BR = 60000; break;
@@ -1513,13 +1531,13 @@ public final class MediaCodecInfo {
FR = 30; FS = 35651584; BR = 60000; break;
case CodecProfileLevel.HEVCHighTierLevel6:
FR = 30; FS = 35651584; BR = 240000; break;
- case CodecProfileLevel.HEVCHighTierLevel61:
- FR = 60; FS = 35651584; BR = 120000; break;
case CodecProfileLevel.HEVCMainTierLevel61:
+ FR = 60; FS = 35651584; BR = 120000; break;
+ case CodecProfileLevel.HEVCHighTierLevel61:
FR = 60; FS = 35651584; BR = 480000; break;
- case CodecProfileLevel.HEVCHighTierLevel62:
- FR = 120; FS = 35651584; BR = 240000; break;
case CodecProfileLevel.HEVCMainTierLevel62:
+ FR = 120; FS = 35651584; BR = 240000; break;
+ case CodecProfileLevel.HEVCHighTierLevel62:
FR = 120; FS = 35651584; BR = 800000; break;
default:
Log.w(TAG, "Unrecognized level "
@@ -1557,9 +1575,13 @@ public final class MediaCodecInfo {
applyMacroBlockLimits(
maxLengthInBlocks, maxLengthInBlocks,
- maxBlocks, maxBlocksPerSecond, 8, 8, 1, 1);
+ maxBlocks, maxBlocksPerSecond,
+ 8 /* blockWidth */, 8 /* blockHeight */,
+ 1 /* widthAlignment */, 1 /* heightAlignment */);
} else {
Log.w(TAG, "Unsupported mime " + mime);
+ // using minimal bitrate here. should be overriden by
+ // info from media_codecs.xml
maxBps = 64000;
errors |= ERROR_UNSUPPORTED;
}
@@ -1628,21 +1650,26 @@ public final class MediaCodecInfo {
if (mMime.toLowerCase().startsWith("audio/")) {
mAudioCaps = AudioCapabilities.create(info, this);
+ mAudioCaps.setDefaultFormat(mDefaultFormat);
} else if (mMime.toLowerCase().startsWith("video/")) {
mVideoCaps = VideoCapabilities.create(info, this);
}
if (encoder) {
mEncoderCaps = EncoderCapabilities.create(info, this);
+ mEncoderCaps.setDefaultFormat(mDefaultFormat);
}
for (Feature feat: getValidFeatures()) {
- Integer yesNo = (Integer)map.get(MediaFormat.KEY_FEATURE_ + feat.mName);
+ String key = MediaFormat.KEY_FEATURE_ + feat.mName;
+ Integer yesNo = (Integer)map.get(key);
if (yesNo == null) {
continue;
} else if (yesNo > 0) {
mFlagsRequired |= feat.mValue;
+ mDefaultFormat.setInteger(key, 1);
} else {
mFlagsSupported |= feat.mValue;
+ mDefaultFormat.setInteger(key, 1);
}
// TODO restrict features by mFlagsVerified once all codecs reliably verify them
}
@@ -1652,10 +1679,14 @@ public final class MediaCodecInfo {
* A class that supports querying the audio capabilities of a codec.
*/
public static final class AudioCapabilities extends BaseCapabilities {
+ private static final String TAG = "AudioCapabilities";
+
private int[] mSampleRates;
private Range<Integer>[] mSampleRateRanges;
private int mMaxInputChannelCount;
+ private static final int MAX_INPUT_CHANNEL_COUNT = 30;
+
/**
* Returns the array of supported sample rates if the codec
* supports only discrete values. Otherwise, it returns
@@ -1702,7 +1733,7 @@ public final class MediaCodecInfo {
}
private void initWithPlatformLimits() {
- mMaxInputChannelCount = 30;
+ mMaxInputChannelCount = MAX_INPUT_CHANNEL_COUNT;
// mBitrateRange = Range.create(1, 320000);
mSampleRateRanges = new Range[] { Range.create(8000, 96000) };
mSampleRates = null;
@@ -1758,7 +1789,7 @@ public final class MediaCodecInfo {
// check if all values are discrete
for (Range<Integer> range: mSampleRateRanges) {
- if (range.getLower() != range.getUpper()) {
+ if (!range.getLower().equals(range.getUpper())) {
mSampleRates = null;
return;
}
@@ -1777,7 +1808,7 @@ public final class MediaCodecInfo {
8000, 11025, 12000,
16000, 22050, 24000,
32000, 44100, 48000 };
- bitRates = Range.create(8192, 327680);
+ bitRates = Range.create(8000, 320000);
maxChannels = 2;
} else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_AMR_NB)) {
sampleRates = new int[] { 8000 };
@@ -1807,11 +1838,23 @@ public final class MediaCodecInfo {
} else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_RAW)) {
sampleRateRange = Range.create(1, 96000);
bitRates = Range.create(1, 10000000);
- maxChannels = 6;
+ maxChannels = 8;
} else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_FLAC)) {
sampleRateRange = Range.create(1, 655350);
// lossless codec, so bitrate is ignored
maxChannels = 255;
+ } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_G711_ALAW)
+ || mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_G711_MLAW)) {
+ sampleRates = new int[] { 8000 };
+ bitRates = Range.create(64000, 64000);
+ // platform allows multiple channels for this format
+ } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_MSGSM)) {
+ sampleRates = new int[] { 8000 };
+ bitRates = Range.create(13000, 13000);
+ maxChannels = 1;
+ } else {
+ Log.w(TAG, "Unsupported mime " + mime);
+ mParent.mError |= ERROR_UNSUPPORTED;
}
// restrict ranges
@@ -1832,7 +1875,7 @@ public final class MediaCodecInfo {
}
private void parseFromInfo(MediaFormat info) {
- int maxInputChannels = 1;
+ int maxInputChannels = MAX_INPUT_CHANNEL_COUNT;
Range<Integer> bitRates = POSITIVE_INTEGERS;
if (info.containsKey("sample-rate-ranges")) {
@@ -1844,7 +1887,8 @@ public final class MediaCodecInfo {
limitSampleRates(rateRanges);
}
if (info.containsKey("max-channel-count")) {
- maxInputChannels = info.getInteger("max-channel-count");
+ maxInputChannels = Utils.parseIntSafely(
+ info.getString("max-channel-count"), maxInputChannels);
}
if (info.containsKey("bitrate-range")) {
bitRates = bitRates.intersect(
@@ -1854,6 +1898,21 @@ public final class MediaCodecInfo {
}
/** @hide */
+ public void setDefaultFormat(MediaFormat format) {
+ // report settings that have only a single choice
+ if (mBitrateRange.getLower().equals(mBitrateRange.getUpper())) {
+ format.setInteger(MediaFormat.KEY_BIT_RATE, mBitrateRange.getLower());
+ }
+ if (mMaxInputChannelCount == 1) {
+ // mono-only format
+ format.setInteger(MediaFormat.KEY_CHANNEL_COUNT, 1);
+ }
+ if (mSampleRates != null && mSampleRates.length == 1) {
+ format.setInteger(MediaFormat.KEY_SAMPLE_RATE, mSampleRates[0]);
+ }
+ }
+
+ /** @hide */
public boolean supportsFormat(MediaFormat format) {
Map<String, Object> map = format.getMap();
Integer sampleRate = (Integer)map.get(MediaFormat.KEY_SAMPLE_RATE);
diff --git a/media/java/android/media/Utils.java b/media/java/android/media/Utils.java
index 12910ecb1491..df0daaf7b4a6 100644
--- a/media/java/android/media/Utils.java
+++ b/media/java/android/media/Utils.java
@@ -210,6 +210,19 @@ class Utils {
return fallback;
}
+ static int parseIntSafely(Object o, int fallback) {
+ try {
+ String s = (String)o;
+ return Integer.parseInt(s);
+ } catch (ClassCastException e) {
+ } catch (NumberFormatException e) {
+ } catch (NullPointerException e) {
+ return fallback;
+ }
+ Log.w(TAG, "could not parse integer '" + o + "'");
+ return fallback;
+ }
+
static Range<Integer> parseIntRange(Object o, Range<Integer> fallback) {
try {
String s = (String)o;
diff --git a/media/java/android/media/session/MediaSessionLegacyHelper.java b/media/java/android/media/session/MediaSessionLegacyHelper.java
index a182982e2a7c..aa196a9fea48 100644
--- a/media/java/android/media/session/MediaSessionLegacyHelper.java
+++ b/media/java/android/media/session/MediaSessionLegacyHelper.java
@@ -290,7 +290,6 @@ public class MediaSessionLegacyHelper {
if (DEBUG) {
Log.d(TAG, "addMediaButtonListener already added " + pi);
}
- return;
}
holder.mMediaButtonListener = new MediaButtonListener(pi, context);
// TODO determine if handling transport performer commands should also
@@ -468,7 +467,11 @@ public class MediaSessionLegacyHelper {
mSessions.remove(mPi);
} else if (mCb == null) {
mCb = new SessionCallback();
- mSession.setCallback(mCb);
+ Handler handler = null;
+ if (Looper.myLooper() == null) {
+ handler = new Handler(Looper.getMainLooper());
+ }
+ mSession.setCallback(mCb, handler);
}
}
diff --git a/media/java/android/media/tv/TvContract.java b/media/java/android/media/tv/TvContract.java
index 9a32bd667712..bdceb24f0a99 100644
--- a/media/java/android/media/tv/TvContract.java
+++ b/media/java/android/media/tv/TvContract.java
@@ -119,12 +119,12 @@ public final class TvContract {
}
/**
- * Build a special channel URI intended to be used with pass-through type inputs. (e.g. HDMI)
+ * Build a special channel URI intended to be used with pass-through inputs. (e.g. HDMI)
*
- * @param inputId The ID of the TV input to build a channels URI for.
- * @see TvInputInfo#isPassthroughInputType()
+ * @param inputId The ID of the pass-through input to build a channels URI for.
+ * @see TvInputInfo#isPassthroughInput()
*/
- public static final Uri buildChannelUriForPassthroughTvInput(String inputId) {
+ public static final Uri buildChannelUriForPassthroughInput(String inputId) {
return new Uri.Builder().scheme(ContentResolver.SCHEME_CONTENT).authority(AUTHORITY)
.appendPath(PATH_PASSTHROUGH).appendPath(inputId).build();
}
@@ -144,7 +144,7 @@ public final class TvContract {
* @param channelUri The URI of the channel whose logo is pointed to.
*/
public static final Uri buildChannelLogoUri(Uri channelUri) {
- if (!isChannelUriForTunerTvInput(channelUri)) {
+ if (!isChannelUriForTunerInput(channelUri)) {
throw new IllegalArgumentException("Not a channel: " + channelUri);
}
return Uri.withAppendedPath(channelUri, Channels.Logo.CONTENT_DIRECTORY);
@@ -230,7 +230,7 @@ public final class TvContract {
* @param channelUri The URI of the channel to return programs for.
*/
public static final Uri buildProgramsUriForChannel(Uri channelUri) {
- if (!isChannelUriForTunerTvInput(channelUri)) {
+ if (!isChannelUriForTunerInput(channelUri)) {
throw new IllegalArgumentException("Not a channel: " + channelUri);
}
return buildProgramsUriForChannel(ContentUris.parseId(channelUri));
@@ -265,7 +265,7 @@ public final class TvContract {
*/
public static final Uri buildProgramsUriForChannel(Uri channelUri, long startTime,
long endTime) {
- if (!isChannelUriForTunerTvInput(channelUri)) {
+ if (!isChannelUriForTunerInput(channelUri)) {
throw new IllegalArgumentException("Not a channel: " + channelUri);
}
return buildProgramsUriForChannel(ContentUris.parseId(channelUri), startTime, endTime);
@@ -296,23 +296,23 @@ public final class TvContract {
* @hide
*/
public static final boolean isChannelUri(Uri uri) {
- return isChannelUriForTunerTvInput(uri) || isChannelUriForPassthroughTvInput(uri);
+ return isChannelUriForTunerInput(uri) || isChannelUriForPassthroughInput(uri);
}
/**
- * Returns true, if {@code uri} is a channel URI for a tuner TV input.
+ * Returns true, if {@code uri} is a channel URI for a tuner input.
* @hide
*/
- public static final boolean isChannelUriForTunerTvInput(Uri uri) {
+ public static final boolean isChannelUriForTunerInput(Uri uri) {
return isTvUri(uri) && isTwoSegmentUriStartingWith(uri, PATH_CHANNEL);
}
/**
- * Returns true, if {@code uri} is a channel URI for a passthrough TV input.
+ * Returns true, if {@code uri} is a channel URI for a passthrough input.
* @hide
*/
@SystemApi
- public static final boolean isChannelUriForPassthroughTvInput(Uri uri) {
+ public static final boolean isChannelUriForPassthroughInput(Uri uri) {
return isTvUri(uri) && isTwoSegmentUriStartingWith(uri, PATH_PASSTHROUGH);
}
diff --git a/media/java/android/media/tv/TvInputInfo.java b/media/java/android/media/tv/TvInputInfo.java
index 6ed758073222..ff4892b75bcb 100644
--- a/media/java/android/media/tv/TvInputInfo.java
+++ b/media/java/android/media/tv/TvInputInfo.java
@@ -380,9 +380,9 @@ public final class TvInputInfo implements Parcelable {
* Returns {@code true} if this TV input is pass-though which does not have any real channels
* in TvProvider. {@code false} otherwise.
*
- * @see TvContract#buildChannelUriForPassthroughTvInput(String)
+ * @see TvContract#buildChannelUriForPassthroughInput(String)
*/
- public boolean isPassthroughInputType() {
+ public boolean isPassthroughInput() {
return mType != TYPE_TUNER;
}
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index 5dc7d26a1b4e..87c015c98630 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -20,6 +20,7 @@ import java.io.FileNotFoundException;
import java.security.SecureRandom;
import java.util.HashMap;
import java.util.HashSet;
+import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
@@ -94,6 +95,9 @@ public class SettingsProvider extends ContentProvider {
// Each defined user has their own settings
protected final SparseArray<DatabaseHelper> mOpenHelpers = new SparseArray<DatabaseHelper>();
+ // Keep the list of managed profiles synced here
+ private List<UserInfo> mManagedProfiles = null;
+
// Over this size we don't reject loading or saving settings but
// we do consider them broken/malicious and don't keep them in
// memory at least:
@@ -119,6 +123,9 @@ public class SettingsProvider extends ContentProvider {
private static final String DROPBOX_TAG_USERLOG = "restricted_profile_ssaid";
+ static final HashSet<String> sSecureCloneToManagedKeys;
+ static final HashSet<String> sSystemCloneToManagedKeys;
+
static {
// Keys (name column) from the 'secure' table that are now in the owner user's 'global'
// table, shared across all users
@@ -142,6 +149,15 @@ public class SettingsProvider extends ContentProvider {
UserManager.ENSURE_VERIFY_APPS);
sRestrictedKeys.put(Settings.Global.PREFERRED_NETWORK_MODE,
UserManager.DISALLOW_CONFIG_MOBILE_NETWORKS);
+
+ sSecureCloneToManagedKeys = new HashSet<String>();
+ for (int i = 0; i < Settings.Secure.CLONE_TO_MANAGED_PROFILE.length; i++) {
+ sSecureCloneToManagedKeys.add(Settings.Secure.CLONE_TO_MANAGED_PROFILE[i]);
+ }
+ sSystemCloneToManagedKeys = new HashSet<String>();
+ for (int i = 0; i < Settings.System.CLONE_TO_MANAGED_PROFILE.length; i++) {
+ sSystemCloneToManagedKeys.add(Settings.System.CLONE_TO_MANAGED_PROFILE[i]);
+ }
}
private boolean settingMovedToGlobal(final String name) {
@@ -362,18 +378,22 @@ public class SettingsProvider extends ContentProvider {
IntentFilter userFilter = new IntentFilter();
userFilter.addAction(Intent.ACTION_USER_REMOVED);
+ userFilter.addAction(Intent.ACTION_USER_ADDED);
getContext().registerReceiver(new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
+ final int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE,
+ UserHandle.USER_OWNER);
if (intent.getAction().equals(Intent.ACTION_USER_REMOVED)) {
- final int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE,
- UserHandle.USER_OWNER);
- if (userHandle != UserHandle.USER_OWNER) {
- onUserRemoved(userHandle);
- }
+ onUserRemoved(userHandle);
+ } else if (intent.getAction().equals(Intent.ACTION_USER_ADDED)) {
+ onProfilesChanged();
}
}
}, userFilter);
+
+ onProfilesChanged();
+
return true;
}
@@ -391,6 +411,32 @@ public class SettingsProvider extends ContentProvider {
sSystemCaches.delete(userHandle);
sSecureCaches.delete(userHandle);
sKnownMutationsInFlight.delete(userHandle);
+ onProfilesChanged();
+ }
+ }
+
+ /**
+ * Updates the list of managed profiles. It assumes that only the primary user
+ * can have managed profiles. Modify this code if that changes in the future.
+ */
+ void onProfilesChanged() {
+ synchronized (this) {
+ mManagedProfiles = mUserManager.getProfiles(UserHandle.USER_OWNER);
+ if (mManagedProfiles != null) {
+ // Remove the primary user from the list
+ for (int i = mManagedProfiles.size() - 1; i >= 0; i--) {
+ if (mManagedProfiles.get(i).id == UserHandle.USER_OWNER) {
+ mManagedProfiles.remove(i);
+ }
+ }
+ // If there are no managed profiles, reset the variable
+ if (mManagedProfiles.size() == 0) {
+ mManagedProfiles = null;
+ }
+ }
+ if (LOCAL_LOGV) {
+ Slog.d(TAG, "Managed Profiles = " + mManagedProfiles);
+ }
}
}
@@ -601,6 +647,24 @@ public class SettingsProvider extends ContentProvider {
}
/**
+ * Checks if the calling user is a managed profile of the primary user.
+ * Currently only the primary user (USER_OWNER) can have managed profiles.
+ * @param callingUser the user trying to read/write settings
+ * @return true if it is a managed profile of the primary user
+ */
+ private boolean isManagedProfile(int callingUser) {
+ synchronized (this) {
+ if (mManagedProfiles == null) return false;
+ for (int i = mManagedProfiles.size() - 1; i >= 0; i--) {
+ if (mManagedProfiles.get(i).id == callingUser) {
+ return true;
+ }
+ }
+ return false;
+ }
+ }
+
+ /**
* Fast path that avoids the use of chatty remoted Cursors.
*/
@Override
@@ -625,12 +689,18 @@ public class SettingsProvider extends ContentProvider {
// Get methods
if (Settings.CALL_METHOD_GET_SYSTEM.equals(method)) {
if (LOCAL_LOGV) Slog.v(TAG, "call(system:" + request + ") for " + callingUser);
+ if (isManagedProfile(callingUser) && sSystemCloneToManagedKeys.contains(request)) {
+ callingUser = UserHandle.USER_OWNER;
+ }
dbHelper = getOrEstablishDatabase(callingUser);
cache = sSystemCaches.get(callingUser);
return lookupValue(dbHelper, TABLE_SYSTEM, cache, request);
}
if (Settings.CALL_METHOD_GET_SECURE.equals(method)) {
if (LOCAL_LOGV) Slog.v(TAG, "call(secure:" + request + ") for " + callingUser);
+ if (isManagedProfile(callingUser) && sSecureCloneToManagedKeys.contains(request)) {
+ callingUser = UserHandle.USER_OWNER;
+ }
dbHelper = getOrEstablishDatabase(callingUser);
cache = sSecureCaches.get(callingUser);
return lookupValue(dbHelper, TABLE_SECURE, cache, request);
@@ -667,13 +737,70 @@ public class SettingsProvider extends ContentProvider {
values.put(Settings.NameValueTable.NAME, request);
values.put(Settings.NameValueTable.VALUE, newValue);
if (Settings.CALL_METHOD_PUT_SYSTEM.equals(method)) {
- if (LOCAL_LOGV) Slog.v(TAG, "call_put(system:" + request + "=" + newValue + ") for " + callingUser);
+ if (LOCAL_LOGV) {
+ Slog.v(TAG, "call_put(system:" + request + "=" + newValue + ") for "
+ + callingUser);
+ }
+ // Extra check for USER_OWNER to optimize for the 99%
+ if (callingUser != UserHandle.USER_OWNER && isManagedProfile(callingUser)) {
+ if (sSystemCloneToManagedKeys.contains(request)) {
+ // Don't write these settings
+ return null;
+ }
+ }
insertForUser(Settings.System.CONTENT_URI, values, callingUser);
+ // Clone the settings to the managed profiles so that notifications can be sent out
+ if (callingUser == UserHandle.USER_OWNER && mManagedProfiles != null
+ && sSystemCloneToManagedKeys.contains(request)) {
+ final long token = Binder.clearCallingIdentity();
+ try {
+ for (int i = mManagedProfiles.size() - 1; i >= 0; i--) {
+ if (LOCAL_LOGV) {
+ Slog.v(TAG, "putting to additional user "
+ + mManagedProfiles.get(i).id);
+ }
+ insertForUser(Settings.System.CONTENT_URI, values,
+ mManagedProfiles.get(i).id);
+ }
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
} else if (Settings.CALL_METHOD_PUT_SECURE.equals(method)) {
- if (LOCAL_LOGV) Slog.v(TAG, "call_put(secure:" + request + "=" + newValue + ") for " + callingUser);
+ if (LOCAL_LOGV) {
+ Slog.v(TAG, "call_put(secure:" + request + "=" + newValue + ") for "
+ + callingUser);
+ }
+ // Extra check for USER_OWNER to optimize for the 99%
+ if (callingUser != UserHandle.USER_OWNER && isManagedProfile(callingUser)) {
+ if (sSecureCloneToManagedKeys.contains(request)) {
+ // Don't write these settings
+ return null;
+ }
+ }
insertForUser(Settings.Secure.CONTENT_URI, values, callingUser);
+ // Clone the settings to the managed profiles so that notifications can be sent out
+ if (callingUser == UserHandle.USER_OWNER && mManagedProfiles != null
+ && sSecureCloneToManagedKeys.contains(request)) {
+ final long token = Binder.clearCallingIdentity();
+ try {
+ for (int i = mManagedProfiles.size() - 1; i >= 0; i--) {
+ if (LOCAL_LOGV) {
+ Slog.v(TAG, "putting to additional user "
+ + mManagedProfiles.get(i).id);
+ }
+ insertForUser(Settings.Secure.CONTENT_URI, values,
+ mManagedProfiles.get(i).id);
+ }
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
} else if (Settings.CALL_METHOD_PUT_GLOBAL.equals(method)) {
- if (LOCAL_LOGV) Slog.v(TAG, "call_put(global:" + request + "=" + newValue + ") for " + callingUser);
+ if (LOCAL_LOGV) {
+ Slog.v(TAG, "call_put(global:" + request + "=" + newValue + ") for "
+ + callingUser);
+ }
insertForUser(Settings.Global.CONTENT_URI, values, callingUser);
} else {
Slog.w(TAG, "call() with invalid method: " + method);
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index c24fcae74ead..d14517290809 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -709,13 +709,13 @@
<string name="guest_wipe_session_title">Welcome back, guest!</string>
<!-- Message of the notification when resuming an existing guest session [CHAR LIMIT=NONE] -->
- <string name="guest_wipe_session_message">Do you want to start a new session?</string>
+ <string name="guest_wipe_session_message">Do you want to continue your session?</string>
<!-- Notification when resuming an existing guest session: Action that starts a new session [CHAR LIMIT=35] -->
- <string name="guest_wipe_session_wipe">Yes</string>
+ <string name="guest_wipe_session_wipe">Start over</string>
<!-- Notification when resuming an existing guest session: Action that continues with the current session [CHAR LIMIT=35] -->
- <string name="guest_wipe_session_dontwipe">No, thanks</string>
+ <string name="guest_wipe_session_dontwipe">Yes, continue</string>
<!-- Zen mode condition: time duration in minutes. [CHAR LIMIT=NONE] -->
diff --git a/packages/SystemUI/src/com/android/systemui/settings/BrightnessController.java b/packages/SystemUI/src/com/android/systemui/settings/BrightnessController.java
index 2113c68613d0..9fbcd7f1b3a7 100644
--- a/packages/SystemUI/src/com/android/systemui/settings/BrightnessController.java
+++ b/packages/SystemUI/src/com/android/systemui/settings/BrightnessController.java
@@ -59,6 +59,7 @@ public class BrightnessController implements ToggleSlider.Listener {
private boolean mAutomatic;
private boolean mListening;
+ private boolean mExternalChange;
public interface BrightnessStateChangeCallback {
public void onBrightnessLevelChanged();
@@ -86,19 +87,24 @@ public class BrightnessController implements ToggleSlider.Listener {
@Override
public void onChange(boolean selfChange, Uri uri) {
if (selfChange) return;
- if (BRIGHTNESS_MODE_URI.equals(uri)) {
- updateMode();
- updateSlider();
- } else if (BRIGHTNESS_URI.equals(uri) && !mAutomatic) {
- updateSlider();
- } else if (BRIGHTNESS_ADJ_URI.equals(uri) && mAutomatic) {
- updateSlider();
- } else {
- updateMode();
- updateSlider();
- }
- for (BrightnessStateChangeCallback cb : mChangeCallbacks) {
- cb.onBrightnessLevelChanged();
+ try {
+ mExternalChange = true;
+ if (BRIGHTNESS_MODE_URI.equals(uri)) {
+ updateMode();
+ updateSlider();
+ } else if (BRIGHTNESS_URI.equals(uri) && !mAutomatic) {
+ updateSlider();
+ } else if (BRIGHTNESS_ADJ_URI.equals(uri) && mAutomatic) {
+ updateSlider();
+ } else {
+ updateMode();
+ updateSlider();
+ }
+ for (BrightnessStateChangeCallback cb : mChangeCallbacks) {
+ cb.onBrightnessLevelChanged();
+ }
+ } finally {
+ mExternalChange = false;
}
}
@@ -191,6 +197,8 @@ public class BrightnessController implements ToggleSlider.Listener {
@Override
public void onChanged(ToggleSlider view, boolean tracking, boolean automatic, int value) {
updateIcon(mAutomatic);
+ if (mExternalChange) return;
+
if (!mAutomatic) {
final int val = value + mMinimumBacklight;
setBrightness(val);
diff --git a/packages/SystemUI/src/com/android/systemui/settings/BrightnessDialog.java b/packages/SystemUI/src/com/android/systemui/settings/BrightnessDialog.java
index d11313962b53..a1704fff1af1 100644
--- a/packages/SystemUI/src/com/android/systemui/settings/BrightnessDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/settings/BrightnessDialog.java
@@ -40,35 +40,27 @@ public class BrightnessDialog extends Activity {
super.onCreate(savedInstanceState);
final Window window = getWindow();
- final WindowManager.LayoutParams lp = window.getAttributes();
- // Offset from the top
- lp.y = getResources().getDimensionPixelOffset(R.dimen.volume_panel_top);
- lp.type = WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY;
- lp.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS;
-
- window.setAttributes(lp);
window.setGravity(Gravity.TOP);
window.clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);
window.requestFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.quick_settings_brightness_dialog);
+
+ final ImageView icon = (ImageView) findViewById(R.id.brightness_icon);
+ final ToggleSlider slider = (ToggleSlider) findViewById(R.id.brightness_slider);
+ mBrightnessController = new BrightnessController(this, icon, slider);
}
@Override
protected void onStart() {
super.onStart();
-
- final ImageView icon = (ImageView) findViewById(R.id.brightness_icon);
- final ToggleSlider slider = (ToggleSlider) findViewById(R.id.brightness_slider);
- mBrightnessController = new BrightnessController(this, icon, slider);
mBrightnessController.registerCallbacks();
}
@Override
protected void onStop() {
super.onStop();
-
mBrightnessController.unregisterCallbacks();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
index 99487ff2131f..ca290e4166b5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
@@ -662,7 +662,6 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView
}
public void reset() {
- super.reset();
setTintColor(0);
setShowingLegacyBackground(false);
setBelowSpeedBump(false);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
index 8c5151b6391e..947d70d51854 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
@@ -1735,6 +1735,9 @@ public abstract class BaseStatusBar extends SystemUI implements
: null;
// Reapply the RemoteViews
+ if (entry.row != null) {
+ entry.row.resetHeight();
+ }
contentView.reapply(mContext, entry.expanded, mOnClickHandler);
if (bigContentView != null && entry.getBigContentView() != null) {
bigContentView.reapply(mContext, entry.getBigContentView(),
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
index 43b77075c975..9ac20a6c9d25 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
@@ -88,9 +88,14 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
mExpansionDisabled = false;
mPublicLayout.reset();
mPrivateLayout.reset();
+ resetHeight();
+ logExpansionEvent(false, wasExpanded);
+ }
+
+ public void resetHeight() {
mMaxExpandHeight = 0;
mWasReset = true;
- logExpansionEvent(false, wasExpanded);
+ onHeightReset();
}
@Override
@@ -178,20 +183,26 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
* @param expand whether the system wants this notification to be expanded.
*/
public void setSystemExpanded(boolean expand) {
- final boolean wasExpanded = isExpanded();
- mIsSystemExpanded = expand;
- notifyHeightChanged();
- logExpansionEvent(false, wasExpanded);
+ if (expand != mIsSystemExpanded) {
+ final boolean wasExpanded = isExpanded();
+ mIsSystemExpanded = expand;
+ notifyHeightChanged();
+ logExpansionEvent(false, wasExpanded);
+ }
}
/**
* @param expansionDisabled whether to prevent notification expansion
*/
public void setExpansionDisabled(boolean expansionDisabled) {
- final boolean wasExpanded = isExpanded();
- mExpansionDisabled = expansionDisabled;
- logExpansionEvent(false, wasExpanded);
- notifyHeightChanged();
+ if (expansionDisabled != mExpansionDisabled) {
+ final boolean wasExpanded = isExpanded();
+ mExpansionDisabled = expansionDisabled;
+ logExpansionEvent(false, wasExpanded);
+ if (wasExpanded != isExpanded()) {
+ notifyHeightChanged();
+ }
+ }
}
/**
@@ -368,9 +379,8 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
mPrivateLayout.notifyContentUpdated();
}
- public boolean isShowingLayoutLayouted() {
- NotificationContentView showingLayout = getShowingLayout();
- return showingLayout.getWidth() != 0;
+ public boolean isMaxExpandHeightInitialized() {
+ return mMaxExpandHeight != 0;
}
private NotificationContentView getShowingLayout() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java
index 5b0bf031596c..127ff6cd4f93 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java
@@ -255,7 +255,7 @@ public abstract class ExpandableView extends FrameLayout {
public void setBelowSpeedBump(boolean below) {
}
- public void reset() {
+ public void onHeightReset() {
if (mOnHeightChangedListener != null) {
mOnHeightChangedListener.onReset(this);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
index c8e943e07547..decaeb6575de 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
@@ -54,6 +54,11 @@ public abstract class PanelView extends FrameLayout {
private float mInitialOffsetOnTouch;
private float mExpandedFraction = 0;
protected float mExpandedHeight = 0;
+ private boolean mPanelClosedOnDown;
+ private boolean mHasLayoutedSinceDown;
+ private float mUpdateFlingVelocity;
+ private boolean mUpdateFlingOnLayout;
+ private boolean mTouching;
private boolean mJustPeeked;
private boolean mClosing;
protected boolean mTracking;
@@ -76,7 +81,6 @@ public abstract class PanelView extends FrameLayout {
PanelBar mBar;
- protected int mMaxPanelHeight = -1;
private String mViewName;
private float mInitialTouchY;
private float mInitialTouchX;
@@ -226,6 +230,10 @@ public abstract class PanelView extends FrameLayout {
mInitialOffsetOnTouch = mExpandedHeight;
mTouchSlopExceeded = false;
mJustPeeked = false;
+ mPanelClosedOnDown = mExpandedHeight == 0.0f;
+ mHasLayoutedSinceDown = false;
+ mUpdateFlingOnLayout = false;
+ mTouching = true;
if (mVelocityTracker == null) {
initVelocityTracker();
}
@@ -316,6 +324,10 @@ public abstract class PanelView extends FrameLayout {
boolean expand = flingExpands(vel, vectorVel);
onTrackingStopped(expand);
fling(vel, expand);
+ mUpdateFlingOnLayout = expand && mPanelClosedOnDown && !mHasLayoutedSinceDown;
+ if (mUpdateFlingOnLayout) {
+ mUpdateFlingVelocity = vel;
+ }
} else {
boolean expands = onEmptySpaceClick(mInitialTouchX);
onTrackingStopped(expands);
@@ -325,6 +337,7 @@ public abstract class PanelView extends FrameLayout {
mVelocityTracker.recycle();
mVelocityTracker = null;
}
+ mTouching = false;
break;
}
return !waitForTouchSlop || mTracking;
@@ -383,6 +396,10 @@ public abstract class PanelView extends FrameLayout {
mInitialTouchX = x;
mTouchSlopExceeded = false;
mJustPeeked = false;
+ mPanelClosedOnDown = mExpandedHeight == 0.0f;
+ mHasLayoutedSinceDown = false;
+ mUpdateFlingOnLayout = false;
+ mTouching = true;
initVelocityTracker();
trackMovement(event);
break;
@@ -415,6 +432,10 @@ public abstract class PanelView extends FrameLayout {
}
}
break;
+ case MotionEvent.ACTION_CANCEL:
+ case MotionEvent.ACTION_UP:
+ mTouching = false;
+ break;
}
return false;
}
@@ -444,7 +465,6 @@ public abstract class PanelView extends FrameLayout {
protected void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
loadDimens();
- mMaxPanelHeight = -1;
}
/**
@@ -524,27 +544,6 @@ public abstract class PanelView extends FrameLayout {
return mViewName;
}
- @Override
- protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- super.onMeasure(widthMeasureSpec, heightMeasureSpec);
-
- if (DEBUG) logf("onMeasure(%d, %d) -> (%d, %d)",
- widthMeasureSpec, heightMeasureSpec, getMeasuredWidth(), getMeasuredHeight());
-
- // Did one of our children change size?
- int newHeight = getMeasuredHeight();
- if (newHeight > mMaxPanelHeight) {
- // we only adapt the max height if it's bigger
- mMaxPanelHeight = newHeight;
- // If the user isn't actively poking us, let's rubberband to the content
- if (!mTracking && mHeightAnimator == null
- && mExpandedHeight > 0 && mExpandedHeight != mMaxPanelHeight
- && mMaxPanelHeight > 0 && mPeekAnimator == null) {
- mExpandedHeight = mMaxPanelHeight;
- }
- }
- }
-
public void setExpandedHeight(float height) {
if (DEBUG) logf("setExpandedHeight(%.1f)", height);
setExpandedHeightInternal(height + getOverExpansionPixels());
@@ -552,10 +551,14 @@ public abstract class PanelView extends FrameLayout {
@Override
protected void onLayout (boolean changed, int left, int top, int right, int bottom) {
- if (DEBUG) logf("onLayout: changed=%s, bottom=%d eh=%d fh=%d", changed?"T":"f", bottom,
- (int)mExpandedHeight, mMaxPanelHeight);
super.onLayout(changed, left, top, right, bottom);
requestPanelHeightUpdate();
+ mHasLayoutedSinceDown = true;
+ if (mUpdateFlingOnLayout) {
+ abortAnimations();
+ fling(mUpdateFlingVelocity, true);
+ mUpdateFlingOnLayout = false;
+ }
}
protected void requestPanelHeightUpdate() {
@@ -567,7 +570,8 @@ public abstract class PanelView extends FrameLayout {
&& mExpandedHeight > 0
&& currentMaxPanelHeight != mExpandedHeight
&& !mPeekPending
- && mPeekAnimator == null) {
+ && mPeekAnimator == null
+ && !mTouching) {
setExpandedHeight(currentMaxPanelHeight);
}
}
@@ -615,10 +619,7 @@ public abstract class PanelView extends FrameLayout {
*
* @return the default implementation simply returns the maximum height.
*/
- protected int getMaxPanelHeight() {
- mMaxPanelHeight = Math.max(mMaxPanelHeight, getHeight());
- return mMaxPanelHeight;
- }
+ protected abstract int getMaxPanelHeight();
public void setExpandedFraction(float frac) {
setExpandedHeight(getMaxPanelHeight() * frac);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
index 04ee294f7f49..e1fd77970e41 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
@@ -121,6 +121,7 @@ public class StatusBarWindowView extends FrameLayout {
MotionEvent cancellation = MotionEvent.obtain(ev);
cancellation.setAction(MotionEvent.ACTION_CANCEL);
mStackScrollLayout.onInterceptTouchEvent(cancellation);
+ mNotificationPanel.onInterceptTouchEvent(cancellation);
cancellation.recycle();
}
return intercept;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeController.java
index 6c4fb7a9f243..7d102bad8dc2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeController.java
@@ -16,7 +16,6 @@
package com.android.systemui.statusbar.policy;
-import android.net.Uri;
import android.service.notification.Condition;
public interface ZenModeController {
@@ -25,15 +24,15 @@ public interface ZenModeController {
void setZen(int zen);
int getZen();
void requestConditions(boolean request);
- void setExitConditionId(Uri exitConditionId);
- Uri getExitConditionId();
+ void setExitCondition(Condition exitCondition);
+ Condition getExitCondition();
long getNextAlarm();
void setUserId(int userId);
boolean isZenAvailable();
public static class Callback {
public void onZenChanged(int zen) {}
- public void onExitConditionChanged(Uri exitConditionId) {}
+ public void onExitConditionChanged(Condition exitCondition) {}
public void onConditionsChanged(Condition[] conditions) {}
public void onNextAlarmChanged() {}
public void onZenAvailableChanged(boolean available) {}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeControllerImpl.java
index b33e502c86ab..b0c8f26dbd9c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeControllerImpl.java
@@ -122,20 +122,20 @@ public class ZenModeControllerImpl implements ZenModeController {
}
@Override
- public void setExitConditionId(Uri exitConditionId) {
+ public void setExitCondition(Condition exitCondition) {
try {
- mNoMan.setZenModeCondition(exitConditionId);
+ mNoMan.setZenModeCondition(exitCondition);
} catch (RemoteException e) {
// noop
}
}
@Override
- public Uri getExitConditionId() {
+ public Condition getExitCondition() {
try {
final ZenModeConfig config = mNoMan.getZenModeConfig();
if (config != null) {
- return config.exitConditionId;
+ return config.exitCondition;
}
} catch (RemoteException e) {
// noop
@@ -186,10 +186,10 @@ public class ZenModeControllerImpl implements ZenModeController {
}
private void fireExitConditionChanged() {
- final Uri exitConditionId = getExitConditionId();
- if (DEBUG) Slog.d(TAG, "exitConditionId changed: " + exitConditionId);
+ final Condition exitCondition = getExitCondition();
+ if (DEBUG) Slog.d(TAG, "exitCondition changed: " + exitCondition);
for (Callback cb : mCallbacks) {
- cb.onExitConditionChanged(exitConditionId);
+ cb.onExitConditionChanged(exitCondition);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
index 8e5077cb20dd..1469d73cf472 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
@@ -1914,6 +1914,7 @@ public class NotificationStackScrollLayout extends ViewGroup
@Override
public void onReset(ExpandableView view) {
mRequestViewResizeAnimationOnLayout = true;
+ mStackScrollAlgorithm.onReset(view);
}
private void updateScrollPositionOnExpandInBottom(ExpandableView view) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java
index fc2be1af7049..fe855d92e6cd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java
@@ -758,39 +758,42 @@ public class StackScrollAlgorithm {
// current height.
mFirstChildMaxHeight = mFirstChildWhileExpanding.getActualHeight();
} else {
-
- // We are expanding the shade, expand it to its full height.
- if (!isMaxSizeInitialized(mFirstChildWhileExpanding)) {
-
- // This child was not layouted yet, wait for a layout pass
- mFirstChildWhileExpanding
- .addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
- @Override
- public void onLayoutChange(View v, int left, int top, int right,
- int bottom, int oldLeft, int oldTop, int oldRight,
- int oldBottom) {
- if (mFirstChildWhileExpanding != null) {
- mFirstChildMaxHeight = getMaxAllowedChildHeight(
- mFirstChildWhileExpanding);
- } else {
- mFirstChildMaxHeight = 0;
- }
- v.removeOnLayoutChangeListener(this);
- }
- });
- } else {
- mFirstChildMaxHeight = getMaxAllowedChildHeight(mFirstChildWhileExpanding);
- }
+ updateFirstChildMaxSizeToMaxHeight();
}
} else {
mFirstChildMaxHeight = 0;
}
}
+ private void updateFirstChildMaxSizeToMaxHeight() {
+ // We are expanding the shade, expand it to its full height.
+ if (!isMaxSizeInitialized(mFirstChildWhileExpanding)) {
+
+ // This child was not layouted yet, wait for a layout pass
+ mFirstChildWhileExpanding
+ .addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
+ @Override
+ public void onLayoutChange(View v, int left, int top, int right,
+ int bottom, int oldLeft, int oldTop, int oldRight,
+ int oldBottom) {
+ if (mFirstChildWhileExpanding != null) {
+ mFirstChildMaxHeight = getMaxAllowedChildHeight(
+ mFirstChildWhileExpanding);
+ } else {
+ mFirstChildMaxHeight = 0;
+ }
+ v.removeOnLayoutChangeListener(this);
+ }
+ });
+ } else {
+ mFirstChildMaxHeight = getMaxAllowedChildHeight(mFirstChildWhileExpanding);
+ }
+ }
+
private boolean isMaxSizeInitialized(ExpandableView child) {
if (child instanceof ExpandableNotificationRow) {
ExpandableNotificationRow row = (ExpandableNotificationRow) child;
- return row.isShowingLayoutLayouted();
+ return row.isMaxExpandHeightInitialized();
}
return child == null || child.getWidth() != 0;
}
@@ -825,6 +828,12 @@ public class StackScrollAlgorithm {
updatePadding(dimmed);
}
+ public void onReset(ExpandableView view) {
+ if (view.equals(mFirstChildWhileExpanding)) {
+ updateFirstChildMaxSizeToMaxHeight();
+ }
+ }
+
class StackScrollAlgorithmState {
/**
diff --git a/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java b/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java
index 0d837c79b54c..c99e1fd41de3 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java
@@ -97,14 +97,16 @@ public class ZenModePanel extends LinearLayout {
private Callback mCallback;
private ZenModeController mController;
private boolean mRequestingConditions;
- private Uri mExitConditionId;
+ private Condition mExitCondition;
+ private String mExitConditionText;
private int mBucketIndex = -1;
private boolean mExpanded;
private boolean mHidden = false;
private int mSessionZen;
- private Uri mSessionExitConditionId;
- private String mExitConditionText;
+ private Condition mSessionExitCondition;
private long mNextAlarm;
+ private Condition[] mConditions;
+ private Condition mTimeCondition;
public ZenModePanel(Context context, AttributeSet attrs) {
super(context, attrs);
@@ -161,7 +163,7 @@ public class ZenModePanel extends LinearLayout {
super.onAttachedToWindow();
if (DEBUG) Log.d(mTag, "onAttachedToWindow");
mSessionZen = getSelectedZen(-1);
- mSessionExitConditionId = mExitConditionId;
+ mSessionExitCondition = copy(mExitCondition);
refreshExitConditionText();
refreshNextAlarm();
updateWidgets();
@@ -172,7 +174,7 @@ public class ZenModePanel extends LinearLayout {
super.onDetachedFromWindow();
if (DEBUG) Log.d(mTag, "onDetachedFromWindow");
mSessionZen = -1;
- mSessionExitConditionId = null;
+ mSessionExitCondition = null;
setExpanded(false);
}
@@ -199,17 +201,16 @@ public class ZenModePanel extends LinearLayout {
mController.requestConditions(mRequestingConditions);
}
if (mRequestingConditions) {
- Condition timeCondition = parseExistingTimeCondition(mExitConditionId);
- if (timeCondition != null) {
+ mTimeCondition = parseExistingTimeCondition(mExitCondition);
+ if (mTimeCondition != null) {
mBucketIndex = -1;
} else {
mBucketIndex = DEFAULT_BUCKET_INDEX;
- timeCondition = newTimeCondition(MINUTE_BUCKETS[mBucketIndex]);
+ mTimeCondition = newTimeCondition(MINUTE_BUCKETS[mBucketIndex]);
}
if (DEBUG) Log.d(mTag, "Initial bucket index: " + mBucketIndex);
- handleUpdateConditions(new Condition[0]); // ensures forever exists
- bind(timeCondition, mZenConditions.getChildAt(TIME_CONDITION_INDEX));
- checkForDefault();
+ mConditions = null; // reset conditions
+ handleUpdateConditions();
} else {
mZenConditions.removeAllViews();
}
@@ -217,31 +218,47 @@ public class ZenModePanel extends LinearLayout {
public void init(ZenModeController controller) {
mController = controller;
- setExitConditionId(mController.getExitConditionId());
+ setExitCondition(mController.getExitCondition());
refreshExitConditionText();
mSessionZen = getSelectedZen(-1);
handleUpdateZen(mController.getZen());
- if (DEBUG) Log.d(mTag, "init mExitConditionId=" + mExitConditionId);
+ if (DEBUG) Log.d(mTag, "init mExitCondition=" + mExitCondition);
mZenConditions.removeAllViews();
mController.addCallback(mZenCallback);
}
- private void setExitConditionId(Uri exitConditionId) {
- if (Objects.equals(mExitConditionId, exitConditionId)) return;
- mExitConditionId = exitConditionId;
+ private void setExitCondition(Condition exitCondition) {
+ if (sameConditionId(mExitCondition, exitCondition)) return;
+ mExitCondition = exitCondition;
refreshExitConditionText();
updateWidgets();
}
+ private Uri getExitConditionId() {
+ return getConditionId(mExitCondition);
+ }
+
+ private static Uri getConditionId(Condition condition) {
+ return condition != null ? condition.id : null;
+ }
+
+ private static boolean sameConditionId(Condition lhs, Condition rhs) {
+ return lhs == null ? rhs == null : rhs != null && lhs.id.equals(rhs.id);
+ }
+
+ private static Condition copy(Condition condition) {
+ return condition == null ? null : condition.copy();
+ }
+
private void refreshExitConditionText() {
final String forever = mContext.getString(R.string.zen_mode_forever);
- if (mExitConditionId == null) {
+ if (mExitCondition == null) {
mExitConditionText = forever;
- } else if (ZenModeConfig.isValidCountdownConditionId(mExitConditionId)) {
- final Condition condition = parseExistingTimeCondition(mExitConditionId);
+ } else if (ZenModeConfig.isValidCountdownConditionId(mExitCondition.id)) {
+ final Condition condition = parseExistingTimeCondition(mExitCondition);
mExitConditionText = condition != null ? condition.summary : forever;
} else {
- mExitConditionText = "(until condition ends)"; // TODO persist current description
+ mExitConditionText = mExitCondition.summary;
}
}
@@ -296,7 +313,7 @@ public class ZenModePanel extends LinearLayout {
mZenConditions.setVisibility(!zenOff && expanded ? VISIBLE : GONE);
mAlarmWarning.setVisibility(zenNone && expanded && hasNextAlarm ? VISIBLE : GONE);
if (showAlarmWarning) {
- final long exitTime = ZenModeConfig.tryParseCountdownConditionId(mExitConditionId);
+ final long exitTime = ZenModeConfig.tryParseCountdownConditionId(getExitConditionId());
final long now = System.currentTimeMillis();
final boolean alarmToday = time(mNextAlarm).yearDay == time(now).yearDay;
final String skeleton = (alarmToday ? "" : "E")
@@ -330,8 +347,9 @@ public class ZenModePanel extends LinearLayout {
return t;
}
- private Condition parseExistingTimeCondition(Uri conditionId) {
- final long time = ZenModeConfig.tryParseCountdownConditionId(conditionId);
+ private Condition parseExistingTimeCondition(Condition condition) {
+ if (condition == null) return null;
+ final long time = ZenModeConfig.tryParseCountdownConditionId(condition.id);
if (time == 0) return null;
final long span = time - System.currentTimeMillis();
if (span <= 0 || span > MAX_BUCKET_MINUTES * MINUTES_MS) return null;
@@ -365,15 +383,36 @@ public class ZenModePanel extends LinearLayout {
}
private void handleUpdateConditions(Condition[] conditions) {
- final int newCount = conditions == null ? 0 : conditions.length;
- if (DEBUG) Log.d(mTag, "handleUpdateConditions newCount=" + newCount);
- for (int i = mZenConditions.getChildCount(); i >= newCount + FIRST_CONDITION_INDEX; i--) {
+ mConditions = conditions;
+ handleUpdateConditions();
+ }
+
+ private void handleUpdateConditions() {
+ final int conditionCount = mConditions == null ? 0 : mConditions.length;
+ if (DEBUG) Log.d(mTag, "handleUpdateConditions conditionCount=" + conditionCount);
+ for (int i = mZenConditions.getChildCount() - 1; i >= FIRST_CONDITION_INDEX; i--) {
mZenConditions.removeViewAt(i);
}
+ // forever
bind(null, mZenConditions.getChildAt(FOREVER_CONDITION_INDEX));
- for (int i = 0; i < newCount; i++) {
- bind(conditions[i], mZenConditions.getChildAt(FIRST_CONDITION_INDEX + i));
+ // countdown
+ bind(mTimeCondition, mZenConditions.getChildAt(TIME_CONDITION_INDEX));
+ // provider conditions
+ boolean foundDowntime = false;
+ for (int i = 0; i < conditionCount; i++) {
+ bind(mConditions[i], mZenConditions.getChildAt(FIRST_CONDITION_INDEX + i));
+ foundDowntime |= isDowntime(mConditions[i]);
}
+ // ensure downtime exists, if active
+ if (isDowntime(mSessionExitCondition) && !foundDowntime) {
+ bind(mSessionExitCondition, null);
+ }
+ // ensure something is selected
+ checkForDefault();
+ }
+
+ private static boolean isDowntime(Condition c) {
+ return ZenModeConfig.isValidDowntimeConditionId(getConditionId(c));
}
private ConditionTag getConditionTagAt(int index) {
@@ -385,7 +424,7 @@ public class ZenModePanel extends LinearLayout {
for (int i = 0; i < mZenConditions.getChildCount(); i++) {
if (getConditionTagAt(i).rb.isChecked()) {
if (DEBUG) Log.d(mTag, "Not selecting a default, checked="
- + getConditionTagAt(i).conditionId);
+ + getConditionTagAt(i).condition);
return;
}
}
@@ -394,20 +433,20 @@ public class ZenModePanel extends LinearLayout {
if (favoriteIndex == -1) {
getConditionTagAt(FOREVER_CONDITION_INDEX).rb.setChecked(true);
} else {
- final Condition c = newTimeCondition(MINUTE_BUCKETS[favoriteIndex]);
+ mTimeCondition = newTimeCondition(MINUTE_BUCKETS[favoriteIndex]);
mBucketIndex = favoriteIndex;
- bind(c, mZenConditions.getChildAt(TIME_CONDITION_INDEX));
+ bind(mTimeCondition, mZenConditions.getChildAt(TIME_CONDITION_INDEX));
getConditionTagAt(TIME_CONDITION_INDEX).rb.setChecked(true);
}
}
- private void handleExitConditionChanged(Uri exitCondition) {
- setExitConditionId(exitCondition);
- if (DEBUG) Log.d(mTag, "handleExitConditionChanged " + mExitConditionId);
+ private void handleExitConditionChanged(Condition exitCondition) {
+ setExitCondition(exitCondition);
+ if (DEBUG) Log.d(mTag, "handleExitConditionChanged " + mExitCondition);
final int N = mZenConditions.getChildCount();
for (int i = 0; i < N; i++) {
final ConditionTag tag = getConditionTagAt(i);
- tag.rb.setChecked(Objects.equals(tag.conditionId, exitCondition));
+ tag.rb.setChecked(sameConditionId(tag.condition, mExitCondition));
}
}
@@ -427,23 +466,23 @@ public class ZenModePanel extends LinearLayout {
if (tag.rb == null) {
tag.rb = (RadioButton) row.findViewById(android.R.id.checkbox);
}
- tag.conditionId = condition != null ? condition.id : null;
+ tag.condition = condition;
tag.rb.setEnabled(enabled);
- if (mSessionExitConditionId != null && mSessionExitConditionId.equals(tag.conditionId)) {
+ if (sameConditionId(mSessionExitCondition, tag.condition)) {
tag.rb.setChecked(true);
}
tag.rb.setOnCheckedChangeListener(new OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if (mExpanded && isChecked) {
- if (DEBUG) Log.d(mTag, "onCheckedChanged " + tag.conditionId);
+ if (DEBUG) Log.d(mTag, "onCheckedChanged " + tag.condition);
final int N = mZenConditions.getChildCount();
for (int i = 0; i < N; i++) {
ConditionTag childTag = getConditionTagAt(i);
if (childTag == tag) continue;
childTag.rb.setChecked(false);
}
- select(tag.conditionId);
+ select(tag.condition);
fireInteraction();
}
}
@@ -479,7 +518,7 @@ public class ZenModePanel extends LinearLayout {
}
});
- final long time = ZenModeConfig.tryParseCountdownConditionId(tag.conditionId);
+ final long time = ZenModeConfig.tryParseCountdownConditionId(getConditionId(tag.condition));
if (time > 0) {
if (mBucketIndex > -1) {
button1.setEnabled(mBucketIndex > 0);
@@ -504,7 +543,8 @@ public class ZenModePanel extends LinearLayout {
final int N = MINUTE_BUCKETS.length;
if (mBucketIndex == -1) {
// not on a known index, search for the next or prev bucket by time
- final long time = ZenModeConfig.tryParseCountdownConditionId(tag.conditionId);
+ final Uri conditionId = getConditionId(tag.condition);
+ final long time = ZenModeConfig.tryParseCountdownConditionId(conditionId);
final long now = System.currentTimeMillis();
for (int i = 0; i < N; i++) {
int j = up ? i : N - 1 - i;
@@ -525,24 +565,25 @@ public class ZenModePanel extends LinearLayout {
mBucketIndex = Math.max(0, Math.min(N - 1, mBucketIndex + (up ? 1 : -1)));
newCondition = newTimeCondition(MINUTE_BUCKETS[mBucketIndex]);
}
- bind(newCondition, row);
+ mTimeCondition = newCondition;
+ bind(mTimeCondition, row);
tag.rb.setChecked(true);
- select(newCondition.id);
+ select(mTimeCondition);
fireInteraction();
}
- private void select(Uri conditionId) {
- if (DEBUG) Log.d(mTag, "select " + conditionId);
+ private void select(Condition condition) {
+ if (DEBUG) Log.d(mTag, "select " + condition);
if (mController != null) {
- mController.setExitConditionId(conditionId);
+ mController.setExitCondition(condition);
}
- setExitConditionId(conditionId);
- if (conditionId == null) {
+ setExitCondition(condition);
+ if (condition == null) {
mFavorites.setMinuteIndex(-1);
- } else if (ZenModeConfig.isValidCountdownConditionId(conditionId) && mBucketIndex != -1) {
+ } else if (ZenModeConfig.isValidCountdownConditionId(condition.id) && mBucketIndex != -1) {
mFavorites.setMinuteIndex(mBucketIndex);
}
- mSessionExitConditionId = conditionId;
+ mSessionExitCondition = copy(condition);
}
private void fireMoreSettings() {
@@ -574,8 +615,8 @@ public class ZenModePanel extends LinearLayout {
}
@Override
- public void onExitConditionChanged(Uri exitConditionId) {
- mHandler.obtainMessage(H.EXIT_CONDITION_CHANGED, exitConditionId).sendToTarget();
+ public void onExitConditionChanged(Condition exitCondition) {
+ mHandler.obtainMessage(H.EXIT_CONDITION_CHANGED, exitCondition).sendToTarget();
}
@Override
@@ -598,9 +639,8 @@ public class ZenModePanel extends LinearLayout {
public void handleMessage(Message msg) {
if (msg.what == UPDATE_CONDITIONS) {
handleUpdateConditions((Condition[]) msg.obj);
- checkForDefault();
} else if (msg.what == EXIT_CONDITION_CHANGED) {
- handleExitConditionChanged((Uri) msg.obj);
+ handleExitConditionChanged((Condition) msg.obj);
} else if (msg.what == UPDATE_ZEN) {
handleUpdateZen(msg.arg1);
} else if (msg.what == NEXT_ALARM_CHANGED) {
@@ -618,7 +658,7 @@ public class ZenModePanel extends LinearLayout {
// used as the view tag on condition rows
private static class ConditionTag {
RadioButton rb;
- Uri conditionId;
+ Condition condition;
}
private final class Favorites implements OnSharedPreferenceChangeListener {
diff --git a/services/appwidget/Android.mk b/services/appwidget/Android.mk
index ca38f2f6449d..e9bab4a94a30 100644
--- a/services/appwidget/Android.mk
+++ b/services/appwidget/Android.mk
@@ -7,4 +7,6 @@ LOCAL_MODULE := services.appwidget
LOCAL_SRC_FILES += \
$(call all-java-files-under,java)
+LOCAL_JAVA_LIBRARIES := services.core
+
include $(BUILD_STATIC_JAVA_LIBRARY)
diff --git a/services/backup/java/com/android/server/backup/BackupManagerService.java b/services/backup/java/com/android/server/backup/BackupManagerService.java
index b2d1b717b527..c44474d901be 100644
--- a/services/backup/java/com/android/server/backup/BackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/BackupManagerService.java
@@ -8599,7 +8599,15 @@ if (MORE_DEBUG) Slog.v(TAG, " + got " + nRead + "; now wanting " + (size - soF
skip = true;
}
- if (!skip && mAutoRestore && mProvisioned) {
+ if (!mAutoRestore || !mProvisioned) {
+ if (DEBUG) {
+ Slog.w(TAG, "Non-restorable state: auto=" + mAutoRestore
+ + " prov=" + mProvisioned);
+ }
+ skip = true;
+ }
+
+ if (!skip) {
try {
// okay, we're going to attempt a restore of this package from this restore set.
// The eventual message back into the Package Manager to run the post-install
@@ -8632,7 +8640,7 @@ if (MORE_DEBUG) Slog.v(TAG, " + got " + nRead + "; now wanting " + (size - soF
if (skip) {
// Auto-restore disabled or no way to attempt a restore; just tell the Package
// Manager to proceed with the post-install handling for this package.
- if (DEBUG) Slog.v(TAG, "Skipping");
+ if (DEBUG) Slog.v(TAG, "Finishing install immediately");
try {
mPackageManagerBinder.finishPackageInstall(token);
} catch (RemoteException e) { /* can't happen */ }
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index dd5a7ea5f6c4..02695c5216bc 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -1534,11 +1534,17 @@ public class ConnectivityService extends IConnectivityManager.Stub {
return;
}
- if (mtu < 68 || mtu > 10000) {
+ if (LinkProperties.isValidMtu(mtu, newLp.hasGlobalIPv6Address())) {
loge("Unexpected mtu value: " + mtu + ", " + iface);
return;
}
+ // Cannot set MTU without interface name
+ if (TextUtils.isEmpty(iface)) {
+ loge("Setting MTU size with null iface.");
+ return;
+ }
+
try {
if (VDBG) log("Setting MTU size: " + iface + ", " + mtu);
mNetd.setMtu(iface, mtu);
diff --git a/services/core/java/com/android/server/NetworkScoreService.java b/services/core/java/com/android/server/NetworkScoreService.java
index ab4d4dca06d4..395e365c421d 100644
--- a/services/core/java/com/android/server/NetworkScoreService.java
+++ b/services/core/java/com/android/server/NetworkScoreService.java
@@ -17,9 +17,9 @@
package com.android.server;
import android.Manifest.permission;
+import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
-import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.net.INetworkScoreCache;
import android.net.INetworkScoreService;
@@ -30,6 +30,7 @@ import android.net.ScoredNetwork;
import android.os.Binder;
import android.os.RemoteException;
import android.os.UserHandle;
+import android.provider.Settings;
import android.text.TextUtils;
import android.util.Log;
@@ -51,9 +52,6 @@ import java.util.Set;
public class NetworkScoreService extends INetworkScoreService.Stub {
private static final String TAG = "NetworkScoreService";
- /** SharedPreference bit set to true after the service is first initialized. */
- private static final String PREF_SCORING_PROVISIONED = "is_provisioned";
-
private final Context mContext;
private final Map<Integer, INetworkScoreCache> mScoreCaches;
@@ -65,8 +63,8 @@ public class NetworkScoreService extends INetworkScoreService.Stub {
/** Called when the system is ready to run third-party code but before it actually does so. */
void systemReady() {
- SharedPreferences prefs = mContext.getSharedPreferences(TAG, Context.MODE_PRIVATE);
- if (!prefs.getBoolean(PREF_SCORING_PROVISIONED, false)) {
+ ContentResolver cr = mContext.getContentResolver();
+ if (Settings.Global.getInt(cr, Settings.Global.NETWORK_SCORING_PROVISIONED, 0) == 0) {
// On first run, we try to initialize the scorer to the one configured at build time.
// This will be a no-op if the scorer isn't actually valid.
String defaultPackage = mContext.getResources().getString(
@@ -74,7 +72,7 @@ public class NetworkScoreService extends INetworkScoreService.Stub {
if (!TextUtils.isEmpty(defaultPackage)) {
NetworkScorerAppManager.setActiveScorer(mContext, defaultPackage);
}
- prefs.edit().putBoolean(PREF_SCORING_PROVISIONED, true).apply();
+ Settings.Global.putInt(cr, Settings.Global.NETWORK_SCORING_PROVISIONED, 1);
}
}
diff --git a/core/java/com/android/server/SystemService.java b/services/core/java/com/android/server/SystemService.java
index 6e67970c1fc5..6e67970c1fc5 100644
--- a/core/java/com/android/server/SystemService.java
+++ b/services/core/java/com/android/server/SystemService.java
diff --git a/core/java/com/android/server/SystemServiceManager.java b/services/core/java/com/android/server/SystemServiceManager.java
index fda6479e2d56..fda6479e2d56 100644
--- a/core/java/com/android/server/SystemServiceManager.java
+++ b/services/core/java/com/android/server/SystemServiceManager.java
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index ad2704ae5bcc..ecd8f11fba09 100755
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -2031,7 +2031,7 @@ public final class ActivityManagerService extends ActivityManagerNative
ApplicationInfo info = mContext.getPackageManager().getApplicationInfo(
"android", STOCK_PM_FLAGS);
- mSystemThread.installSystemApplicationInfo(info);
+ mSystemThread.installSystemApplicationInfo(info, getClass().getClassLoader());
synchronized (this) {
ProcessRecord app = newProcessRecordLocked(info, info.processName, false, 0);
diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java
index 9a6732126ebd..46cb6c398d99 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController.java
@@ -37,7 +37,7 @@ import android.os.Message;
import android.os.PowerManager;
import android.os.RemoteException;
import android.os.SystemClock;
-import android.text.format.DateUtils;
+import android.os.Trace;
import android.util.MathUtils;
import android.util.Slog;
import android.util.Spline;
@@ -74,6 +74,8 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
private static boolean DEBUG = false;
private static final boolean DEBUG_PRETEND_PROXIMITY_SENSOR_ABSENT = false;
+ private static final String SCREEN_ON_BLOCKED_TRACE_NAME = "Screen on blocked";
+
// If true, uses the electron beam on animation.
// We might want to turn this off if we cannot get a guarantee that the screen
// actually turns on and starts showing new content after the call to set the
@@ -714,11 +716,10 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
private void blockScreenOn() {
if (!mScreenOnWasBlocked) {
+ Trace.asyncTraceBegin(Trace.TRACE_TAG_POWER, SCREEN_ON_BLOCKED_TRACE_NAME, 0);
mScreenOnWasBlocked = true;
mScreenOnBlockStartRealTime = SystemClock.elapsedRealtime();
- if (DEBUG) {
- Slog.d(TAG, "Blocked screen on.");
- }
+ Slog.i(TAG, "Blocking screen on until initial contents have been drawn.");
}
}
@@ -726,9 +727,8 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
if (mScreenOnWasBlocked) {
mScreenOnWasBlocked = false;
long delay = SystemClock.elapsedRealtime() - mScreenOnBlockStartRealTime;
- if (delay > 1000 || DEBUG) {
- Slog.d(TAG, "Unblocked screen on after " + delay + " ms");
- }
+ Slog.i(TAG, "Unblocked screen on after " + delay + " ms");
+ Trace.asyncTraceEnd(Trace.TRACE_TAG_POWER, SCREEN_ON_BLOCKED_TRACE_NAME, 0);
}
}
diff --git a/services/core/java/com/android/server/display/DisplayPowerState.java b/services/core/java/com/android/server/display/DisplayPowerState.java
index 6522b89e2d42..a7651e42107e 100644
--- a/services/core/java/com/android/server/display/DisplayPowerState.java
+++ b/services/core/java/com/android/server/display/DisplayPowerState.java
@@ -23,6 +23,7 @@ import android.os.AsyncTask;
import android.os.Handler;
import android.os.Looper;
import android.os.PowerManager;
+import android.os.Trace;
import android.util.FloatProperty;
import android.util.IntProperty;
import android.util.Slog;
@@ -405,19 +406,38 @@ final class DisplayPowerState {
}
boolean suspending = Display.isSuspendedState(state);
if (stateChanged && !suspending) {
- mBlanker.requestDisplayState(state);
+ requestDisplayState(state);
}
if (backlightChanged) {
- mBacklight.setBrightness(backlight);
+ setBrightness(backlight);
}
if (stateChanged && suspending) {
- mBlanker.requestDisplayState(state);
+ requestDisplayState(state);
}
}
// Let the outer class know that all changes have been applied.
postScreenUpdateThreadSafe();
}
+
+ private void requestDisplayState(int state) {
+ Trace.traceBegin(Trace.TRACE_TAG_POWER, "requestDisplayState("
+ + Display.stateToString(state) + ")");
+ try {
+ mBlanker.requestDisplayState(state);
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_POWER);
+ }
+ }
+
+ private void setBrightness(int backlight) {
+ Trace.traceBegin(Trace.TRACE_TAG_POWER, "setBrightness(" + backlight + ")");
+ try {
+ mBacklight.setBrightness(backlight);
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_POWER);
+ }
+ }
};
}
}
diff --git a/services/core/java/com/android/server/display/LocalDisplayAdapter.java b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
index 4fd006d7e70a..9c91ab505f2f 100644
--- a/services/core/java/com/android/server/display/LocalDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
@@ -21,7 +21,7 @@ import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
import android.os.SystemProperties;
-import android.util.Pair;
+import android.os.Trace;
import android.util.Slog;
import android.util.SparseArray;
import android.view.Display;
@@ -224,8 +224,14 @@ final class LocalDisplayAdapter extends DisplayAdapter {
@Override
public void requestDisplayStateLocked(int state) {
if (mState != state) {
- SurfaceControl.setDisplayPowerMode(getDisplayTokenLocked(),
- getPowerModeForState(state));
+ final int mode = getPowerModeForState(state);
+ Trace.traceBegin(Trace.TRACE_TAG_POWER, "requestDisplayState("
+ + Display.stateToString(state) + ", id=" + mBuiltInDisplayId + ")");
+ try {
+ SurfaceControl.setDisplayPowerMode(getDisplayTokenLocked(), mode);
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_POWER);
+ }
mState = state;
updateDeviceInfoLocked();
}
diff --git a/services/core/java/com/android/server/dreams/DreamController.java b/services/core/java/com/android/server/dreams/DreamController.java
index 334f0aca497d..768ccf228513 100644
--- a/services/core/java/com/android/server/dreams/DreamController.java
+++ b/services/core/java/com/android/server/dreams/DreamController.java
@@ -25,6 +25,7 @@ import android.os.Handler;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.IBinder.DeathRecipient;
+import android.os.Trace;
import android.os.UserHandle;
import android.service.dreams.DreamService;
import android.service.dreams.IDreamService;
@@ -111,41 +112,46 @@ final class DreamController {
boolean isTest, boolean canDoze, int userId) {
stopDream(true /*immediate*/);
- // Close the notification shade. Don't need to send to all, but better to be explicit.
- mContext.sendBroadcastAsUser(mCloseNotificationShadeIntent, UserHandle.ALL);
+ Trace.traceBegin(Trace.TRACE_TAG_POWER, "startDream");
+ try {
+ // Close the notification shade. Don't need to send to all, but better to be explicit.
+ mContext.sendBroadcastAsUser(mCloseNotificationShadeIntent, UserHandle.ALL);
- Slog.i(TAG, "Starting dream: name=" + name
- + ", isTest=" + isTest + ", canDoze=" + canDoze
- + ", userId=" + userId);
+ Slog.i(TAG, "Starting dream: name=" + name
+ + ", isTest=" + isTest + ", canDoze=" + canDoze
+ + ", userId=" + userId);
- mCurrentDream = new DreamRecord(token, name, isTest, canDoze, userId);
+ mCurrentDream = new DreamRecord(token, name, isTest, canDoze, userId);
- try {
- mIWindowManager.addWindowToken(token, WindowManager.LayoutParams.TYPE_DREAM);
- } catch (RemoteException ex) {
- Slog.e(TAG, "Unable to add window token for dream.", ex);
- stopDream(true /*immediate*/);
- return;
- }
+ try {
+ mIWindowManager.addWindowToken(token, WindowManager.LayoutParams.TYPE_DREAM);
+ } catch (RemoteException ex) {
+ Slog.e(TAG, "Unable to add window token for dream.", ex);
+ stopDream(true /*immediate*/);
+ return;
+ }
- Intent intent = new Intent(DreamService.SERVICE_INTERFACE);
- intent.setComponent(name);
- intent.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
- try {
- if (!mContext.bindServiceAsUser(intent, mCurrentDream,
- Context.BIND_AUTO_CREATE, new UserHandle(userId))) {
- Slog.e(TAG, "Unable to bind dream service: " + intent);
+ Intent intent = new Intent(DreamService.SERVICE_INTERFACE);
+ intent.setComponent(name);
+ intent.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
+ try {
+ if (!mContext.bindServiceAsUser(intent, mCurrentDream,
+ Context.BIND_AUTO_CREATE, new UserHandle(userId))) {
+ Slog.e(TAG, "Unable to bind dream service: " + intent);
+ stopDream(true /*immediate*/);
+ return;
+ }
+ } catch (SecurityException ex) {
+ Slog.e(TAG, "Unable to bind dream service: " + intent, ex);
stopDream(true /*immediate*/);
return;
}
- } catch (SecurityException ex) {
- Slog.e(TAG, "Unable to bind dream service: " + intent, ex);
- stopDream(true /*immediate*/);
- return;
- }
- mCurrentDream.mBound = true;
- mHandler.postDelayed(mStopUnconnectedDreamRunnable, DREAM_CONNECTION_TIMEOUT);
+ mCurrentDream.mBound = true;
+ mHandler.postDelayed(mStopUnconnectedDreamRunnable, DREAM_CONNECTION_TIMEOUT);
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_POWER);
+ }
}
public void stopDream(boolean immediate) {
@@ -153,71 +159,76 @@ final class DreamController {
return;
}
- if (!immediate) {
- if (mCurrentDream.mWakingGently) {
- return; // already waking gently
- }
+ Trace.traceBegin(Trace.TRACE_TAG_POWER, "stopDream");
+ try {
+ if (!immediate) {
+ if (mCurrentDream.mWakingGently) {
+ return; // already waking gently
+ }
- if (mCurrentDream.mService != null) {
- // Give the dream a moment to wake up and finish itself gently.
- mCurrentDream.mWakingGently = true;
- try {
- mCurrentDream.mService.wakeUp();
- mHandler.postDelayed(mStopStubbornDreamRunnable, DREAM_FINISH_TIMEOUT);
- return;
- } catch (RemoteException ex) {
- // oh well, we tried, finish immediately instead
+ if (mCurrentDream.mService != null) {
+ // Give the dream a moment to wake up and finish itself gently.
+ mCurrentDream.mWakingGently = true;
+ try {
+ mCurrentDream.mService.wakeUp();
+ mHandler.postDelayed(mStopStubbornDreamRunnable, DREAM_FINISH_TIMEOUT);
+ return;
+ } catch (RemoteException ex) {
+ // oh well, we tried, finish immediately instead
+ }
}
}
- }
- final DreamRecord oldDream = mCurrentDream;
- mCurrentDream = null;
- Slog.i(TAG, "Stopping dream: name=" + oldDream.mName
- + ", isTest=" + oldDream.mIsTest + ", canDoze=" + oldDream.mCanDoze
- + ", userId=" + oldDream.mUserId);
+ final DreamRecord oldDream = mCurrentDream;
+ mCurrentDream = null;
+ Slog.i(TAG, "Stopping dream: name=" + oldDream.mName
+ + ", isTest=" + oldDream.mIsTest + ", canDoze=" + oldDream.mCanDoze
+ + ", userId=" + oldDream.mUserId);
- mHandler.removeCallbacks(mStopUnconnectedDreamRunnable);
- mHandler.removeCallbacks(mStopStubbornDreamRunnable);
+ mHandler.removeCallbacks(mStopUnconnectedDreamRunnable);
+ mHandler.removeCallbacks(mStopStubbornDreamRunnable);
- if (oldDream.mSentStartBroadcast) {
- mContext.sendBroadcastAsUser(mDreamingStoppedIntent, UserHandle.ALL);
- }
+ if (oldDream.mSentStartBroadcast) {
+ mContext.sendBroadcastAsUser(mDreamingStoppedIntent, UserHandle.ALL);
+ }
- if (oldDream.mService != null) {
- // Tell the dream that it's being stopped so that
- // it can shut down nicely before we yank its window token out from
- // under it.
- try {
- oldDream.mService.detach();
- } catch (RemoteException ex) {
- // we don't care; this thing is on the way out
+ if (oldDream.mService != null) {
+ // Tell the dream that it's being stopped so that
+ // it can shut down nicely before we yank its window token out from
+ // under it.
+ try {
+ oldDream.mService.detach();
+ } catch (RemoteException ex) {
+ // we don't care; this thing is on the way out
+ }
+
+ try {
+ oldDream.mService.asBinder().unlinkToDeath(oldDream, 0);
+ } catch (NoSuchElementException ex) {
+ // don't care
+ }
+ oldDream.mService = null;
}
- try {
- oldDream.mService.asBinder().unlinkToDeath(oldDream, 0);
- } catch (NoSuchElementException ex) {
- // don't care
+ if (oldDream.mBound) {
+ mContext.unbindService(oldDream);
}
- oldDream.mService = null;
- }
- if (oldDream.mBound) {
- mContext.unbindService(oldDream);
- }
+ try {
+ mIWindowManager.removeWindowToken(oldDream.mToken);
+ } catch (RemoteException ex) {
+ Slog.w(TAG, "Error removing window token for dream.", ex);
+ }
- try {
- mIWindowManager.removeWindowToken(oldDream.mToken);
- } catch (RemoteException ex) {
- Slog.w(TAG, "Error removing window token for dream.", ex);
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ mListener.onDreamStopped(oldDream.mToken);
+ }
+ });
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_POWER);
}
-
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- mListener.onDreamStopped(oldDream.mToken);
- }
- });
}
private void attach(IDreamService service) {
diff --git a/services/core/java/com/android/server/lights/LightsService.java b/services/core/java/com/android/server/lights/LightsService.java
index 94cf6689e921..9dcc5294b36f 100644
--- a/services/core/java/com/android/server/lights/LightsService.java
+++ b/services/core/java/com/android/server/lights/LightsService.java
@@ -23,6 +23,7 @@ import android.content.pm.PackageManager;
import android.os.Handler;
import android.os.IHardwareService;
import android.os.Message;
+import android.os.Trace;
import android.util.Slog;
import java.io.FileInputStream;
@@ -105,7 +106,12 @@ public class LightsService extends SystemService {
mMode = mode;
mOnMS = onMS;
mOffMS = offMS;
- setLight_native(mNativePointer, mId, color, mode, onMS, offMS, brightnessMode);
+ Trace.traceBegin(Trace.TRACE_TAG_POWER, "setLight(" + mId + ", " + color + ")");
+ try {
+ setLight_native(mNativePointer, mId, color, mode, onMS, offMS, brightnessMode);
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_POWER);
+ }
}
}
diff --git a/services/core/java/com/android/server/notification/ConditionProviders.java b/services/core/java/com/android/server/notification/ConditionProviders.java
index a06daf637496..189131c557f4 100644
--- a/services/core/java/com/android/server/notification/ConditionProviders.java
+++ b/services/core/java/com/android/server/notification/ConditionProviders.java
@@ -51,8 +51,9 @@ public class ConditionProviders extends ManagedServices {
= new ArrayMap<IBinder, IConditionListener>();
private final ArrayList<ConditionRecord> mRecords = new ArrayList<ConditionRecord>();
private final CountdownConditionProvider mCountdown = new CountdownConditionProvider();
+ private final DowntimeConditionProvider mDowntime = new DowntimeConditionProvider();
- private Uri mExitConditionId;
+ private Condition mExitCondition;
private ComponentName mExitConditionComponent;
public ConditionProviders(Context context, Handler handler,
@@ -97,6 +98,7 @@ public class ConditionProviders extends ManagedServices {
}
}
mCountdown.dump(pw, filter);
+ mDowntime.dump(pw, filter);
}
@Override
@@ -110,6 +112,10 @@ public class ConditionProviders extends ManagedServices {
mCountdown.attachBase(mContext);
registerService(mCountdown.asInterface(), CountdownConditionProvider.COMPONENT,
UserHandle.USER_OWNER);
+ mDowntime.attachBase(mContext);
+ registerService(mDowntime.asInterface(), DowntimeConditionProvider.COMPONENT,
+ UserHandle.USER_OWNER);
+ mDowntime.setCallback(new DowntimeCallback());
}
@Override
@@ -125,7 +131,7 @@ public class ConditionProviders extends ManagedServices {
if (info.component.equals(mExitConditionComponent)) {
// ensure record exists, we'll wire it up and subscribe below
final ConditionRecord manualRecord =
- getRecordLocked(mExitConditionId, mExitConditionComponent);
+ getRecordLocked(mExitCondition.id, mExitConditionComponent);
manualRecord.isManual = true;
}
final int N = mRecords.size();
@@ -149,11 +155,11 @@ public class ConditionProviders extends ManagedServices {
if (!r.component.equals(removed.component)) continue;
if (r.isManual) {
// removing the current manual condition, exit zen
- mZenModeHelper.setZenMode(Global.ZEN_MODE_OFF);
+ mZenModeHelper.setZenMode(Global.ZEN_MODE_OFF, "manualServiceRemoved");
}
if (r.isAutomatic) {
// removing an automatic condition, exit zen
- mZenModeHelper.setZenMode(Global.ZEN_MODE_OFF);
+ mZenModeHelper.setZenMode(Global.ZEN_MODE_OFF, "automaticServiceRemoved");
}
mRecords.remove(i);
}
@@ -249,7 +255,8 @@ public class ConditionProviders extends ManagedServices {
} else if (DEBUG) {
Slog.d(TAG, "Exit zen: manual condition false: " + c);
}
- mZenModeHelper.setZenMode(Settings.Global.ZEN_MODE_OFF);
+ mZenModeHelper.setZenMode(Settings.Global.ZEN_MODE_OFF,
+ "manualConditionExit");
unsubscribeLocked(r);
r.isManual = false;
}
@@ -263,33 +270,46 @@ public class ConditionProviders extends ManagedServices {
} else if (DEBUG) {
Slog.d(TAG, "Exit zen: automatic condition false: " + c);
}
- mZenModeHelper.setZenMode(Settings.Global.ZEN_MODE_OFF);
+ mZenModeHelper.setZenMode(Settings.Global.ZEN_MODE_OFF,
+ "automaticConditionExit");
} else if (c.state == Condition.STATE_TRUE) {
Slog.d(TAG, "Enter zen: automatic condition true: " + c);
- mZenModeHelper.setZenMode(Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS);
+ mZenModeHelper.setZenMode(Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS,
+ "automaticConditionEnter");
}
}
}
}
}
- public void setZenModeCondition(Uri conditionId, String reason) {
- if (DEBUG) Slog.d(TAG, "setZenModeCondition " + conditionId);
+ public void setZenModeCondition(Condition condition, String reason) {
+ if (DEBUG) Slog.d(TAG, "setZenModeCondition " + condition);
synchronized(mMutex) {
ComponentName conditionComponent = null;
- if (ZenModeConfig.isValidCountdownConditionId(conditionId)) {
- // constructed by the client, make sure the record exists...
- final ConditionRecord r = getRecordLocked(conditionId,
- CountdownConditionProvider.COMPONENT);
- if (r.info == null) {
- // ... and is associated with the in-process service
- r.info = checkServiceTokenLocked(mCountdown.asInterface());
+ if (condition != null) {
+ if (ZenModeConfig.isValidCountdownConditionId(condition.id)) {
+ // constructed by the client, make sure the record exists...
+ final ConditionRecord r = getRecordLocked(condition.id,
+ CountdownConditionProvider.COMPONENT);
+ if (r.info == null) {
+ // ... and is associated with the in-process service
+ r.info = checkServiceTokenLocked(mCountdown.asInterface());
+ }
+ }
+ if (ZenModeConfig.isValidDowntimeConditionId(condition.id)) {
+ // constructed by the client, make sure the record exists...
+ final ConditionRecord r = getRecordLocked(condition.id,
+ DowntimeConditionProvider.COMPONENT);
+ if (r.info == null) {
+ // ... and is associated with the in-process service
+ r.info = checkServiceTokenLocked(mDowntime.asInterface());
+ }
}
}
final int N = mRecords.size();
for (int i = 0; i < N; i++) {
final ConditionRecord r = mRecords.get(i);
- final boolean idEqual = r.id.equals(conditionId);
+ final boolean idEqual = condition != null && r.id.equals(condition.id);
if (r.isManual && !idEqual) {
// was previous manual condition, unsubscribe
unsubscribeLocked(r);
@@ -303,10 +323,10 @@ public class ConditionProviders extends ManagedServices {
conditionComponent = r.component;
}
}
- if (!Objects.equals(mExitConditionId, conditionId)) {
- mExitConditionId = conditionId;
+ if (!Objects.equals(mExitCondition, condition)) {
+ mExitCondition = condition;
mExitConditionComponent = conditionComponent;
- ZenLog.traceExitCondition(mExitConditionId, mExitConditionComponent, reason);
+ ZenLog.traceExitCondition(mExitCondition, mExitConditionComponent, reason);
saveZenConfigLocked();
}
}
@@ -318,6 +338,7 @@ public class ConditionProviders extends ManagedServices {
RemoteException re = null;
if (provider != null) {
try {
+ Slog.d(TAG, "Subscribing to " + r.id + " with " + provider);
provider.onSubscribe(r.id);
} catch (RemoteException e) {
Slog.w(TAG, "Error subscribing to " + r, e);
@@ -436,12 +457,13 @@ public class ConditionProviders extends ManagedServices {
return;
}
synchronized (mMutex) {
- final boolean changingExit = !Objects.equals(mExitConditionId, config.exitConditionId);
- mExitConditionId = config.exitConditionId;
+ final boolean changingExit = !Objects.equals(mExitCondition, config.exitCondition);
+ mExitCondition = config.exitCondition;
mExitConditionComponent = config.exitConditionComponent;
if (changingExit) {
- ZenLog.traceExitCondition(mExitConditionId, mExitConditionComponent, "config");
+ ZenLog.traceExitCondition(mExitCondition, mExitConditionComponent, "config");
}
+ mDowntime.setConfig(config);
if (config.conditionComponents == null || config.conditionIds == null
|| config.conditionComponents.length != config.conditionIds.length) {
if (DEBUG) Slog.d(TAG, "loadZenConfig: no conditions");
@@ -488,7 +510,7 @@ public class ConditionProviders extends ManagedServices {
config.conditionIds[i] = r.id;
}
}
- config.exitConditionId = mExitConditionId;
+ config.exitCondition = mExitCondition;
config.exitConditionComponent = mExitConditionComponent;
if (DEBUG) Slog.d(TAG, "Setting zen config to: " + config);
mZenModeHelper.setConfig(config);
@@ -510,6 +532,26 @@ public class ConditionProviders extends ManagedServices {
}
}
+ private class DowntimeCallback implements DowntimeConditionProvider.Callback {
+ @Override
+ public void onDowntimeChanged(boolean inDowntime) {
+ final int mode = mZenModeHelper.getZenMode();
+ final ZenModeConfig config = mZenModeHelper.getConfig();
+ // enter downtime
+ if (inDowntime && mode == Global.ZEN_MODE_OFF && config != null) {
+ final Condition condition = mDowntime.createCondition(config.toDowntimeInfo(),
+ Condition.STATE_TRUE);
+ mZenModeHelper.setZenMode(Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS, "downtimeEnter");
+ setZenModeCondition(condition, "downtime");
+ }
+ // exit downtime
+ if (!inDowntime && mode == Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS
+ && mDowntime.isDowntimeCondition(mExitCondition)) {
+ mZenModeHelper.setZenMode(Global.ZEN_MODE_OFF, "downtimeExit");
+ }
+ }
+ }
+
private static class ConditionRecord {
public final Uri id;
public final ComponentName component;
diff --git a/services/core/java/com/android/server/notification/CountdownConditionProvider.java b/services/core/java/com/android/server/notification/CountdownConditionProvider.java
index aaf7cfc73fa8..37aacaa880bd 100644
--- a/services/core/java/com/android/server/notification/CountdownConditionProvider.java
+++ b/services/core/java/com/android/server/notification/CountdownConditionProvider.java
@@ -29,6 +29,7 @@ import android.service.notification.ConditionProviderService;
import android.service.notification.IConditionProvider;
import android.service.notification.ZenModeConfig;
import android.text.format.DateUtils;
+import android.util.Log;
import android.util.Slog;
import com.android.server.notification.NotificationManagerService.DumpFilter;
@@ -38,8 +39,8 @@ import java.util.Date;
/** Built-in zen condition provider for simple time-based conditions */
public class CountdownConditionProvider extends ConditionProviderService {
- private static final String TAG = "CountdownConditionProvider";
- private static final boolean DEBUG = false;
+ private static final String TAG = "CountdownConditions";
+ private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
public static final ComponentName COMPONENT =
new ComponentName("android", CountdownConditionProvider.class.getName());
diff --git a/services/core/java/com/android/server/notification/DowntimeConditionProvider.java b/services/core/java/com/android/server/notification/DowntimeConditionProvider.java
new file mode 100644
index 000000000000..317ebefc02bb
--- /dev/null
+++ b/services/core/java/com/android/server/notification/DowntimeConditionProvider.java
@@ -0,0 +1,289 @@
+/**
+ * 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.notification;
+
+import android.app.AlarmManager;
+import android.app.PendingIntent;
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.net.Uri;
+import android.service.notification.Condition;
+import android.service.notification.ConditionProviderService;
+import android.service.notification.IConditionProvider;
+import android.service.notification.ZenModeConfig;
+import android.service.notification.ZenModeConfig.DowntimeInfo;
+import android.text.format.DateFormat;
+import android.util.ArraySet;
+import android.util.Log;
+import android.util.Slog;
+
+import com.android.internal.R;
+import com.android.server.notification.NotificationManagerService.DumpFilter;
+
+import java.io.PrintWriter;
+import java.text.SimpleDateFormat;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.Locale;
+import java.util.Objects;
+
+/** Built-in zen condition provider for managing downtime */
+public class DowntimeConditionProvider extends ConditionProviderService {
+ private static final String TAG = "DowntimeConditions";
+ private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+
+ public static final ComponentName COMPONENT =
+ new ComponentName("android", DowntimeConditionProvider.class.getName());
+
+ private static final String ENTER_ACTION = TAG + ".enter";
+ private static final int ENTER_CODE = 100;
+ private static final String EXIT_ACTION = TAG + ".exit";
+ private static final int EXIT_CODE = 101;
+ private static final String EXTRA_TIME = "time";
+
+ private final Calendar mCalendar = Calendar.getInstance();
+ private final Context mContext = this;
+ private final ArraySet<Integer> mDays = new ArraySet<Integer>();
+
+ private boolean mConnected;
+ private boolean mInDowntime;
+ private ZenModeConfig mConfig;
+ private Callback mCallback;
+
+ public DowntimeConditionProvider() {
+ if (DEBUG) Slog.d(TAG, "new DowntimeConditionProvider()");
+ }
+
+ public void dump(PrintWriter pw, DumpFilter filter) {
+ pw.println(" DowntimeConditionProvider:");
+ pw.print(" mConnected="); pw.println(mConnected);
+ pw.print(" mInDowntime="); pw.println(mInDowntime);
+ }
+
+ public void attachBase(Context base) {
+ attachBaseContext(base);
+ }
+
+ public IConditionProvider asInterface() {
+ return (IConditionProvider) onBind(null);
+ }
+
+ public void setCallback(Callback callback) {
+ mCallback = callback;
+ }
+
+ @Override
+ public void onConnected() {
+ if (DEBUG) Slog.d(TAG, "onConnected");
+ mConnected = true;
+ final IntentFilter filter = new IntentFilter();
+ filter.addAction(ENTER_ACTION);
+ filter.addAction(EXIT_ACTION);
+ filter.addAction(Intent.ACTION_TIME_CHANGED);
+ filter.addAction(Intent.ACTION_TIMEZONE_CHANGED);
+ mContext.registerReceiver(mReceiver, filter);
+ init();
+ }
+
+ @Override
+ public void onDestroy() {
+ if (DEBUG) Slog.d(TAG, "onDestroy");
+ mConnected = false;
+ }
+
+ @Override
+ public void onRequestConditions(int relevance) {
+ if (DEBUG) Slog.d(TAG, "onRequestConditions relevance=" + relevance);
+ if ((relevance & Condition.FLAG_RELEVANT_NOW) != 0) {
+ if (mInDowntime && mConfig != null) {
+ notifyCondition(createCondition(mConfig.toDowntimeInfo(), Condition.STATE_TRUE));
+ }
+ }
+ }
+
+ @Override
+ public void onSubscribe(Uri conditionId) {
+ if (DEBUG) Slog.d(TAG, "onSubscribe conditionId=" + conditionId);
+ final DowntimeInfo downtime = ZenModeConfig.tryParseDowntimeConditionId(conditionId);
+ if (downtime != null && mConfig != null) {
+ final int state = mConfig.toDowntimeInfo().equals(downtime) && mInDowntime
+ ? Condition.STATE_TRUE : Condition.STATE_FALSE;
+ if (DEBUG) Slog.d(TAG, "notify condition state: " + Condition.stateToString(state));
+ notifyCondition(createCondition(downtime, state));
+ }
+ }
+
+ @Override
+ public void onUnsubscribe(Uri conditionId) {
+ if (DEBUG) Slog.d(TAG, "onUnsubscribe conditionId=" + conditionId);
+ }
+
+ public void setConfig(ZenModeConfig config) {
+ if (Objects.equals(mConfig, config)) return;
+ if (DEBUG) Slog.d(TAG, "setConfig");
+ mConfig = config;
+ if (mConnected) {
+ init();
+ }
+ }
+
+ public boolean isInDowntime() {
+ return mInDowntime;
+ }
+
+ public Condition createCondition(DowntimeInfo downtime, int state) {
+ if (downtime == null) return null;
+ final Uri id = ZenModeConfig.toDowntimeConditionId(downtime);
+ final String skeleton = DateFormat.is24HourFormat(mContext) ? "Hm" : "hma";
+ final Locale locale = Locale.getDefault();
+ final String pattern = DateFormat.getBestDateTimePattern(locale, skeleton);
+ final long time = getTime(System.currentTimeMillis(), downtime.endHour, downtime.endMinute);
+ final String formatted = new SimpleDateFormat(pattern, locale).format(new Date(time));
+ final String summary = mContext.getString(R.string.downtime_condition_summary, formatted);
+ return new Condition(id, summary, "", "", 0, state, Condition.FLAG_RELEVANT_NOW);
+ }
+
+ public boolean isDowntimeCondition(Condition condition) {
+ return condition != null && ZenModeConfig.isValidDowntimeConditionId(condition.id);
+ }
+
+ private void init() {
+ updateDays();
+ reevaluateDowntime();
+ updateAlarms();
+ }
+
+ private void updateDays() {
+ mDays.clear();
+ if (mConfig != null) {
+ final int[] days = ZenModeConfig.tryParseDays(mConfig.sleepMode);
+ for (int i = 0; days != null && i < days.length; i++) {
+ mDays.add(days[i]);
+ }
+ }
+ }
+
+ private boolean isInDowntime(long time) {
+ if (mConfig == null || mDays.size() == 0) return false;
+ final long start = getTime(time, mConfig.sleepStartHour, mConfig.sleepStartMinute);
+ long end = getTime(time, mConfig.sleepEndHour, mConfig.sleepEndMinute);
+ if (start == end) return false;
+ if (end < start) {
+ end = addDays(end, 1);
+ }
+ return isInDowntime(-1, time, start, end) || isInDowntime(0, time, start, end);
+ }
+
+ private boolean isInDowntime(int daysOffset, long time, long start, long end) {
+ final int day = ((getDayOfWeek(time) + daysOffset - 1) % Calendar.SATURDAY) + 1;
+ start = addDays(start, daysOffset);
+ end = addDays(end, daysOffset);
+ return mDays.contains(day) && time >= start && time < end;
+ }
+
+ private void reevaluateDowntime() {
+ final boolean inDowntime = isInDowntime(System.currentTimeMillis());
+ if (DEBUG) Slog.d(TAG, "inDowntime=" + inDowntime);
+ if (inDowntime == mInDowntime) return;
+ Slog.i(TAG, (inDowntime ? "Entering" : "Exiting" ) + " downtime");
+ mInDowntime = inDowntime;
+ ZenLog.traceDowntime(mInDowntime, getDayOfWeek(System.currentTimeMillis()), mDays);
+ fireDowntimeChanged();
+ }
+
+ private void fireDowntimeChanged() {
+ if (mCallback != null) {
+ mCallback.onDowntimeChanged(mInDowntime);
+ }
+ }
+
+ private void updateAlarms() {
+ if (mConfig == null) return;
+ updateAlarm(ENTER_ACTION, ENTER_CODE, mConfig.sleepStartHour, mConfig.sleepStartMinute);
+ updateAlarm(EXIT_ACTION, EXIT_CODE, mConfig.sleepEndHour, mConfig.sleepEndMinute);
+ }
+
+ private int getDayOfWeek(long time) {
+ mCalendar.setTimeInMillis(time);
+ return mCalendar.get(Calendar.DAY_OF_WEEK);
+ }
+
+ private long getTime(long millis, int hour, int min) {
+ mCalendar.setTimeInMillis(millis);
+ mCalendar.set(Calendar.HOUR_OF_DAY, hour);
+ mCalendar.set(Calendar.MINUTE, min);
+ mCalendar.set(Calendar.SECOND, 0);
+ mCalendar.set(Calendar.MILLISECOND, 0);
+ return mCalendar.getTimeInMillis();
+ }
+
+ private long addDays(long time, int days) {
+ mCalendar.setTimeInMillis(time);
+ mCalendar.add(Calendar.DATE, days);
+ return mCalendar.getTimeInMillis();
+ }
+
+ private void updateAlarm(String action, int requestCode, int hr, int min) {
+ final AlarmManager alarms = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
+ final long now = System.currentTimeMillis();
+ mCalendar.setTimeInMillis(now);
+ mCalendar.set(Calendar.HOUR_OF_DAY, hr);
+ mCalendar.set(Calendar.MINUTE, min);
+ mCalendar.set(Calendar.SECOND, 0);
+ mCalendar.set(Calendar.MILLISECOND, 0);
+ long time = mCalendar.getTimeInMillis();
+ if (time <= now) {
+ time = addDays(time, 1);
+ }
+ final PendingIntent pendingIntent = PendingIntent.getBroadcast(mContext, requestCode,
+ new Intent(action).putExtra(EXTRA_TIME, time), PendingIntent.FLAG_UPDATE_CURRENT);
+ alarms.cancel(pendingIntent);
+ if (mConfig.sleepMode != null) {
+ if (DEBUG) Slog.d(TAG, String.format("Scheduling %s for %s, %s in the future, now=%s",
+ action, ts(time), time - now, ts(now)));
+ alarms.setExact(AlarmManager.RTC_WAKEUP, time, pendingIntent);
+ }
+ }
+
+ private static String ts(long time) {
+ return new Date(time) + " (" + time + ")";
+ }
+
+ private BroadcastReceiver mReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ final String action = intent.getAction();
+ final long now = System.currentTimeMillis();
+ if (ENTER_ACTION.equals(action) || EXIT_ACTION.equals(action)) {
+ final long schTime = intent.getLongExtra(EXTRA_TIME, 0);
+ if (DEBUG) Slog.d(TAG, String.format("%s scheduled for %s, fired at %s, delta=%s",
+ action, ts(schTime), ts(now), now - schTime));
+ } else {
+ if (DEBUG) Slog.d(TAG, action + " fired at " + now);
+ }
+ reevaluateDowntime();
+ updateAlarms();
+ }
+ };
+
+ public interface Callback {
+ void onDowntimeChanged(boolean inDowntime);
+ }
+}
diff --git a/services/core/java/com/android/server/notification/ManagedServices.java b/services/core/java/com/android/server/notification/ManagedServices.java
index 36be21fd28d5..f647037e14d7 100644
--- a/services/core/java/com/android/server/notification/ManagedServices.java
+++ b/services/core/java/com/android/server/notification/ManagedServices.java
@@ -41,6 +41,7 @@ import android.os.UserManager;
import android.provider.Settings;
import android.text.TextUtils;
import android.util.ArraySet;
+import android.util.Log;
import android.util.Slog;
import android.util.SparseArray;
@@ -64,7 +65,7 @@ import java.util.Set;
*/
abstract public class ManagedServices {
protected final String TAG = getClass().getSimpleName();
- protected static final boolean DEBUG = true;
+ protected final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
private static final String ENABLED_SERVICES_SEPARATOR = ":";
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index d6afe68fb213..f2ac963a26d5 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -1351,11 +1351,11 @@ public class NotificationManagerService extends SystemService {
}
@Override
- public void setZenModeCondition(Uri conditionId) {
+ public void setZenModeCondition(Condition condition) {
enforceSystemOrSystemUI("INotificationManager.setZenModeCondition");
final long identity = Binder.clearCallingIdentity();
try {
- mConditionProviders.setZenModeCondition(conditionId, "binderCall");
+ mConditionProviders.setZenModeCondition(condition, "binderCall");
} finally {
Binder.restoreCallingIdentity(identity);
}
diff --git a/services/core/java/com/android/server/notification/ZenLog.java b/services/core/java/com/android/server/notification/ZenLog.java
index b22ed2dfe1e5..525f5f858631 100644
--- a/services/core/java/com/android/server/notification/ZenLog.java
+++ b/services/core/java/com/android/server/notification/ZenLog.java
@@ -22,8 +22,10 @@ import android.net.Uri;
import android.os.Build;
import android.os.RemoteException;
import android.provider.Settings.Global;
+import android.service.notification.Condition;
import android.service.notification.IConditionProvider;
import android.service.notification.ZenModeConfig;
+import android.util.ArraySet;
import android.util.Slog;
import java.io.PrintWriter;
@@ -52,13 +54,14 @@ public class ZenLog {
private static final int TYPE_ALLOW_DISABLE = 2;
private static final int TYPE_SET_RINGER_MODE = 3;
private static final int TYPE_DOWNTIME = 4;
- private static final int TYPE_ZEN_MODE = 5;
- private static final int TYPE_EXIT_CONDITION = 6;
- private static final int TYPE_SUBSCRIBE = 7;
- private static final int TYPE_UNSUBSCRIBE = 8;
- private static final int TYPE_CONFIG = 9;
- private static final int TYPE_FOLLOW_RINGER_MODE = 10;
- private static final int TYPE_NOT_INTERCEPTED = 11;
+ private static final int TYPE_SET_ZEN_MODE = 5;
+ private static final int TYPE_UPDATE_ZEN_MODE = 6;
+ private static final int TYPE_EXIT_CONDITION = 7;
+ private static final int TYPE_SUBSCRIBE = 8;
+ private static final int TYPE_UNSUBSCRIBE = 9;
+ private static final int TYPE_CONFIG = 10;
+ private static final int TYPE_FOLLOW_RINGER_MODE = 11;
+ private static final int TYPE_NOT_INTERCEPTED = 12;
private static int sNext;
private static int sSize;
@@ -82,17 +85,20 @@ public class ZenLog {
append(TYPE_SET_RINGER_MODE, ringerModeToString(ringerMode));
}
- public static void traceDowntime(boolean enter, int day, int[] days) {
- append(TYPE_DOWNTIME, enter + ",day=" + day + ",days=" + (days != null ? Arrays.asList(days)
- : null));
+ public static void traceDowntime(boolean inDowntime, int day, ArraySet<Integer> days) {
+ append(TYPE_DOWNTIME, inDowntime + ",day=" + day + ",days=" + days);
+ }
+
+ public static void traceSetZenMode(int mode, String reason) {
+ append(TYPE_SET_ZEN_MODE, zenModeToString(mode) + "," + reason);
}
public static void traceUpdateZenMode(int fromMode, int toMode) {
- append(TYPE_ZEN_MODE, zenModeToString(fromMode) + " -> " + zenModeToString(toMode));
+ append(TYPE_UPDATE_ZEN_MODE, zenModeToString(fromMode) + " -> " + zenModeToString(toMode));
}
- public static void traceExitCondition(Uri id, ComponentName component, String reason) {
- append(TYPE_EXIT_CONDITION, id + "," + componentToString(component) + "," + reason);
+ public static void traceExitCondition(Condition c, ComponentName component, String reason) {
+ append(TYPE_EXIT_CONDITION, c + "," + componentToString(component) + "," + reason);
}
public static void traceSubscribe(Uri uri, IConditionProvider provider, RemoteException e) {
@@ -122,7 +128,8 @@ public class ZenLog {
case TYPE_ALLOW_DISABLE: return "allow_disable";
case TYPE_SET_RINGER_MODE: return "set_ringer_mode";
case TYPE_DOWNTIME: return "downtime";
- case TYPE_ZEN_MODE: return "zen_mode";
+ case TYPE_SET_ZEN_MODE: return "set_zen_mode";
+ case TYPE_UPDATE_ZEN_MODE: return "update_zen_mode";
case TYPE_EXIT_CONDITION: return "exit_condition";
case TYPE_SUBSCRIBE: return "subscribe";
case TYPE_UNSUBSCRIBE: return "unsubscribe";
diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java
index 9282283b87d8..758f3344d750 100644
--- a/services/core/java/com/android/server/notification/ZenModeHelper.java
+++ b/services/core/java/com/android/server/notification/ZenModeHelper.java
@@ -20,10 +20,8 @@ import static android.media.AudioAttributes.USAGE_ALARM;
import static android.media.AudioAttributes.USAGE_NOTIFICATION_RINGTONE;
import static android.media.AudioAttributes.USAGE_UNKNOWN;
-import android.app.AlarmManager;
import android.app.AppOpsManager;
import android.app.Notification;
-import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.ContentResolver;
@@ -44,6 +42,7 @@ import android.provider.Settings.Secure;
import android.service.notification.NotificationListenerService;
import android.service.notification.ZenModeConfig;
import android.telecomm.TelecommManager;
+import android.util.Log;
import android.util.Slog;
import com.android.internal.R;
@@ -57,8 +56,6 @@ import org.xmlpull.v1.XmlSerializer;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
-import java.util.Calendar;
-import java.util.Date;
import java.util.Objects;
/**
@@ -66,12 +63,7 @@ import java.util.Objects;
*/
public class ZenModeHelper {
private static final String TAG = "ZenModeHelper";
-
- private static final String ACTION_ENTER_ZEN = "enter_zen";
- private static final int REQUEST_CODE_ENTER = 100;
- private static final String ACTION_EXIT_ZEN = "exit_zen";
- private static final int REQUEST_CODE_EXIT = 101;
- private static final String EXTRA_TIME = "time";
+ private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
private final Context mContext;
private final Handler mHandler;
@@ -96,10 +88,8 @@ public class ZenModeHelper {
mSettingsObserver.observe();
final IntentFilter filter = new IntentFilter();
- filter.addAction(ACTION_ENTER_ZEN);
- filter.addAction(ACTION_EXIT_ZEN);
filter.addAction(AudioManager.RINGER_MODE_CHANGED_ACTION);
- mContext.registerReceiver(new ZenBroadcastReceiver(), filter);
+ mContext.registerReceiver(mReceiver, filter);
}
public static ZenModeConfig readDefaultConfig(Resources resources) {
@@ -156,7 +146,7 @@ public class ZenModeHelper {
public void requestFromListener(int hints) {
final int newZen = zenFromListenerHint(hints, -1);
if (newZen != -1) {
- setZenMode(newZen);
+ setZenMode(newZen, "listener");
}
}
@@ -179,24 +169,19 @@ public class ZenModeHelper {
return false;
}
}
- // audience has veto power over all following rules
- if (!audienceMatches(record)) {
- ZenLog.traceIntercepted(record, "!audienceMatches");
- return true;
- }
if (isCall(record)) {
if (!mConfig.allowCalls) {
ZenLog.traceIntercepted(record, "!allowCalls");
return true;
}
- return false;
+ return shouldInterceptAudience(record);
}
if (isMessage(record)) {
if (!mConfig.allowMessages) {
ZenLog.traceIntercepted(record, "!allowMessages");
return true;
}
- return false;
+ return shouldInterceptAudience(record);
}
ZenLog.traceIntercepted(record, "!allowed");
return true;
@@ -204,11 +189,20 @@ public class ZenModeHelper {
return false;
}
+ private boolean shouldInterceptAudience(NotificationRecord record) {
+ if (!audienceMatches(record)) {
+ ZenLog.traceIntercepted(record, "!audienceMatches");
+ return true;
+ }
+ return false;
+ }
+
public int getZenMode() {
return mZenMode;
}
- public void setZenMode(int zenModeValue) {
+ public void setZenMode(int zenModeValue, String reason) {
+ ZenLog.traceSetZenMode(zenModeValue, reason);
Global.putInt(mContext.getContentResolver(), Global.ZEN_MODE, zenModeValue);
}
@@ -216,9 +210,6 @@ public class ZenModeHelper {
final int mode = Global.getInt(mContext.getContentResolver(),
Global.ZEN_MODE, Global.ZEN_MODE_OFF);
if (mode != mZenMode) {
- Slog.d(TAG, String.format("updateZenMode: %s -> %s",
- Global.zenModeToString(mZenMode),
- Global.zenModeToString(mode)));
ZenLog.traceUpdateZenMode(mZenMode, mode);
}
mZenMode = mode;
@@ -255,12 +246,12 @@ public class ZenModeHelper {
if (mZenMode == Global.ZEN_MODE_NO_INTERRUPTIONS) {
if (ringerMode != AudioManager.RINGER_MODE_SILENT) {
mPreviousRingerMode = ringerMode;
- Slog.d(TAG, "Silencing ringer");
+ if (DEBUG) Slog.d(TAG, "Silencing ringer");
forcedRingerMode = AudioManager.RINGER_MODE_SILENT;
}
} else {
if (ringerMode == AudioManager.RINGER_MODE_SILENT) {
- Slog.d(TAG, "Unsilencing ringer");
+ if (DEBUG) Slog.d(TAG, "Unsilencing ringer");
forcedRingerMode = mPreviousRingerMode != -1 ? mPreviousRingerMode
: AudioManager.RINGER_MODE_NORMAL;
mPreviousRingerMode = -1;
@@ -318,7 +309,6 @@ public class ZenModeHelper {
dispatchOnConfigChanged();
final String val = Integer.toString(mConfig.hashCode());
Global.putString(mContext.getContentResolver(), Global.ZEN_MODE_CONFIG_ETAG, val);
- updateAlarms();
updateZenMode();
return true;
}
@@ -339,7 +329,7 @@ public class ZenModeHelper {
}
if (newZen != -1) {
ZenLog.traceFollowRingerMode(ringerMode, mZenMode, newZen);
- setZenMode(newZen);
+ setZenMode(newZen, "ringerMode");
}
}
}
@@ -377,7 +367,7 @@ public class ZenModeHelper {
final TelecommManager telecomm =
(TelecommManager) mContext.getSystemService(Context.TELECOMM_SERVICE);
mDefaultPhoneApp = telecomm != null ? telecomm.getDefaultPhoneApp() : null;
- Slog.d(TAG, "Default phone app: " + mDefaultPhoneApp);
+ if (DEBUG) Slog.d(TAG, "Default phone app: " + mDefaultPhoneApp);
}
return pkg != null && mDefaultPhoneApp != null
&& pkg.equals(mDefaultPhoneApp.getPackageName());
@@ -409,40 +399,6 @@ public class ZenModeHelper {
}
}
- private void updateAlarms() {
- updateAlarm(ACTION_ENTER_ZEN, REQUEST_CODE_ENTER,
- mConfig.sleepStartHour, mConfig.sleepStartMinute);
- updateAlarm(ACTION_EXIT_ZEN, REQUEST_CODE_EXIT,
- mConfig.sleepEndHour, mConfig.sleepEndMinute);
- }
-
- private void updateAlarm(String action, int requestCode, int hr, int min) {
- final AlarmManager alarms = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
- final long now = System.currentTimeMillis();
- final Calendar c = Calendar.getInstance();
- c.setTimeInMillis(now);
- c.set(Calendar.HOUR_OF_DAY, hr);
- c.set(Calendar.MINUTE, min);
- c.set(Calendar.SECOND, 0);
- c.set(Calendar.MILLISECOND, 0);
- if (c.getTimeInMillis() <= now) {
- c.add(Calendar.DATE, 1);
- }
- final long time = c.getTimeInMillis();
- final PendingIntent pendingIntent = PendingIntent.getBroadcast(mContext, requestCode,
- new Intent(action).putExtra(EXTRA_TIME, time), PendingIntent.FLAG_UPDATE_CURRENT);
- alarms.cancel(pendingIntent);
- if (mConfig.sleepMode != null) {
- Slog.d(TAG, String.format("Scheduling %s for %s, %s in the future, now=%s",
- action, ts(time), time - now, ts(now)));
- alarms.setExact(AlarmManager.RTC_WAKEUP, time, pendingIntent);
- }
- }
-
- private static String ts(long time) {
- return new Date(time) + " (" + time + ")";
- }
-
private final Runnable mRingerModeChanged = new Runnable() {
@Override
public void run() {
@@ -475,47 +431,12 @@ public class ZenModeHelper {
}
}
- private class ZenBroadcastReceiver extends BroadcastReceiver {
- private final Calendar mCalendar = Calendar.getInstance();
-
+ private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
- if (ACTION_ENTER_ZEN.equals(intent.getAction())) {
- setZenMode(intent, Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS);
- } else if (ACTION_EXIT_ZEN.equals(intent.getAction())) {
- setZenMode(intent, Global.ZEN_MODE_OFF);
- } else if (AudioManager.RINGER_MODE_CHANGED_ACTION.equals(intent.getAction())) {
- mHandler.post(mRingerModeChanged);
- }
- }
-
- private void setZenMode(Intent intent, int zenModeValue) {
- final long schTime = intent.getLongExtra(EXTRA_TIME, 0);
- final long now = System.currentTimeMillis();
- Slog.d(TAG, String.format("%s scheduled for %s, fired at %s, delta=%s",
- intent.getAction(), ts(schTime), ts(now), now - schTime));
-
- final int[] days = ZenModeConfig.tryParseDays(mConfig.sleepMode);
- boolean enter = false;
- final int day = getDayOfWeek(schTime);
- if (days != null) {
- for (int i = 0; i < days.length; i++) {
- if (days[i] == day) {
- enter = true;
- ZenModeHelper.this.setZenMode(zenModeValue);
- break;
- }
- }
- }
- ZenLog.traceDowntime(enter, day, days);
- updateAlarms();
+ mHandler.post(mRingerModeChanged);
}
-
- private int getDayOfWeek(long time) {
- mCalendar.setTimeInMillis(time);
- return mCalendar.get(Calendar.DAY_OF_WEEK);
- }
- }
+ };
public static class Callback {
void onConfigChanged() {}
diff --git a/services/core/java/com/android/server/pm/Installer.java b/services/core/java/com/android/server/pm/Installer.java
index b261ef5dd124..d1e03ec7510c 100644
--- a/services/core/java/com/android/server/pm/Installer.java
+++ b/services/core/java/com/android/server/pm/Installer.java
@@ -16,33 +16,23 @@
package com.android.server.pm;
-import com.android.server.SystemService;
-
import android.content.Context;
import android.content.pm.PackageStats;
-import android.net.LocalSocket;
-import android.net.LocalSocketAddress;
+import android.os.Build;
import android.util.Slog;
+import dalvik.system.VMRuntime;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.util.List;
+import com.android.internal.os.InstallerConnection;
+import com.android.server.SystemService;
public final class Installer extends SystemService {
private static final String TAG = "Installer";
- private static final boolean LOCAL_DEBUG = false;
-
- InputStream mIn;
- OutputStream mOut;
- LocalSocket mSocket;
-
- byte buf[] = new byte[1024];
- int buflen = 0;
+ private final InstallerConnection mInstaller;
public Installer(Context context) {
super(context);
+ mInstaller = new InstallerConnection();
}
@Override
@@ -51,154 +41,6 @@ public final class Installer extends SystemService {
ping();
}
- private boolean connect() {
- if (mSocket != null) {
- return true;
- }
- Slog.i(TAG, "connecting...");
- try {
- mSocket = new LocalSocket();
-
- LocalSocketAddress address = new LocalSocketAddress("installd",
- LocalSocketAddress.Namespace.RESERVED);
-
- mSocket.connect(address);
-
- mIn = mSocket.getInputStream();
- mOut = mSocket.getOutputStream();
- } catch (IOException ex) {
- disconnect();
- return false;
- }
- return true;
- }
-
- private void disconnect() {
- Slog.i(TAG, "disconnecting...");
- try {
- if (mSocket != null)
- mSocket.close();
- } catch (IOException ex) {
- }
- try {
- if (mIn != null)
- mIn.close();
- } catch (IOException ex) {
- }
- try {
- if (mOut != null)
- mOut.close();
- } catch (IOException ex) {
- }
- mSocket = null;
- mIn = null;
- mOut = null;
- }
-
- private boolean readBytes(byte buffer[], int len) {
- int off = 0, count;
- if (len < 0)
- return false;
- while (off != len) {
- try {
- count = mIn.read(buffer, off, len - off);
- if (count <= 0) {
- Slog.e(TAG, "read error " + count);
- break;
- }
- off += count;
- } catch (IOException ex) {
- Slog.e(TAG, "read exception");
- break;
- }
- }
- if (LOCAL_DEBUG) {
- Slog.i(TAG, "read " + len + " bytes");
- }
- if (off == len)
- return true;
- disconnect();
- return false;
- }
-
- private boolean readReply() {
- int len;
- buflen = 0;
- if (!readBytes(buf, 2))
- return false;
- len = (((int) buf[0]) & 0xff) | ((((int) buf[1]) & 0xff) << 8);
- if ((len < 1) || (len > 1024)) {
- Slog.e(TAG, "invalid reply length (" + len + ")");
- disconnect();
- return false;
- }
- if (!readBytes(buf, len))
- return false;
- buflen = len;
- return true;
- }
-
- private boolean writeCommand(String _cmd) {
- byte[] cmd = _cmd.getBytes();
- int len = cmd.length;
- if ((len < 1) || (len > 1024))
- return false;
- buf[0] = (byte) (len & 0xff);
- buf[1] = (byte) ((len >> 8) & 0xff);
- try {
- mOut.write(buf, 0, 2);
- mOut.write(cmd, 0, len);
- } catch (IOException ex) {
- Slog.e(TAG, "write error");
- disconnect();
- return false;
- }
- return true;
- }
-
- private synchronized String transaction(String cmd) {
- if (!connect()) {
- Slog.e(TAG, "connection failed");
- return "-1";
- }
-
- if (!writeCommand(cmd)) {
- /*
- * If installd died and restarted in the background (unlikely but
- * possible) we'll fail on the next write (this one). Try to
- * reconnect and write the command one more time before giving up.
- */
- Slog.e(TAG, "write command failed? reconnect!");
- if (!connect() || !writeCommand(cmd)) {
- return "-1";
- }
- }
- if (LOCAL_DEBUG) {
- Slog.i(TAG, "send: '" + cmd + "'");
- }
- if (readReply()) {
- String s = new String(buf, 0, buflen);
- if (LOCAL_DEBUG) {
- Slog.i(TAG, "recv: '" + s + "'");
- }
- return s;
- } else {
- if (LOCAL_DEBUG) {
- Slog.i(TAG, "fail");
- }
- return "-1";
- }
- }
-
- private int execute(String cmd) {
- String res = transaction(cmd);
- try {
- return Integer.parseInt(res);
- } catch (NumberFormatException ex) {
- return -1;
- }
- }
-
public int install(String name, int uid, int gid, String seinfo) {
StringBuilder builder = new StringBuilder("install");
builder.append(' ');
@@ -209,11 +51,16 @@ public final class Installer extends SystemService {
builder.append(gid);
builder.append(' ');
builder.append(seinfo != null ? seinfo : "!");
- return execute(builder.toString());
+ return mInstaller.execute(builder.toString());
}
public int patchoat(String apkPath, int uid, boolean isPublic, String pkgName,
String instructionSet) {
+ if (!isValidInstructionSet(instructionSet)) {
+ Slog.e(TAG, "Invalid instruction set: " + instructionSet);
+ return -1;
+ }
+
StringBuilder builder = new StringBuilder("patchoat");
builder.append(' ');
builder.append(apkPath);
@@ -224,37 +71,34 @@ public final class Installer extends SystemService {
builder.append(pkgName);
builder.append(' ');
builder.append(instructionSet);
- return execute(builder.toString());
+ return mInstaller.execute(builder.toString());
}
public int patchoat(String apkPath, int uid, boolean isPublic, String instructionSet) {
- StringBuilder builder = new StringBuilder("patchoat");
- builder.append(' ');
- builder.append(apkPath);
- builder.append(' ');
- builder.append(uid);
- builder.append(isPublic ? " 1" : " 0");
- builder.append(" *"); // No pkgName arg present
- builder.append(' ');
- builder.append(instructionSet);
- return execute(builder.toString());
+ if (!isValidInstructionSet(instructionSet)) {
+ Slog.e(TAG, "Invalid instruction set: " + instructionSet);
+ return -1;
+ }
+
+ return mInstaller.patchoat(apkPath, uid, isPublic, instructionSet);
}
public int dexopt(String apkPath, int uid, boolean isPublic, String instructionSet) {
- StringBuilder builder = new StringBuilder("dexopt");
- builder.append(' ');
- builder.append(apkPath);
- builder.append(' ');
- builder.append(uid);
- builder.append(isPublic ? " 1" : " 0");
- builder.append(" *"); // No pkgName arg present
- builder.append(' ');
- builder.append(instructionSet);
- return execute(builder.toString());
+ if (!isValidInstructionSet(instructionSet)) {
+ Slog.e(TAG, "Invalid instruction set: " + instructionSet);
+ return -1;
+ }
+
+ return mInstaller.dexopt(apkPath, uid, isPublic, instructionSet);
}
public int dexopt(String apkPath, int uid, boolean isPublic, String pkgName,
String instructionSet) {
+ if (!isValidInstructionSet(instructionSet)) {
+ Slog.e(TAG, "Invalid instruction set: " + instructionSet);
+ return -1;
+ }
+
StringBuilder builder = new StringBuilder("dexopt");
builder.append(' ');
builder.append(apkPath);
@@ -265,7 +109,7 @@ public final class Installer extends SystemService {
builder.append(pkgName);
builder.append(' ');
builder.append(instructionSet);
- return execute(builder.toString());
+ return mInstaller.execute(builder.toString());
}
public int idmap(String targetApkPath, String overlayApkPath, int uid) {
@@ -276,10 +120,15 @@ public final class Installer extends SystemService {
builder.append(overlayApkPath);
builder.append(' ');
builder.append(uid);
- return execute(builder.toString());
+ return mInstaller.execute(builder.toString());
}
public int movedex(String srcPath, String dstPath, String instructionSet) {
+ if (!isValidInstructionSet(instructionSet)) {
+ Slog.e(TAG, "Invalid instruction set: " + instructionSet);
+ return -1;
+ }
+
StringBuilder builder = new StringBuilder("movedex");
builder.append(' ');
builder.append(srcPath);
@@ -287,16 +136,21 @@ public final class Installer extends SystemService {
builder.append(dstPath);
builder.append(' ');
builder.append(instructionSet);
- return execute(builder.toString());
+ return mInstaller.execute(builder.toString());
}
public int rmdex(String codePath, String instructionSet) {
+ if (!isValidInstructionSet(instructionSet)) {
+ Slog.e(TAG, "Invalid instruction set: " + instructionSet);
+ return -1;
+ }
+
StringBuilder builder = new StringBuilder("rmdex");
builder.append(' ');
builder.append(codePath);
builder.append(' ');
builder.append(instructionSet);
- return execute(builder.toString());
+ return mInstaller.execute(builder.toString());
}
public int remove(String name, int userId) {
@@ -305,7 +159,7 @@ public final class Installer extends SystemService {
builder.append(name);
builder.append(' ');
builder.append(userId);
- return execute(builder.toString());
+ return mInstaller.execute(builder.toString());
}
public int rename(String oldname, String newname) {
@@ -314,7 +168,7 @@ public final class Installer extends SystemService {
builder.append(oldname);
builder.append(' ');
builder.append(newname);
- return execute(builder.toString());
+ return mInstaller.execute(builder.toString());
}
public int fixUid(String name, int uid, int gid) {
@@ -325,7 +179,7 @@ public final class Installer extends SystemService {
builder.append(uid);
builder.append(' ');
builder.append(gid);
- return execute(builder.toString());
+ return mInstaller.execute(builder.toString());
}
public int deleteCacheFiles(String name, int userId) {
@@ -334,7 +188,7 @@ public final class Installer extends SystemService {
builder.append(name);
builder.append(' ');
builder.append(userId);
- return execute(builder.toString());
+ return mInstaller.execute(builder.toString());
}
public int deleteCodeCacheFiles(String name, int userId) {
@@ -343,7 +197,7 @@ public final class Installer extends SystemService {
builder.append(name);
builder.append(' ');
builder.append(userId);
- return execute(builder.toString());
+ return mInstaller.execute(builder.toString());
}
public int createUserData(String name, int uid, int userId, String seinfo) {
@@ -356,21 +210,21 @@ public final class Installer extends SystemService {
builder.append(userId);
builder.append(' ');
builder.append(seinfo != null ? seinfo : "!");
- return execute(builder.toString());
+ return mInstaller.execute(builder.toString());
}
public int createUserConfig(int userId) {
StringBuilder builder = new StringBuilder("mkuserconfig");
builder.append(' ');
builder.append(userId);
- return execute(builder.toString());
+ return mInstaller.execute(builder.toString());
}
public int removeUserDataDirs(int userId) {
StringBuilder builder = new StringBuilder("rmuser");
builder.append(' ');
builder.append(userId);
- return execute(builder.toString());
+ return mInstaller.execute(builder.toString());
}
public int clearUserData(String name, int userId) {
@@ -379,11 +233,11 @@ public final class Installer extends SystemService {
builder.append(name);
builder.append(' ');
builder.append(userId);
- return execute(builder.toString());
+ return mInstaller.execute(builder.toString());
}
public boolean ping() {
- if (execute("ping") < 0) {
+ if (mInstaller.execute("ping") < 0) {
return false;
} else {
return true;
@@ -391,18 +245,25 @@ public final class Installer extends SystemService {
}
public int pruneDexCache(String cacheSubDir) {
- return execute("prunedexcache " + cacheSubDir);
+ return mInstaller.execute("prunedexcache " + cacheSubDir);
}
public int freeCache(long freeStorageSize) {
StringBuilder builder = new StringBuilder("freecache");
builder.append(' ');
builder.append(String.valueOf(freeStorageSize));
- return execute(builder.toString());
+ return mInstaller.execute(builder.toString());
}
public int getSizeInfo(String pkgName, int persona, String apkPath, String libDirPath,
String fwdLockApkPath, String asecPath, String[] instructionSets, PackageStats pStats) {
+ for (String instructionSet : instructionSets) {
+ if (!isValidInstructionSet(instructionSet)) {
+ Slog.e(TAG, "Invalid instruction set: " + instructionSet);
+ return -1;
+ }
+ }
+
StringBuilder builder = new StringBuilder("getsize");
builder.append(' ');
builder.append(pkgName);
@@ -423,7 +284,7 @@ public final class Installer extends SystemService {
// just the primary.
builder.append(instructionSets[0]);
- String s = transaction(builder.toString());
+ String s = mInstaller.transact(builder.toString());
String res[] = s.split(" ");
if ((res == null) || (res.length != 5)) {
@@ -441,7 +302,7 @@ public final class Installer extends SystemService {
}
public int moveFiles() {
- return execute("movefiles");
+ return mInstaller.execute("movefiles");
}
/**
@@ -467,7 +328,7 @@ public final class Installer extends SystemService {
builder.append(' ');
builder.append(userId);
- return execute(builder.toString());
+ return mInstaller.execute(builder.toString());
}
public boolean restoreconData(String pkgName, String seinfo, int uid) {
@@ -478,6 +339,23 @@ public final class Installer extends SystemService {
builder.append(seinfo != null ? seinfo : "!");
builder.append(' ');
builder.append(uid);
- return (execute(builder.toString()) == 0);
+ return (mInstaller.execute(builder.toString()) == 0);
+ }
+
+ /**
+ * Returns true iff. {@code instructionSet} is a valid instruction set.
+ */
+ private static boolean isValidInstructionSet(String instructionSet) {
+ if (instructionSet == null) {
+ return false;
+ }
+
+ for (String abi : Build.SUPPORTED_ABIS) {
+ if (instructionSet.equals(VMRuntime.getInstructionSet(abi))) {
+ return true;
+ }
+ }
+
+ return false;
}
}
diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java
index c7e3fb74d2ec..dca8ad421ba2 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerService.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerService.java
@@ -36,19 +36,23 @@ import static org.xmlpull.v1.XmlPullParser.START_TAG;
import android.app.ActivityManager;
import android.app.AppOpsManager;
+import android.app.PackageDeleteObserver;
+import android.app.PackageInstallObserver;
import android.content.Context;
import android.content.Intent;
-import android.content.pm.IPackageDeleteObserver2;
+import android.content.IntentSender;
+import android.content.IntentSender.SendIntentException;
import android.content.pm.IPackageInstaller;
import android.content.pm.IPackageInstallerCallback;
import android.content.pm.IPackageInstallerSession;
-import android.content.pm.InstallSessionInfo;
-import android.content.pm.InstallSessionParams;
import android.content.pm.PackageInstaller;
+import android.content.pm.PackageInstaller.SessionInfo;
+import android.content.pm.PackageInstaller.SessionParams;
import android.content.pm.PackageManager;
import android.graphics.Bitmap;
import android.net.Uri;
import android.os.Binder;
+import android.os.Bundle;
import android.os.Environment;
import android.os.FileUtils;
import android.os.Handler;
@@ -63,6 +67,7 @@ import android.os.UserHandle;
import android.os.UserManager;
import android.system.ErrnoException;
import android.system.Os;
+import android.text.TextUtils;
import android.text.format.DateUtils;
import android.util.ArraySet;
import android.util.AtomicFile;
@@ -279,8 +284,8 @@ public class PackageInstallerService extends IPackageInstaller.Stub {
final File sessionStageDir = new File(readStringAttribute(in, ATTR_SESSION_STAGE_DIR));
final boolean sealed = readBooleanAttribute(in, ATTR_SEALED);
- final InstallSessionParams params = new InstallSessionParams(
- InstallSessionParams.MODE_INVALID);
+ final SessionParams params = new SessionParams(
+ SessionParams.MODE_INVALID);
params.mode = readIntAttribute(in, ATTR_MODE);
params.installFlags = readIntAttribute(in, ATTR_INSTALL_FLAGS);
params.installLocation = readIntAttribute(in, ATTR_INSTALL_LOCATION);
@@ -292,9 +297,9 @@ public class PackageInstallerService extends IPackageInstaller.Stub {
params.referrerUri = readUriAttribute(in, ATTR_REFERRER_URI);
params.abiOverride = readStringAttribute(in, ATTR_ABI_OVERRIDE);
- return new PackageInstallerSession(mInternalCallback, mPm, mInstallThread.getLooper(),
- sessionId, userId, installerPackageName, params, createdMillis, sessionStageDir,
- sealed);
+ return new PackageInstallerSession(mInternalCallback, mContext, mPm,
+ mInstallThread.getLooper(), sessionId, userId, installerPackageName, params,
+ createdMillis, sessionStageDir, sealed);
}
private void writeSessionsLocked() {
@@ -326,7 +331,7 @@ public class PackageInstallerService extends IPackageInstaller.Stub {
private void writeSessionLocked(XmlSerializer out, PackageInstallerSession session)
throws IOException {
- final InstallSessionParams params = session.params;
+ final SessionParams params = session.params;
final Snapshot snapshot = session.snapshot();
out.startTag(null, TAG_SESSION);
@@ -366,7 +371,7 @@ public class PackageInstallerService extends IPackageInstaller.Stub {
}
@Override
- public int createSession(InstallSessionParams params, String installerPackageName, int userId) {
+ public int createSession(SessionParams params, String installerPackageName, int userId) {
final int callingUid = Binder.getCallingUid();
mPm.enforceCrossUserPermission(callingUid, userId, true, "createSession");
@@ -389,8 +394,8 @@ public class PackageInstallerService extends IPackageInstaller.Stub {
}
switch (params.mode) {
- case InstallSessionParams.MODE_FULL_INSTALL:
- case InstallSessionParams.MODE_INHERIT_EXISTING:
+ case SessionParams.MODE_FULL_INSTALL:
+ case SessionParams.MODE_INHERIT_EXISTING:
break;
default:
throw new IllegalArgumentException("Params must have valid mode set");
@@ -437,7 +442,7 @@ public class PackageInstallerService extends IPackageInstaller.Stub {
final long createdMillis = System.currentTimeMillis();
final File sessionStageDir = prepareSessionStageDir(sessionId);
- session = new PackageInstallerSession(mInternalCallback, mPm,
+ session = new PackageInstallerSession(mInternalCallback, mContext, mPm,
mInstallThread.getLooper(), sessionId, userId, installerPackageName, params,
createdMillis, sessionStageDir, false);
mSessions.put(sessionId, session);
@@ -501,7 +506,7 @@ public class PackageInstallerService extends IPackageInstaller.Stub {
}
@Override
- public InstallSessionInfo getSessionInfo(int sessionId) {
+ public SessionInfo getSessionInfo(int sessionId) {
synchronized (mSessions) {
final PackageInstallerSession session = mSessions.get(sessionId);
if (!isCallingUidOwner(session)) {
@@ -512,11 +517,11 @@ public class PackageInstallerService extends IPackageInstaller.Stub {
}
@Override
- public List<InstallSessionInfo> getAllSessions(int userId) {
+ public List<SessionInfo> getAllSessions(int userId) {
mPm.enforceCrossUserPermission(Binder.getCallingUid(), userId, true, "getAllSessions");
enforceCallerCanReadSessions();
- final List<InstallSessionInfo> result = new ArrayList<>();
+ final List<SessionInfo> result = new ArrayList<>();
synchronized (mSessions) {
for (int i = 0; i < mSessions.size(); i++) {
final PackageInstallerSession session = mSessions.valueAt(i);
@@ -529,11 +534,11 @@ public class PackageInstallerService extends IPackageInstaller.Stub {
}
@Override
- public List<InstallSessionInfo> getMySessions(String installerPackageName, int userId) {
+ public List<SessionInfo> getMySessions(String installerPackageName, int userId) {
mPm.enforceCrossUserPermission(Binder.getCallingUid(), userId, true, "getMySessions");
mAppOps.checkPackage(Binder.getCallingUid(), installerPackageName);
- final List<InstallSessionInfo> result = new ArrayList<>();
+ final List<SessionInfo> result = new ArrayList<>();
synchronized (mSessions) {
for (int i = 0; i < mSessions.size(); i++) {
final PackageInstallerSession session = mSessions.valueAt(i);
@@ -547,37 +552,26 @@ public class PackageInstallerService extends IPackageInstaller.Stub {
}
@Override
- public void uninstall(String packageName, int flags, IPackageDeleteObserver2 observer,
- int userId) {
+ public void uninstall(String packageName, int flags, IntentSender statusReceiver, int userId) {
mPm.enforceCrossUserPermission(Binder.getCallingUid(), userId, true, "uninstall");
+ final PackageDeleteObserverAdapter adapter = new PackageDeleteObserverAdapter(mContext,
+ statusReceiver);
if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DELETE_PACKAGES)
== PackageManager.PERMISSION_GRANTED) {
// Sweet, call straight through!
- mPm.deletePackage(packageName, observer, userId, flags);
+ mPm.deletePackage(packageName, adapter.getBinder(), userId, flags);
} else {
// Take a short detour to confirm with user
final Intent intent = new Intent(Intent.ACTION_UNINSTALL_PACKAGE);
intent.setData(Uri.fromParts("package", packageName, null));
- intent.putExtra(PackageInstaller.EXTRA_CALLBACK, observer.asBinder());
- try {
- observer.onUserActionRequired(intent);
- } catch (RemoteException ignored) {
- }
+ intent.putExtra(PackageInstaller.EXTRA_CALLBACK, adapter.getBinder().asBinder());
+ adapter.onUserActionRequired(intent);
}
}
@Override
- public void uninstallSplit(String basePackageName, String overlayName, int flags,
- IPackageDeleteObserver2 observer, int userId) {
- mPm.enforceCrossUserPermission(Binder.getCallingUid(), userId, true, "uninstallSplit");
-
- // TODO: flesh out once PM has split support
- throw new UnsupportedOperationException();
- }
-
- @Override
public void setPermissionsResult(int sessionId, boolean accepted) {
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.INSTALL_PACKAGES, TAG);
@@ -636,6 +630,87 @@ public class PackageInstallerService extends IPackageInstaller.Stub {
}
}
+ static class PackageDeleteObserverAdapter extends PackageDeleteObserver {
+ private final Context mContext;
+ private final IntentSender mTarget;
+
+ public PackageDeleteObserverAdapter(Context context, IntentSender target) {
+ mContext = context;
+ mTarget = target;
+ }
+
+ @Override
+ public void onUserActionRequired(Intent intent) {
+ final Intent fillIn = new Intent();
+ fillIn.putExtra(PackageInstaller.EXTRA_STATUS,
+ PackageInstaller.STATUS_USER_ACTION_REQUIRED);
+ fillIn.putExtra(Intent.EXTRA_INTENT, intent);
+ try {
+ mTarget.sendIntent(mContext, 0, fillIn, null, null);
+ } catch (SendIntentException ignored) {
+ }
+ }
+
+ @Override
+ public void onPackageDeleted(String basePackageName, int returnCode, String msg) {
+ final Intent fillIn = new Intent();
+ fillIn.putExtra(PackageInstaller.EXTRA_STATUS,
+ PackageManager.deleteStatusToPublicStatus(returnCode));
+ fillIn.putExtra(PackageInstaller.EXTRA_STATUS_MESSAGE,
+ PackageManager.deleteStatusToString(returnCode, msg));
+ fillIn.putExtra(PackageInstaller.EXTRA_LEGACY_STATUS, returnCode);
+ try {
+ mTarget.sendIntent(mContext, 0, fillIn, null, null);
+ } catch (SendIntentException ignored) {
+ }
+ }
+ }
+
+ static class PackageInstallObserverAdapter extends PackageInstallObserver {
+ private final Context mContext;
+ private final IntentSender mTarget;
+
+ public PackageInstallObserverAdapter(Context context, IntentSender target) {
+ mContext = context;
+ mTarget = target;
+ }
+
+ @Override
+ public void onUserActionRequired(Intent intent) {
+ final Intent fillIn = new Intent();
+ fillIn.putExtra(PackageInstaller.EXTRA_STATUS,
+ PackageInstaller.STATUS_USER_ACTION_REQUIRED);
+ fillIn.putExtra(Intent.EXTRA_INTENT, intent);
+ try {
+ mTarget.sendIntent(mContext, 0, fillIn, null, null);
+ } catch (SendIntentException ignored) {
+ }
+ }
+
+ @Override
+ public void onPackageInstalled(String basePackageName, int returnCode, String msg,
+ Bundle extras) {
+ final Intent fillIn = new Intent();
+ fillIn.putExtra(PackageInstaller.EXTRA_STATUS,
+ PackageManager.installStatusToPublicStatus(returnCode));
+ fillIn.putExtra(PackageInstaller.EXTRA_STATUS_MESSAGE,
+ PackageManager.installStatusToString(returnCode, msg));
+ fillIn.putExtra(PackageInstaller.EXTRA_LEGACY_STATUS, returnCode);
+ if (extras != null) {
+ final String existing = extras.getString(
+ PackageManager.EXTRA_FAILURE_EXISTING_PACKAGE);
+ if (!TextUtils.isEmpty(existing)) {
+ fillIn.putExtra(PackageInstaller.EXTRA_PACKAGE_NAMES, new String[] {
+ existing });
+ }
+ }
+ try {
+ mTarget.sendIntent(mContext, 0, fillIn, null, null);
+ } catch (SendIntentException ignored) {
+ }
+ }
+ }
+
private static class Callbacks extends Handler {
private static final int MSG_SESSION_CREATED = 1;
private static final int MSG_SESSION_OPENED = 2;
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index a3184f027093..5ef24f2ab6ac 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -25,13 +25,15 @@ import static android.system.OsConstants.O_CREAT;
import static android.system.OsConstants.O_RDONLY;
import static android.system.OsConstants.O_WRONLY;
+import android.content.Context;
import android.content.Intent;
+import android.content.IntentSender;
import android.content.pm.ApplicationInfo;
import android.content.pm.IPackageInstallObserver2;
import android.content.pm.IPackageInstallerSession;
-import android.content.pm.InstallSessionInfo;
-import android.content.pm.InstallSessionParams;
import android.content.pm.PackageInstaller;
+import android.content.pm.PackageInstaller.SessionInfo;
+import android.content.pm.PackageInstaller.SessionParams;
import android.content.pm.PackageManager;
import android.content.pm.PackageParser;
import android.content.pm.PackageParser.ApkLite;
@@ -59,6 +61,7 @@ import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.IndentingPrintWriter;
import com.android.internal.util.Preconditions;
+import com.android.server.pm.PackageInstallerService.PackageInstallObserverAdapter;
import libcore.io.Libcore;
@@ -81,13 +84,14 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
// TODO: treat INHERIT_EXISTING as installExistingPackage()
private final PackageInstallerService.InternalCallback mCallback;
+ private final Context mContext;
private final PackageManagerService mPm;
private final Handler mHandler;
final int sessionId;
final int userId;
final String installerPackageName;
- final InstallSessionParams params;
+ final SessionParams params;
final long createdMillis;
final File sessionStageDir;
@@ -159,10 +163,11 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
};
public PackageInstallerSession(PackageInstallerService.InternalCallback callback,
- PackageManagerService pm, Looper looper, int sessionId, int userId,
- String installerPackageName, InstallSessionParams params, long createdMillis,
+ Context context, PackageManagerService pm, Looper looper, int sessionId, int userId,
+ String installerPackageName, SessionParams params, long createdMillis,
File sessionStageDir, boolean sealed) {
mCallback = callback;
+ mContext = context;
mPm = pm;
mHandler = new Handler(looper, mHandlerCallback);
@@ -188,8 +193,8 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
computeProgressLocked();
}
- public InstallSessionInfo generateInfo() {
- final InstallSessionInfo info = new InstallSessionInfo();
+ public SessionInfo generateInfo() {
+ final SessionInfo info = new SessionInfo();
info.sessionId = sessionId;
info.installerPackageName = installerPackageName;
@@ -246,8 +251,8 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
}
@Override
- public String[] list() {
- assertNotSealed("list");
+ public String[] getNames() {
+ assertNotSealed("getNames");
return sessionStageDir.list();
}
@@ -337,9 +342,12 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
}
@Override
- public void commit(IPackageInstallObserver2 observer) {
- Preconditions.checkNotNull(observer);
- mHandler.obtainMessage(MSG_COMMIT, observer).sendToTarget();
+ public void commit(IntentSender statusReceiver) {
+ Preconditions.checkNotNull(statusReceiver);
+
+ final PackageInstallObserverAdapter adapter = new PackageInstallObserverAdapter(mContext,
+ statusReceiver);
+ mHandler.obtainMessage(MSG_COMMIT, adapter.getBinder()).sendToTarget();
}
private void commitLocked() throws PackageManagerException {
@@ -385,7 +393,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
// Inherit any packages and native libraries from existing install that
// haven't been overridden.
- if (params.mode == InstallSessionParams.MODE_INHERIT_EXISTING) {
+ if (params.mode == SessionParams.MODE_INHERIT_EXISTING) {
spliceExistingFilesIntoStage();
}
@@ -396,7 +404,6 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
// We've reached point of no return; call into PMS to install the stage.
// Regardless of success or failure we always destroy session.
- final IPackageInstallObserver2 remoteObserver = mRemoteObserver;
final IPackageInstallObserver2 localObserver = new IPackageInstallObserver2.Stub() {
@Override
public void onUserActionRequired(Intent intent) {
@@ -488,7 +495,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
// currently relying on PMS to do this.
// TODO: teach about compatible upgrade keysets.
- if (params.mode == InstallSessionParams.MODE_FULL_INSTALL) {
+ if (params.mode == SessionParams.MODE_FULL_INSTALL) {
// Full installs must include a base package
if (!seenSplits.contains(null)) {
throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 89bd1d4a589c..63f3c0f7b4ca 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -107,12 +107,12 @@ import android.content.pm.IPackageInstaller;
import android.content.pm.IPackageManager;
import android.content.pm.IPackageMoveObserver;
import android.content.pm.IPackageStatsObserver;
-import android.content.pm.InstallSessionParams;
import android.content.pm.InstrumentationInfo;
import android.content.pm.ManifestDigest;
import android.content.pm.PackageCleanItem;
import android.content.pm.PackageInfo;
import android.content.pm.PackageInfoLite;
+import android.content.pm.PackageInstaller;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.LegacyPackageDeleteObserver;
import android.content.pm.PackageParser.ActivityIntentInfo;
@@ -1394,16 +1394,27 @@ public class PackageManagerService extends IPackageManager.Stub {
* list of process files because dexopt will have been run
* if necessary during zygote startup.
*/
- String bootClassPath = System.getProperty("java.boot.class.path");
+ final String bootClassPath = System.getenv("BOOTCLASSPATH");
+ final String systemServerClassPath = System.getenv("SYSTEMSERVERCLASSPATH");
+
if (bootClassPath != null) {
- String[] paths = splitString(bootClassPath, ':');
- for (int i=0; i<paths.length; i++) {
- alreadyDexOpted.add(paths[i]);
+ String[] bootClassPathElements = splitString(bootClassPath, ':');
+ for (String element : bootClassPathElements) {
+ alreadyDexOpted.add(element);
}
} else {
Slog.w(TAG, "No BOOTCLASSPATH found!");
}
+ if (systemServerClassPath != null) {
+ String[] systemServerClassPathElements = splitString(systemServerClassPath, ':');
+ for (String element : systemServerClassPathElements) {
+ alreadyDexOpted.add(element);
+ }
+ } else {
+ Slog.w(TAG, "No SYSTEMSERVERCLASSPATH found!");
+ }
+
boolean didDexOptLibraryOrTool = false;
final List<String> allInstructionSets = getAllInstructionSets();
@@ -7835,7 +7846,7 @@ public class PackageManagerService extends IPackageManager.Stub {
}
void installStage(String packageName, File stageDir, IPackageInstallObserver2 observer,
- InstallSessionParams params, String installerPackageName, int installerUid,
+ PackageInstaller.SessionParams params, String installerPackageName, int installerUid,
UserHandle user) {
final VerificationParams verifParams = new VerificationParams(null, params.originatingUri,
params.referrerUri, installerUid, null);
diff --git a/services/core/java/com/android/server/power/Notifier.java b/services/core/java/com/android/server/power/Notifier.java
index 2b4a24a768a1..464972428409 100644
--- a/services/core/java/com/android/server/power/Notifier.java
+++ b/services/core/java/com/android/server/power/Notifier.java
@@ -406,7 +406,6 @@ final class Notifier {
private void sendNextBroadcast() {
final int powerState;
- final int goToSleepReason;
synchronized (mLock) {
if (mBroadcastedPowerState == POWER_STATE_UNKNOWN) {
// Broadcasted power state is unknown. Send wake up.
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index 39c6e0e2e982..41db2c39b0c4 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -56,10 +56,9 @@ import android.os.RemoteException;
import android.os.SystemClock;
import android.os.SystemProperties;
import android.os.SystemService;
+import android.os.Trace;
import android.os.UserHandle;
import android.os.WorkSource;
-import android.os.Parcel;
-import android.os.ServiceManager;
import android.provider.Settings;
import android.service.dreams.DreamManagerInternal;
import android.util.EventLog;
@@ -709,7 +708,6 @@ public final class PowerManagerService extends com.android.server.SystemService
if (mLowPowerModeEnabled != lowPowerModeEnabled) {
mLowPowerModeEnabled = lowPowerModeEnabled;
powerHintInternal(POWER_HINT_LOW_POWER_MODE, lowPowerModeEnabled ? 1 : 0);
- setSurfaceFlingerLowPowerMode(lowPowerModeEnabled ? 1 : 0);
mLowPowerModeEnabled = lowPowerModeEnabled;
BackgroundThread.getHandler().post(new Runnable() {
@Override
@@ -820,17 +818,12 @@ public final class PowerManagerService extends com.android.server.SystemService
+ " [" + wakeLock.mTag + "], flags=0x" + Integer.toHexString(flags));
}
- mWakeLocks.remove(index);
- notifyWakeLockReleasedLocked(wakeLock);
- wakeLock.mLock.unlinkToDeath(wakeLock, 0);
-
if ((flags & PowerManager.WAIT_FOR_PROXIMITY_NEGATIVE) != 0) {
mRequestWaitForNegativeProximity = true;
}
- applyWakeLockFlagsOnReleaseLocked(wakeLock);
- mDirty |= DIRTY_WAKE_LOCKS;
- updatePowerStateLocked();
+ wakeLock.mLock.unlinkToDeath(wakeLock, 0);
+ removeWakeLockLocked(wakeLock, index);
}
}
@@ -846,15 +839,19 @@ public final class PowerManagerService extends com.android.server.SystemService
return;
}
- mWakeLocks.remove(index);
- notifyWakeLockReleasedLocked(wakeLock);
-
- applyWakeLockFlagsOnReleaseLocked(wakeLock);
- mDirty |= DIRTY_WAKE_LOCKS;
- updatePowerStateLocked();
+ removeWakeLockLocked(wakeLock, index);
}
}
+ private void removeWakeLockLocked(WakeLock wakeLock, int index) {
+ mWakeLocks.remove(index);
+ notifyWakeLockReleasedLocked(wakeLock);
+
+ applyWakeLockFlagsOnReleaseLocked(wakeLock);
+ mDirty |= DIRTY_WAKE_LOCKS;
+ updatePowerStateLocked();
+ }
+
private void applyWakeLockFlagsOnReleaseLocked(WakeLock wakeLock) {
if ((wakeLock.mFlags & PowerManager.ON_AFTER_RELEASE) != 0
&& isScreenLock(wakeLock)) {
@@ -975,21 +972,26 @@ public final class PowerManagerService extends com.android.server.SystemService
return false;
}
- mNotifier.onUserActivity(event, uid);
+ Trace.traceBegin(Trace.TRACE_TAG_POWER, "userActivity");
+ try {
+ mNotifier.onUserActivity(event, uid);
- if ((flags & PowerManager.USER_ACTIVITY_FLAG_NO_CHANGE_LIGHTS) != 0) {
- if (eventTime > mLastUserActivityTimeNoChangeLights
- && eventTime > mLastUserActivityTime) {
- mLastUserActivityTimeNoChangeLights = eventTime;
- mDirty |= DIRTY_USER_ACTIVITY;
- return true;
- }
- } else {
- if (eventTime > mLastUserActivityTime) {
- mLastUserActivityTime = eventTime;
- mDirty |= DIRTY_USER_ACTIVITY;
- return true;
+ if ((flags & PowerManager.USER_ACTIVITY_FLAG_NO_CHANGE_LIGHTS) != 0) {
+ if (eventTime > mLastUserActivityTimeNoChangeLights
+ && eventTime > mLastUserActivityTime) {
+ mLastUserActivityTimeNoChangeLights = eventTime;
+ mDirty |= DIRTY_USER_ACTIVITY;
+ return true;
+ }
+ } else {
+ if (eventTime > mLastUserActivityTime) {
+ mLastUserActivityTime = eventTime;
+ mDirty |= DIRTY_USER_ACTIVITY;
+ return true;
+ }
}
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_POWER);
}
return false;
}
@@ -1012,25 +1014,30 @@ public final class PowerManagerService extends com.android.server.SystemService
return false;
}
- switch (mWakefulness) {
- case WAKEFULNESS_ASLEEP:
- Slog.i(TAG, "Waking up from sleep (uid " + uid +")...");
- break;
- case WAKEFULNESS_DREAMING:
- Slog.i(TAG, "Waking up from dream (uid " + uid +")...");
- break;
- case WAKEFULNESS_DOZING:
- Slog.i(TAG, "Waking up from dozing (uid " + uid +")...");
- break;
- }
+ Trace.traceBegin(Trace.TRACE_TAG_POWER, "wakeUp");
+ try {
+ switch (mWakefulness) {
+ case WAKEFULNESS_ASLEEP:
+ Slog.i(TAG, "Waking up from sleep (uid " + uid +")...");
+ break;
+ case WAKEFULNESS_DREAMING:
+ Slog.i(TAG, "Waking up from dream (uid " + uid +")...");
+ break;
+ case WAKEFULNESS_DOZING:
+ Slog.i(TAG, "Waking up from dozing (uid " + uid +")...");
+ break;
+ }
- mLastWakeTime = eventTime;
- mDirty |= DIRTY_WAKEFULNESS;
- mWakefulness = WAKEFULNESS_AWAKE;
- setInteractiveStateLocked(true, 0);
+ mLastWakeTime = eventTime;
+ mDirty |= DIRTY_WAKEFULNESS;
+ mWakefulness = WAKEFULNESS_AWAKE;
+ setInteractiveStateLocked(true, 0);
- userActivityNoUpdateLocked(
- eventTime, PowerManager.USER_ACTIVITY_EVENT_OTHER, 0, uid);
+ userActivityNoUpdateLocked(
+ eventTime, PowerManager.USER_ACTIVITY_EVENT_OTHER, 0, uid);
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_POWER);
+ }
return true;
}
@@ -1058,53 +1065,58 @@ public final class PowerManagerService extends com.android.server.SystemService
return false;
}
- switch (reason) {
- case PowerManager.GO_TO_SLEEP_REASON_DEVICE_ADMIN:
- Slog.i(TAG, "Going to sleep due to device administration policy "
- + "(uid " + uid +")...");
- break;
- case PowerManager.GO_TO_SLEEP_REASON_TIMEOUT:
- Slog.i(TAG, "Going to sleep due to screen timeout (uid " + uid +")...");
- break;
- case PowerManager.GO_TO_SLEEP_REASON_LID_SWITCH:
- Slog.i(TAG, "Going to sleep due to lid switch (uid " + uid +")...");
- break;
- case PowerManager.GO_TO_SLEEP_REASON_POWER_BUTTON:
- Slog.i(TAG, "Going to sleep due to power button (uid " + uid +")...");
- break;
- case PowerManager.GO_TO_SLEEP_REASON_HDMI:
- Slog.i(TAG, "Going to sleep due to HDMI standby (uid " + uid +")...");
- break;
- default:
- Slog.i(TAG, "Going to sleep by application request (uid " + uid +")...");
- reason = PowerManager.GO_TO_SLEEP_REASON_APPLICATION;
- break;
- }
-
- mLastSleepTime = eventTime;
- mDirty |= DIRTY_WAKEFULNESS;
- mWakefulness = WAKEFULNESS_DOZING;
- mSandmanSummoned = true;
- setInteractiveStateLocked(false, reason);
-
- // Report the number of wake locks that will be cleared by going to sleep.
- int numWakeLocksCleared = 0;
- final int numWakeLocks = mWakeLocks.size();
- for (int i = 0; i < numWakeLocks; i++) {
- final WakeLock wakeLock = mWakeLocks.get(i);
- switch (wakeLock.mFlags & PowerManager.WAKE_LOCK_LEVEL_MASK) {
- case PowerManager.FULL_WAKE_LOCK:
- case PowerManager.SCREEN_BRIGHT_WAKE_LOCK:
- case PowerManager.SCREEN_DIM_WAKE_LOCK:
- numWakeLocksCleared += 1;
+ Trace.traceBegin(Trace.TRACE_TAG_POWER, "goToSleep");
+ try {
+ switch (reason) {
+ case PowerManager.GO_TO_SLEEP_REASON_DEVICE_ADMIN:
+ Slog.i(TAG, "Going to sleep due to device administration policy "
+ + "(uid " + uid +")...");
+ break;
+ case PowerManager.GO_TO_SLEEP_REASON_TIMEOUT:
+ Slog.i(TAG, "Going to sleep due to screen timeout (uid " + uid +")...");
+ break;
+ case PowerManager.GO_TO_SLEEP_REASON_LID_SWITCH:
+ Slog.i(TAG, "Going to sleep due to lid switch (uid " + uid +")...");
+ break;
+ case PowerManager.GO_TO_SLEEP_REASON_POWER_BUTTON:
+ Slog.i(TAG, "Going to sleep due to power button (uid " + uid +")...");
+ break;
+ case PowerManager.GO_TO_SLEEP_REASON_HDMI:
+ Slog.i(TAG, "Going to sleep due to HDMI standby (uid " + uid +")...");
+ break;
+ default:
+ Slog.i(TAG, "Going to sleep by application request (uid " + uid +")...");
+ reason = PowerManager.GO_TO_SLEEP_REASON_APPLICATION;
break;
}
- }
- EventLog.writeEvent(EventLogTags.POWER_SLEEP_REQUESTED, numWakeLocksCleared);
- // Skip dozing if requested.
- if ((flags & PowerManager.GO_TO_SLEEP_FLAG_NO_DOZE) != 0) {
- reallyGoToSleepNoUpdateLocked(eventTime, uid);
+ mLastSleepTime = eventTime;
+ mDirty |= DIRTY_WAKEFULNESS;
+ mWakefulness = WAKEFULNESS_DOZING;
+ mSandmanSummoned = true;
+ setInteractiveStateLocked(false, reason);
+
+ // Report the number of wake locks that will be cleared by going to sleep.
+ int numWakeLocksCleared = 0;
+ final int numWakeLocks = mWakeLocks.size();
+ for (int i = 0; i < numWakeLocks; i++) {
+ final WakeLock wakeLock = mWakeLocks.get(i);
+ switch (wakeLock.mFlags & PowerManager.WAKE_LOCK_LEVEL_MASK) {
+ case PowerManager.FULL_WAKE_LOCK:
+ case PowerManager.SCREEN_BRIGHT_WAKE_LOCK:
+ case PowerManager.SCREEN_DIM_WAKE_LOCK:
+ numWakeLocksCleared += 1;
+ break;
+ }
+ }
+ EventLog.writeEvent(EventLogTags.POWER_SLEEP_REQUESTED, numWakeLocksCleared);
+
+ // Skip dozing if requested.
+ if ((flags & PowerManager.GO_TO_SLEEP_FLAG_NO_DOZE) != 0) {
+ reallyGoToSleepNoUpdateLocked(eventTime, uid);
+ }
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_POWER);
}
return true;
}
@@ -1127,12 +1139,17 @@ public final class PowerManagerService extends com.android.server.SystemService
return false;
}
- Slog.i(TAG, "Nap time (uid " + uid +")...");
+ Trace.traceBegin(Trace.TRACE_TAG_POWER, "nap");
+ try {
+ Slog.i(TAG, "Nap time (uid " + uid +")...");
- mDirty |= DIRTY_WAKEFULNESS;
- mWakefulness = WAKEFULNESS_DREAMING;
- mSandmanSummoned = true;
- setInteractiveStateLocked(true, 0);
+ mDirty |= DIRTY_WAKEFULNESS;
+ mWakefulness = WAKEFULNESS_DREAMING;
+ mSandmanSummoned = true;
+ setInteractiveStateLocked(true, 0);
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_POWER);
+ }
return true;
}
@@ -1148,11 +1165,16 @@ public final class PowerManagerService extends com.android.server.SystemService
return false;
}
- Slog.i(TAG, "Sleeping (uid " + uid +")...");
+ Trace.traceBegin(Trace.TRACE_TAG_POWER, "reallyGoToSleep");
+ try {
+ Slog.i(TAG, "Sleeping (uid " + uid +")...");
- mDirty |= DIRTY_WAKEFULNESS;
- mWakefulness = WAKEFULNESS_ASLEEP;
- setInteractiveStateLocked(false, PowerManager.GO_TO_SLEEP_REASON_TIMEOUT);
+ mDirty |= DIRTY_WAKEFULNESS;
+ mWakefulness = WAKEFULNESS_ASLEEP;
+ setInteractiveStateLocked(false, PowerManager.GO_TO_SLEEP_REASON_TIMEOUT);
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_POWER);
+ }
return true;
}
@@ -1189,40 +1211,45 @@ public final class PowerManagerService extends com.android.server.SystemService
Slog.wtf(TAG, "Power manager lock was not held when calling updatePowerStateLocked");
}
- // Phase 0: Basic state updates.
- updateIsPoweredLocked(mDirty);
- updateStayOnLocked(mDirty);
-
- // Phase 1: Update wakefulness.
- // Loop because the wake lock and user activity computations are influenced
- // by changes in wakefulness.
- final long now = SystemClock.uptimeMillis();
- int dirtyPhase2 = 0;
- for (;;) {
- int dirtyPhase1 = mDirty;
- dirtyPhase2 |= dirtyPhase1;
- mDirty = 0;
+ Trace.traceBegin(Trace.TRACE_TAG_POWER, "updatePowerState");
+ try {
+ // Phase 0: Basic state updates.
+ updateIsPoweredLocked(mDirty);
+ updateStayOnLocked(mDirty);
- updateWakeLockSummaryLocked(dirtyPhase1);
- updateUserActivitySummaryLocked(now, dirtyPhase1);
- if (!updateWakefulnessLocked(dirtyPhase1)) {
- break;
+ // Phase 1: Update wakefulness.
+ // Loop because the wake lock and user activity computations are influenced
+ // by changes in wakefulness.
+ final long now = SystemClock.uptimeMillis();
+ int dirtyPhase2 = 0;
+ for (;;) {
+ int dirtyPhase1 = mDirty;
+ dirtyPhase2 |= dirtyPhase1;
+ mDirty = 0;
+
+ updateWakeLockSummaryLocked(dirtyPhase1);
+ updateUserActivitySummaryLocked(now, dirtyPhase1);
+ if (!updateWakefulnessLocked(dirtyPhase1)) {
+ break;
+ }
}
- }
- // Phase 2: Update dreams and display power state.
- updateDreamLocked(dirtyPhase2);
- updateDisplayPowerStateLocked(dirtyPhase2);
+ // Phase 2: Update dreams and display power state.
+ updateDreamLocked(dirtyPhase2);
+ updateDisplayPowerStateLocked(dirtyPhase2);
- // Phase 3: Send notifications, if needed.
- if (mDisplayReady) {
- finishInteractiveStateChangeLocked();
- }
+ // Phase 3: Send notifications, if needed.
+ if (mDisplayReady) {
+ finishInteractiveStateChangeLocked();
+ }
- // Phase 4: Update suspend blocker.
- // Because we might release the last suspend blocker here, we need to make sure
- // we finished everything else first!
- updateSuspendBlockerLocked();
+ // Phase 4: Update suspend blocker.
+ // Because we might release the last suspend blocker here, we need to make sure
+ // we finished everything else first!
+ updateSuspendBlockerLocked();
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_POWER);
+ }
}
/**
@@ -1993,7 +2020,12 @@ public final class PowerManagerService extends com.android.server.SystemService
Slog.d(TAG, "Setting HAL auto-suspend mode to " + enable);
}
mHalAutoSuspendModeEnabled = enable;
- nativeSetAutoSuspend(enable);
+ Trace.traceBegin(Trace.TRACE_TAG_POWER, "setHalAutoSuspend(" + enable + ")");
+ try {
+ nativeSetAutoSuspend(enable);
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_POWER);
+ }
}
}
@@ -2003,7 +2035,12 @@ public final class PowerManagerService extends com.android.server.SystemService
Slog.d(TAG, "Setting HAL interactive mode to " + enable);
}
mHalInteractiveModeEnabled = enable;
- nativeSetInteractive(enable);
+ Trace.traceBegin(Trace.TRACE_TAG_POWER, "setHalInteractive(" + enable + ")");
+ try {
+ nativeSetInteractive(enable);
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_POWER);
+ }
}
}
@@ -2198,21 +2235,6 @@ public final class PowerManagerService extends com.android.server.SystemService
nativeSendPowerHint(hintId, data);
}
- private static void setSurfaceFlingerLowPowerMode(int enabled) {
- try {
- final IBinder flinger = ServiceManager.getService("SurfaceFlinger");
- if (flinger != null) {
- final Parcel data = Parcel.obtain();
- data.writeInterfaceToken("android.ui.ISurfaceComposer");
- data.writeInt(enabled);
- flinger.transact(1016, data, null, 0);
- data.recycle();
- }
- } catch (RemoteException ex) {
- Slog.e(TAG, "Failed to reduce refresh rate", ex);
- }
- }
-
/**
* Low-level function turn the device off immediately, without trying
* to be clean. Most people should use {@link ShutdownThread} for a clean shutdown.
@@ -2605,20 +2627,23 @@ public final class PowerManagerService extends com.android.server.SystemService
private final class SuspendBlockerImpl implements SuspendBlocker {
private final String mName;
+ private final String mTraceName;
private int mReferenceCount;
public SuspendBlockerImpl(String name) {
mName = name;
+ mTraceName = "SuspendBlocker (" + name + ")";
}
@Override
protected void finalize() throws Throwable {
try {
if (mReferenceCount != 0) {
- Log.wtf(TAG, "Suspend blocker \"" + mName
+ Slog.wtf(TAG, "Suspend blocker \"" + mName
+ "\" was finalized without being released!");
mReferenceCount = 0;
nativeReleaseSuspendBlocker(mName);
+ Trace.asyncTraceEnd(Trace.TRACE_TAG_POWER, mTraceName, 0);
}
} finally {
super.finalize();
@@ -2633,6 +2658,7 @@ public final class PowerManagerService extends com.android.server.SystemService
if (DEBUG_SPEW) {
Slog.d(TAG, "Acquiring suspend blocker \"" + mName + "\".");
}
+ Trace.asyncTraceBegin(Trace.TRACE_TAG_POWER, mTraceName, 0);
nativeAcquireSuspendBlocker(mName);
}
}
@@ -2647,8 +2673,9 @@ public final class PowerManagerService extends com.android.server.SystemService
Slog.d(TAG, "Releasing suspend blocker \"" + mName + "\".");
}
nativeReleaseSuspendBlocker(mName);
+ Trace.asyncTraceEnd(Trace.TRACE_TAG_POWER, mTraceName, 0);
} else if (mReferenceCount < 0) {
- Log.wtf(TAG, "Suspend blocker \"" + mName
+ Slog.wtf(TAG, "Suspend blocker \"" + mName
+ "\" was released without being acquired!", new Throwable());
mReferenceCount = 0;
}
@@ -2664,6 +2691,8 @@ public final class PowerManagerService extends com.android.server.SystemService
}
private final class ScreenOnBlockerImpl implements ScreenOnBlocker {
+ private static final String TRACE_NAME = "ScreenOnBlocker";
+
private int mNestCount;
public boolean isHeld() {
@@ -2676,9 +2705,12 @@ public final class PowerManagerService extends com.android.server.SystemService
public void acquire() {
synchronized (this) {
mNestCount += 1;
- if (DEBUG) {
+ if (DEBUG || true) {
Slog.d(TAG, "Screen on blocked: mNestCount=" + mNestCount);
}
+ if (mNestCount == 1) {
+ Trace.asyncTraceBegin(Trace.TRACE_TAG_POWER, TRACE_NAME, 0);
+ }
}
}
@@ -2686,16 +2718,16 @@ public final class PowerManagerService extends com.android.server.SystemService
public void release() {
synchronized (this) {
mNestCount -= 1;
- if (mNestCount < 0) {
- Log.wtf(TAG, "Screen on blocker was released without being acquired!",
- new Throwable());
- mNestCount = 0;
- }
if (mNestCount == 0) {
+ if (DEBUG || true) {
+ Slog.d(TAG, "Screen on unblocked: mNestCount=" + mNestCount);
+ }
mHandler.sendEmptyMessage(MSG_SCREEN_ON_BLOCKER_RELEASED);
- }
- if (DEBUG) {
- Slog.d(TAG, "Screen on unblocked: mNestCount=" + mNestCount);
+ Trace.asyncTraceEnd(Trace.TRACE_TAG_POWER, TRACE_NAME, 0);
+ } else if (mNestCount < 0) {
+ Slog.wtf(TAG, "Screen on blocker was released without being acquired!",
+ new Throwable());
+ mNestCount = 0;
}
}
}
diff --git a/services/core/java/com/android/server/tv/TvInputManagerService.java b/services/core/java/com/android/server/tv/TvInputManagerService.java
index 3b5e79d9dea6..aa8c391567eb 100644
--- a/services/core/java/com/android/server/tv/TvInputManagerService.java
+++ b/services/core/java/com/android/server/tv/TvInputManagerService.java
@@ -1223,7 +1223,7 @@ public final class TvInputManagerService extends SystemService {
try {
getSessionLocked(sessionToken, callingUid, resolvedUserId).tune(
channelUri, params);
- if (TvContract.isChannelUriForPassthroughTvInput(channelUri)) {
+ if (TvContract.isChannelUriForPassthroughInput(channelUri)) {
// Do not log the watch history for passthrough inputs.
return;
}
diff --git a/services/core/jni/onload.cpp b/services/core/jni/onload.cpp
index ce2ca9b5be36..39b70a86c03e 100644
--- a/services/core/jni/onload.cpp
+++ b/services/core/jni/onload.cpp
@@ -41,6 +41,8 @@ int register_android_server_hdmi_HdmiCecController(JNIEnv* env);
int register_android_server_hdmi_HdmiMhlController(JNIEnv* env);
int register_android_server_tv_TvInputHal(JNIEnv* env);
int register_android_server_PersistentDataBlockService(JNIEnv* env);
+int register_android_server_fingerprint_FingerprintService(JNIEnv* env);
+int register_android_server_Watchdog(JNIEnv* env);
};
using namespace android;
@@ -77,6 +79,8 @@ extern "C" jint JNI_OnLoad(JavaVM* vm, void* reserved)
register_android_server_hdmi_HdmiMhlController(env);
register_android_server_tv_TvInputHal(env);
register_android_server_PersistentDataBlockService(env);
+ register_android_server_fingerprint_FingerprintService(env);
+ register_android_server_Watchdog(env);
return JNI_VERSION_1_4;
}
diff --git a/services/devicepolicy/Android.mk b/services/devicepolicy/Android.mk
index a55d1386671c..7020f174fefe 100644
--- a/services/devicepolicy/Android.mk
+++ b/services/devicepolicy/Android.mk
@@ -7,6 +7,6 @@ LOCAL_MODULE := services.devicepolicy
LOCAL_SRC_FILES += \
$(call all-java-files-under,java)
-LOCAL_JAVA_LIBRARIES := conscrypt
+LOCAL_JAVA_LIBRARIES := conscrypt services.core
include $(BUILD_STATIC_JAVA_LIBRARY)
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index fc96991fbca8..d46ae42c1ce4 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -19,6 +19,7 @@ package com.android.server.devicepolicy;
import static android.Manifest.permission.MANAGE_CA_CERTIFICATES;
import android.app.admin.DevicePolicyManagerInternal;
+
import com.android.internal.R;
import com.android.internal.os.storage.ExternalStorageFormatter;
import com.android.internal.util.FastXmlSerializer;
@@ -58,6 +59,7 @@ import android.net.ConnectivityManager;
import android.net.Uri;
import android.content.pm.PackageManager.NameNotFoundException;
import android.database.ContentObserver;
+import android.hardware.usb.UsbManager;
import android.net.ProxyInfo;
import android.os.Binder;
import android.os.Bundle;
@@ -3417,8 +3419,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
synchronized (this) {
long ident = Binder.clearCallingIdentity();
try {
- mUserManager.setUserRestrictions(new Bundle(),
- new UserHandle(UserHandle.USER_OWNER));
+ clearUserRestrictions(new UserHandle(UserHandle.USER_OWNER));
if (mDeviceOwner != null) {
mDeviceOwner.clearDeviceOwner();
mDeviceOwner.writeOwnerFile();
@@ -3481,7 +3482,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
synchronized (this) {
long ident = Binder.clearCallingIdentity();
try {
- mUserManager.setUserRestrictions(new Bundle(), callingUser);
+ clearUserRestrictions(callingUser);
if (mDeviceOwner != null) {
mDeviceOwner.removeProfileOwner(callingUser.getIdentifier());
mDeviceOwner.writeOwnerFile();
@@ -3492,6 +3493,19 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
}
+ private void clearUserRestrictions(UserHandle userHandle) {
+ AudioManager audioManager =
+ (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
+ Bundle userRestrictions = mUserManager.getUserRestrictions();
+ mUserManager.setUserRestrictions(new Bundle(), userHandle);
+ if (userRestrictions.getBoolean(UserManager.DISALLOW_ADJUST_VOLUME)) {
+ audioManager.setMasterMute(false);
+ }
+ if (userRestrictions.getBoolean(UserManager.DISALLOW_UNMUTE_MICROPHONE)) {
+ audioManager.setMicrophoneMute(false);
+ }
+ }
+
@Override
public boolean hasUserSetupCompleted() {
if (!mHasFeature) {
@@ -4034,7 +4048,57 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
long id = Binder.clearCallingIdentity();
try {
+ AudioManager audioManager =
+ (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
+ boolean alreadyRestricted = mUserManager.hasUserRestriction(key);
+
+ if (enabled && !alreadyRestricted) {
+ if (UserManager.DISALLOW_CONFIG_WIFI.equals(key)) {
+ Settings.Secure.putIntForUser(mContext.getContentResolver(),
+ Settings.Secure.WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON, 0,
+ userHandle.getIdentifier());
+ } else if (UserManager.DISALLOW_USB_FILE_TRANSFER.equals(key)) {
+ UsbManager manager =
+ (UsbManager) mContext.getSystemService(Context.USB_SERVICE);
+ manager.setCurrentFunction("none", false);
+ } else if (UserManager.DISALLOW_SHARE_LOCATION.equals(key)) {
+ Settings.Secure.putIntForUser(mContext.getContentResolver(),
+ Settings.Secure.LOCATION_MODE, Settings.Secure.LOCATION_MODE_OFF,
+ userHandle.getIdentifier());
+ Settings.Secure.putStringForUser(mContext.getContentResolver(),
+ Settings.Secure.LOCATION_PROVIDERS_ALLOWED, "",
+ userHandle.getIdentifier());
+ } else if (UserManager.DISALLOW_DEBUGGING_FEATURES.equals(key)) {
+ Settings.Global.putStringForUser(mContext.getContentResolver(),
+ Settings.Global.ADB_ENABLED, "0", userHandle.getIdentifier());
+ } else if (UserManager.ENSURE_VERIFY_APPS.equals(key)) {
+ Settings.Global.putStringForUser(mContext.getContentResolver(),
+ Settings.Global.PACKAGE_VERIFIER_ENABLE, "1",
+ userHandle.getIdentifier());
+ Settings.Global.putStringForUser(mContext.getContentResolver(),
+ Settings.Global.PACKAGE_VERIFIER_INCLUDE_ADB, "1",
+ userHandle.getIdentifier());
+ } else if (UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES.equals(key)) {
+ Settings.Secure.putIntForUser(mContext.getContentResolver(),
+ Settings.Secure.INSTALL_NON_MARKET_APPS, 0,
+ userHandle.getIdentifier());
+ } else if (UserManager.DISALLOW_UNMUTE_MICROPHONE.equals(key)) {
+ audioManager.setMicrophoneMute(true);
+ } else if (UserManager.DISALLOW_ADJUST_VOLUME.equals(key)) {
+ audioManager.setMasterMute(true);
+ }
+ }
+
mUserManager.setUserRestriction(key, enabled, userHandle);
+
+ if (!enabled && alreadyRestricted) {
+ if (UserManager.DISALLOW_UNMUTE_MICROPHONE.equals(key)) {
+ audioManager.setMicrophoneMute(false);
+ } else if (UserManager.DISALLOW_ADJUST_VOLUME.equals(key)) {
+ audioManager.setMasterMute(false);
+ }
+ }
+
} finally {
restoreCallingIdentity(id);
}
diff --git a/services/print/Android.mk b/services/print/Android.mk
index 33604b711159..00eb2e4f9f98 100644
--- a/services/print/Android.mk
+++ b/services/print/Android.mk
@@ -7,4 +7,6 @@ LOCAL_MODULE := services.print
LOCAL_SRC_FILES += \
$(call all-java-files-under,java)
+LOCAL_JAVA_LIBRARIES := services.core
+
include $(BUILD_STATIC_JAVA_LIBRARY)
diff --git a/services/restrictions/Android.mk b/services/restrictions/Android.mk
index fcf8626af5fd..57d1c465f825 100644
--- a/services/restrictions/Android.mk
+++ b/services/restrictions/Android.mk
@@ -7,4 +7,6 @@ LOCAL_MODULE := services.restrictions
LOCAL_SRC_FILES += \
$(call all-java-files-under,java)
+LOCAL_JAVA_LIBRARIES := services.core
+
include $(BUILD_STATIC_JAVA_LIBRARY)
diff --git a/services/usage/Android.mk b/services/usage/Android.mk
index d4b7fa8a486c..f1cbe98586bb 100644
--- a/services/usage/Android.mk
+++ b/services/usage/Android.mk
@@ -7,4 +7,6 @@ LOCAL_MODULE := services.usage
LOCAL_SRC_FILES += \
$(call all-java-files-under,java)
+LOCAL_JAVA_LIBRARIES := services.core
+
include $(BUILD_STATIC_JAVA_LIBRARY)
diff --git a/telecomm/java/android/telecomm/Call.java b/telecomm/java/android/telecomm/Call.java
index f988ac8a759b..7223574b2889 100644
--- a/telecomm/java/android/telecomm/Call.java
+++ b/telecomm/java/android/telecomm/Call.java
@@ -27,6 +27,7 @@ import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Objects;
+import java.util.concurrent.CopyOnWriteArrayList;
/**
* Represents an ongoing phone call that the in-call app should present to the user.
@@ -364,7 +365,7 @@ public final class Call {
private final InCallAdapter mInCallAdapter;
private final List<Call> mChildren = new ArrayList<>();
private final List<Call> mUnmodifiableChildren = Collections.unmodifiableList(mChildren);
- private final List<Listener> mListeners = new ArrayList<>();
+ private final List<Listener> mListeners = new CopyOnWriteArrayList<>();
private final List<Call> mConferenceableCalls = new ArrayList<>();
private final List<Call> mUnmodifiableConferenceableCalls =
Collections.unmodifiableList(mConferenceableCalls);
@@ -589,7 +590,9 @@ public final class Call {
* @param listener A {@code Listener}.
*/
public void removeListener(Listener listener) {
- mListeners.remove(listener);
+ if (listener != null) {
+ mListeners.remove(listener);
+ }
}
/** {@hide} */
@@ -709,72 +712,62 @@ public final class Call {
}
private void fireStateChanged(int newState) {
- Listener[] listeners = mListeners.toArray(new Listener[mListeners.size()]);
- for (int i = 0; i < listeners.length; i++) {
- listeners[i].onStateChanged(this, newState);
+ for (Listener listener : mListeners) {
+ listener.onStateChanged(this, newState);
}
}
private void fireParentChanged(Call newParent) {
- Listener[] listeners = mListeners.toArray(new Listener[mListeners.size()]);
- for (int i = 0; i < listeners.length; i++) {
- listeners[i].onParentChanged(this, newParent);
+ for (Listener listener : mListeners) {
+ listener.onParentChanged(this, newParent);
}
}
private void fireChildrenChanged(List<Call> children) {
- Listener[] listeners = mListeners.toArray(new Listener[mListeners.size()]);
- for (int i = 0; i < listeners.length; i++) {
- listeners[i].onChildrenChanged(this, children);
+ for (Listener listener : mListeners) {
+ listener.onChildrenChanged(this, children);
}
}
private void fireDetailsChanged(Details details) {
- Listener[] listeners = mListeners.toArray(new Listener[mListeners.size()]);
- for (int i = 0; i < listeners.length; i++) {
- listeners[i].onDetailsChanged(this, details);
+ for (Listener listener : mListeners) {
+ listener.onDetailsChanged(this, details);
}
}
private void fireCannedTextResponsesLoaded(List<String> cannedTextResponses) {
- Listener[] listeners = mListeners.toArray(new Listener[mListeners.size()]);
- for (int i = 0; i < listeners.length; i++) {
- listeners[i].onCannedTextResponsesLoaded(this, cannedTextResponses);
+ for (Listener listener : mListeners) {
+ listener.onCannedTextResponsesLoaded(this, cannedTextResponses);
}
}
private void fireVideoCallChanged(InCallService.VideoCall videoCall) {
- Listener[] listeners = mListeners.toArray(new Listener[mListeners.size()]);
- for (int i = 0; i < listeners.length; i++) {
- listeners[i].onVideoCallChanged(this, videoCall);
+ for (Listener listener : mListeners) {
+ listener.onVideoCallChanged(this, videoCall);
}
}
private void firePostDialWait(String remainingPostDialSequence) {
- Listener[] listeners = mListeners.toArray(new Listener[mListeners.size()]);
- for (int i = 0; i < listeners.length; i++) {
- listeners[i].onPostDialWait(this, remainingPostDialSequence);
+ for (Listener listener : mListeners) {
+ listener.onPostDialWait(this, remainingPostDialSequence);
}
}
private void fireStartActivity(PendingIntent intent) {
- Listener[] listeners = mListeners.toArray(new Listener[mListeners.size()]);
- for (int i = 0; i < listeners.length; i++) {
- listeners[i].onStartActivity(this, intent);
+ for (Listener listener : mListeners) {
+ listener.onStartActivity(this, intent);
}
}
private void fireCallDestroyed() {
- Listener[] listeners = mListeners.toArray(new Listener[mListeners.size()]);
- for (int i = 0; i < listeners.length; i++) {
- listeners[i].onCallDestroyed(this);
+ for (Listener listener : mListeners) {
+ listener.onCallDestroyed(this);
}
}
private void fireConferenceableCallsChanged() {
- Listener[] listeners = mListeners.toArray(new Listener[mListeners.size()]);
- for (int i = 0; i < listeners.length; i++) {
- listeners[i].onConferenceableCallsChanged(this, mUnmodifiableConferenceableCalls);
+ for (Listener listener : mListeners) {
+ listener.onConferenceableCallsChanged(this, mUnmodifiableConferenceableCalls);
}
}
diff --git a/telecomm/java/android/telecomm/Connection.java b/telecomm/java/android/telecomm/Connection.java
index 3ecb4cb70b8b..78c34a117500 100644
--- a/telecomm/java/android/telecomm/Connection.java
+++ b/telecomm/java/android/telecomm/Connection.java
@@ -32,7 +32,7 @@ import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Set;
-import java.util.concurrent.CopyOnWriteArraySet;
+import java.util.concurrent.ConcurrentHashMap;
/**
* Represents a connection to a remote endpoint that carries voice traffic.
@@ -448,7 +448,13 @@ public abstract class Connection {
}
};
- private final Set<Listener> mListeners = new CopyOnWriteArraySet<>();
+ /**
+ * ConcurrentHashMap constructor params: 8 is initial table size, 0.9f is
+ * load factor before resizing, 1 means we only expect a single thread to
+ * access the map so make only a single shard
+ */
+ private final Set<Listener> mListeners = Collections.newSetFromMap(
+ new ConcurrentHashMap<Listener, Boolean>(8, 0.9f, 1));
private final List<Connection> mChildConnections = new ArrayList<>();
private final List<Connection> mUnmodifiableChildConnections =
Collections.unmodifiableList(mChildConnections);
@@ -587,7 +593,9 @@ public abstract class Connection {
* @hide
*/
public final Connection removeConnectionListener(Listener l) {
- mListeners.remove(l);
+ if (l != null) {
+ mListeners.remove(l);
+ }
return this;
}
@@ -874,13 +882,8 @@ public abstract class Connection {
* Tears down the Connection object.
*/
public final void destroy() {
- // It is possible that onDestroy() will trigger the listener to remove itself which will
- // result in a concurrent modification exception. To counteract this we make a copy of the
- // listeners and iterate on that.
- for (Listener l : new ArrayList<>(mListeners)) {
- if (mListeners.contains(l)) {
- l.onDestroyed(this);
- }
+ for (Listener l : mListeners) {
+ l.onDestroyed(this);
}
}
diff --git a/telecomm/java/android/telecomm/ConnectionService.java b/telecomm/java/android/telecomm/ConnectionService.java
index 44aacfc3b9b4..d2d4828054a6 100644
--- a/telecomm/java/android/telecomm/ConnectionService.java
+++ b/telecomm/java/android/telecomm/ConnectionService.java
@@ -45,7 +45,6 @@ import java.util.Map;
* Android device.
*/
public abstract class ConnectionService extends Service {
-
/**
* The {@link Intent} that must be declared as handled by the service.
*/
@@ -481,15 +480,12 @@ public abstract class ConnectionService extends Service {
case Connection.STATE_INITIALIZING:
Log.d(this, "State changed to STATE_INITIALIZING; ignoring");
return; // Don't want to stop listening on this state transition.
- default:
- Log.d(this, "Connection created in state %s",
- Connection.stateToString(state));
- connectionCreated(callId, request, createdConnection);
- break;
}
c.removeConnectionListener(this);
}
});
+ Log.d(this, "Connection created in state INITIALIZING");
+ connectionCreated(callId, request, createdConnection);
} else if (createdConnection.getState() == Connection.STATE_CANCELED) {
// Tell telecomm not to attempt any more services.
mAdapter.handleCreateConnectionCancelled(callId, request);
@@ -620,7 +616,8 @@ public abstract class ConnectionService extends Service {
public void onError(String request, int code, String reason) {
// no-op
}
- });
+ }
+ );
}
private void splitFromConference(String callId) {
@@ -832,5 +829,4 @@ public abstract class ConnectionService extends Service {
Log.w(this, "%s - Cannot find Connection %s", action, callId);
return Connection.getNullConnection();
}
-
}
diff --git a/telecomm/java/android/telecomm/ConnectionServiceAdapter.java b/telecomm/java/android/telecomm/ConnectionServiceAdapter.java
index bfcb5c3218be..4144b81e5c84 100644
--- a/telecomm/java/android/telecomm/ConnectionServiceAdapter.java
+++ b/telecomm/java/android/telecomm/ConnectionServiceAdapter.java
@@ -36,8 +36,13 @@ import java.util.concurrent.ConcurrentHashMap;
* @hide
*/
final class ConnectionServiceAdapter implements DeathRecipient {
+ /**
+ * ConcurrentHashMap constructor params: 8 is initial table size, 0.9f is
+ * load factor before resizing, 1 means we only expect a single thread to
+ * access the map so make only a single shard
+ */
private final Set<IConnectionServiceAdapter> mAdapters = Collections.newSetFromMap(
- new ConcurrentHashMap<IConnectionServiceAdapter, Boolean>(2));
+ new ConcurrentHashMap<IConnectionServiceAdapter, Boolean>(8, 0.9f, 1));
ConnectionServiceAdapter() {
}
@@ -53,7 +58,7 @@ final class ConnectionServiceAdapter implements DeathRecipient {
}
void removeAdapter(IConnectionServiceAdapter adapter) {
- if (mAdapters.remove(adapter)) {
+ if (adapter != null && mAdapters.remove(adapter)) {
adapter.asBinder().unlinkToDeath(this, 0);
}
}
diff --git a/telecomm/java/android/telecomm/Phone.java b/telecomm/java/android/telecomm/Phone.java
index 79e777a4eb4e..03a86763ce87 100644
--- a/telecomm/java/android/telecomm/Phone.java
+++ b/telecomm/java/android/telecomm/Phone.java
@@ -24,6 +24,7 @@ import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Objects;
+import java.util.concurrent.CopyOnWriteArrayList;
/**
* A unified virtual device providing a means of voice (and other) communication on a device.
@@ -89,7 +90,7 @@ public final class Phone {
private AudioState mAudioState;
- private final List<Listener> mListeners = new ArrayList<>();
+ private final List<Listener> mListeners = new CopyOnWriteArrayList<>();
/** {@hide} */
Phone(InCallAdapter adapter) {
@@ -171,7 +172,9 @@ public final class Phone {
* @param listener A {@code Listener} object.
*/
public final void removeListener(Listener listener) {
- mListeners.remove(listener);
+ if (listener != null) {
+ mListeners.remove(listener);
+ }
}
/**
@@ -236,30 +239,26 @@ public final class Phone {
}
private void fireCallAdded(Call call) {
- Listener[] listeners = mListeners.toArray(new Listener[mListeners.size()]);
- for (int i = 0; i < listeners.length; i++) {
- listeners[i].onCallAdded(this, call);
+ for (Listener listener : mListeners) {
+ listener.onCallAdded(this, call);
}
}
private void fireCallRemoved(Call call) {
- Listener[] listeners = mListeners.toArray(new Listener[mListeners.size()]);
- for (int i = 0; i < listeners.length; i++) {
- listeners[i].onCallRemoved(this, call);
+ for (Listener listener : mListeners) {
+ listener.onCallRemoved(this, call);
}
}
private void fireAudioStateChanged(AudioState audioState) {
- Listener[] listeners = mListeners.toArray(new Listener[mListeners.size()]);
- for (int i = 0; i < listeners.length; i++) {
- listeners[i].onAudioStateChanged(this, audioState);
+ for (Listener listener : mListeners) {
+ listener.onAudioStateChanged(this, audioState);
}
}
private void fireBringToForeground(boolean showDialpad) {
- Listener[] listeners = mListeners.toArray(new Listener[mListeners.size()]);
- for (int i = 0; i < listeners.length; i++) {
- listeners[i].onBringToForeground(this, showDialpad);
+ for (Listener listener : mListeners) {
+ listener.onBringToForeground(this, showDialpad);
}
}
diff --git a/telecomm/java/android/telecomm/RemoteConnection.java b/telecomm/java/android/telecomm/RemoteConnection.java
index d3972d31fa39..f1cee10e4ea1 100644
--- a/telecomm/java/android/telecomm/RemoteConnection.java
+++ b/telecomm/java/android/telecomm/RemoteConnection.java
@@ -184,8 +184,13 @@ public final class RemoteConnection {
private IConnectionService mConnectionService;
private final String mConnectionId;
+ /**
+ * ConcurrentHashMap constructor params: 8 is initial table size, 0.9f is
+ * load factor before resizing, 1 means we only expect a single thread to
+ * access the map so make only a single shard
+ */
private final Set<Listener> mListeners = Collections.newSetFromMap(
- new ConcurrentHashMap<Listener, Boolean>(2));
+ new ConcurrentHashMap<Listener, Boolean>(8, 0.9f, 1));
private final Set<RemoteConnection> mConferenceableConnections = new HashSet<>();
private int mState = Connection.STATE_NEW;
@@ -248,7 +253,9 @@ public final class RemoteConnection {
* @param listener A {@code Listener}.
*/
public void removeListener(Listener listener) {
- mListeners.remove(listener);
+ if (listener != null) {
+ mListeners.remove(listener);
+ }
}
/**
@@ -588,11 +595,10 @@ public final class RemoteConnection {
setDisconnected(DisconnectCause.ERROR_UNSPECIFIED, "Connection destroyed.");
}
- Set<Listener> listeners = new HashSet<Listener>(mListeners);
- mListeners.clear();
- for (Listener l : listeners) {
+ for (Listener l : mListeners) {
l.onDestroyed(this);
}
+ mListeners.clear();
mConnected = false;
}
diff --git a/telephony/java/com/android/internal/telephony/PhoneConstants.java b/telephony/java/com/android/internal/telephony/PhoneConstants.java
index cf87bec09cb9..b4b1ea5735dc 100644
--- a/telephony/java/com/android/internal/telephony/PhoneConstants.java
+++ b/telephony/java/com/android/internal/telephony/PhoneConstants.java
@@ -187,4 +187,7 @@ public class PhoneConstants {
REASON_RADIO_UNAVAILABLE,
REASON_SIM_REFRESH_RESET
};
+
+ // Initial MTU value.
+ public static final int UNSET_MTU = 0;
}
diff --git a/tests/OneMedia/AndroidManifest.xml b/tests/OneMedia/AndroidManifest.xml
index 9d78ca5af00d..95072a44143b 100644
--- a/tests/OneMedia/AndroidManifest.xml
+++ b/tests/OneMedia/AndroidManifest.xml
@@ -23,7 +23,7 @@
</activity>
<service
android:name="com.android.onemedia.OnePlayerService"
- android:exported="false"
+ android:exported="true"
android:process="com.android.onemedia.service" />
<service
android:name=".provider.OneMediaRouteProvider"
diff --git a/tests/OneMedia/res/drawable/ic_fast_forward.xml b/tests/OneMedia/res/drawable/ic_fast_forward.xml
new file mode 100644
index 000000000000..8daf07df5d36
--- /dev/null
+++ b/tests/OneMedia/res/drawable/ic_fast_forward.xml
@@ -0,0 +1,25 @@
+<!--
+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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="36dp"
+ android:height="36dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24" >
+
+ <path
+ android:fillColor="#FFFFFFFF"
+ android:pathData="M4.0,18.0l8.5,-6.0L4.0,6.0L4.0,18.0zM13.0,6.0l0.0,12.0l8.5,-6.0L13.0,6.0z"/>
+</vector>
diff --git a/tests/OneMedia/res/drawable/ic_fast_rewind.xml b/tests/OneMedia/res/drawable/ic_fast_rewind.xml
new file mode 100644
index 000000000000..4ed1f5443ff7
--- /dev/null
+++ b/tests/OneMedia/res/drawable/ic_fast_rewind.xml
@@ -0,0 +1,24 @@
+<!--
+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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="36dp"
+ android:height="36dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24" >
+ <path
+ android:fillColor="#FFFFFFFF"
+ android:pathData="M11.0,18.0L11.0,6.0l-8.5,6.0L11.0,18.0zM11.5,12.0l8.5,6.0L20.0,6.0L11.5,12.0z"/>
+</vector>
diff --git a/tests/OneMedia/res/drawable/ic_pause.xml b/tests/OneMedia/res/drawable/ic_pause.xml
new file mode 100644
index 000000000000..15d07564cece
--- /dev/null
+++ b/tests/OneMedia/res/drawable/ic_pause.xml
@@ -0,0 +1,25 @@
+<!--
+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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="36dp"
+ android:height="36dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24" >
+
+ <path
+ android:fillColor="#FFFFFFFF"
+ android:pathData="M6.0,19.0l4.0,0.0L10.0,5.0L6.0,5.0L6.0,19.0zM14.0,5.0l0.0,14.0l4.0,0.0L18.0,5.0L14.0,5.0z"/>
+</vector>
diff --git a/tests/OneMedia/res/drawable/ic_play_arrow.xml b/tests/OneMedia/res/drawable/ic_play_arrow.xml
new file mode 100644
index 000000000000..49d766d984eb
--- /dev/null
+++ b/tests/OneMedia/res/drawable/ic_play_arrow.xml
@@ -0,0 +1,25 @@
+<!--
+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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="36dp"
+ android:height="36dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24" >
+
+ <path
+ android:fillColor="#FFFFFFFF"
+ android:pathData="M8.0,5.0l0.0,14.0 11.0,-7.0z"/>
+</vector>
diff --git a/tests/OneMedia/res/drawable/ic_skip_next.xml b/tests/OneMedia/res/drawable/ic_skip_next.xml
new file mode 100644
index 000000000000..8a6ceca3a066
--- /dev/null
+++ b/tests/OneMedia/res/drawable/ic_skip_next.xml
@@ -0,0 +1,25 @@
+<!--
+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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="36dp"
+ android:height="36dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24" >
+
+ <path
+ android:fillColor="#FFFFFFFF"
+ android:pathData="M6.0,18.0l8.5,-6.0L6.0,6.0L6.0,18.0zM16.0,6.0l0.0,12.0l2.0,0.0L18.0,6.0L16.0,6.0z"/>
+</vector>
diff --git a/tests/OneMedia/res/drawable/ic_skip_previous.xml b/tests/OneMedia/res/drawable/ic_skip_previous.xml
new file mode 100644
index 000000000000..c5d07db83dfb
--- /dev/null
+++ b/tests/OneMedia/res/drawable/ic_skip_previous.xml
@@ -0,0 +1,28 @@
+<!--
+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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="36dp"
+ android:height="36dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24" >
+
+ <path
+ android:fillColor="#FFFFFFFF"
+ android:pathData="M6.0,6.0l2.0,0.0l0.0,12.0l-2.0,0.0z"/>
+ <path
+ android:fillColor="#FFFFFFFF"
+ android:pathData="M9.5,12.0l8.5,6.0 0.0,-12.0z"/>
+</vector>
diff --git a/tests/OneMedia/res/drawable/ic_stop.xml b/tests/OneMedia/res/drawable/ic_stop.xml
new file mode 100644
index 000000000000..6043fdb6d04d
--- /dev/null
+++ b/tests/OneMedia/res/drawable/ic_stop.xml
@@ -0,0 +1,25 @@
+<!--
+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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="36dp"
+ android:height="36dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24" >
+
+ <path
+ android:fillColor="#FFFFFFFF"
+ android:pathData="M6.0,6.0l12.0,0.0l0.0,12.0l-12.0,0.0z"/>
+</vector>
diff --git a/tests/OneMedia/res/layout/activity_one_player.xml b/tests/OneMedia/res/layout/activity_one_player.xml
index 516562faf3bc..ce2d64144715 100644
--- a/tests/OneMedia/res/layout/activity_one_player.xml
+++ b/tests/OneMedia/res/layout/activity_one_player.xml
@@ -33,6 +33,19 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/has_video" />
+ <ImageView
+ android:id="@+id/art"
+ android:layout_width="match_parent"
+ android:layout_height="96dp"
+ android:scaleType="centerCrop"
+ android:visibility="gone"
+ />
+ <Button
+ android:id="@+id/art_picker"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/art_picker"
+ />
<LinearLayout
android:id="@+id/controls"
android:layout_width="match_parent"
diff --git a/tests/OneMedia/res/values/strings.xml b/tests/OneMedia/res/values/strings.xml
index 3735c8d36252..86657fd99951 100644
--- a/tests/OneMedia/res/values/strings.xml
+++ b/tests/OneMedia/res/values/strings.xml
@@ -12,5 +12,5 @@
<string name="media_next_hint">Next content</string>
<string name="has_video">Is video</string>
<string name="has_duration">Has duration</string>
-
+ <string name="art_picker">Choose artwork</string>
</resources>
diff --git a/tests/OneMedia/src/com/android/onemedia/IPlayerService.aidl b/tests/OneMedia/src/com/android/onemedia/IPlayerService.aidl
index d4df4c5b1801..f53eac005818 100644
--- a/tests/OneMedia/src/com/android/onemedia/IPlayerService.aidl
+++ b/tests/OneMedia/src/com/android/onemedia/IPlayerService.aidl
@@ -15,6 +15,7 @@
package com.android.onemedia;
+import android.graphics.Bitmap;
import android.media.session.MediaSession;
import android.os.Bundle;
@@ -26,4 +27,5 @@ interface IPlayerService {
void registerCallback(in IPlayerCallback cb);
void unregisterCallback(in IPlayerCallback cb);
void sendRequest(String action, in Bundle params, in IRequestCallback cb);
+ void setIcon(in Bitmap icon);
}
diff --git a/tests/OneMedia/src/com/android/onemedia/NotificationHelper.java b/tests/OneMedia/src/com/android/onemedia/NotificationHelper.java
new file mode 100644
index 000000000000..a5bcda516b01
--- /dev/null
+++ b/tests/OneMedia/src/com/android/onemedia/NotificationHelper.java
@@ -0,0 +1,234 @@
+package com.android.onemedia;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.app.Notification;
+import android.app.NotificationManager;
+import android.app.PendingIntent;
+import android.app.Service;
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.graphics.Bitmap;
+import android.media.MediaMetadata;
+import android.media.session.MediaController;
+import android.media.session.MediaSession;
+import android.media.session.PlaybackState;
+import android.text.format.DateUtils;
+import android.util.Log;
+import android.util.SparseArray;
+
+import com.android.onemedia.playback.RequestUtils;
+
+/**
+ * Keeps track of a notification and updates it automatically for a given
+ * MediaSession.
+ */
+public class NotificationHelper extends BroadcastReceiver {
+ private static final String TAG = "NotificationHelper";
+
+ private static final int NOTIFICATION_ID = 433; // John Cage, 1952
+
+ private final Service mService;
+ private final MediaSession mSession;
+ private final MediaController mController;
+ private final MediaController.TransportControls mTransportControls;
+ private final SparseArray<PendingIntent> mIntents = new SparseArray<PendingIntent>();
+
+ private PlaybackState mPlaybackState;
+ private MediaMetadata mMetadata;
+
+ private boolean mStarted = false;
+
+ public NotificationHelper(Service service, MediaSession session) {
+ mService = service;
+ mSession = session;
+ mController = session.getController();
+ mTransportControls = mController.getTransportControls();
+ String pkg = mService.getPackageName();
+
+ mIntents.put(R.drawable.ic_pause, PendingIntent.getBroadcast(mService, 100, new Intent(
+ com.android.onemedia.playback.RequestUtils.ACTION_PAUSE).setPackage(pkg),
+ PendingIntent.FLAG_CANCEL_CURRENT));
+ mIntents.put(R.drawable.ic_play_arrow, PendingIntent.getBroadcast(mService, 100,
+ new Intent(com.android.onemedia.playback.RequestUtils.ACTION_PLAY).setPackage(pkg),
+ PendingIntent.FLAG_CANCEL_CURRENT));
+ mIntents.put(R.drawable.ic_skip_previous, PendingIntent.getBroadcast(mService, 100,
+ new Intent(com.android.onemedia.playback.RequestUtils.ACTION_PREV).setPackage(pkg),
+ PendingIntent.FLAG_CANCEL_CURRENT));
+ mIntents.put(R.drawable.ic_skip_next, PendingIntent.getBroadcast(mService, 100,
+ new Intent(com.android.onemedia.playback.RequestUtils.ACTION_NEXT).setPackage(pkg),
+ PendingIntent.FLAG_CANCEL_CURRENT));
+ mIntents.put(R.drawable.ic_fast_rewind, PendingIntent.getBroadcast(mService, 100,
+ new Intent(com.android.onemedia.playback.RequestUtils.ACTION_REW).setPackage(pkg),
+ PendingIntent.FLAG_CANCEL_CURRENT));
+ mIntents.put(R.drawable.ic_fast_forward, PendingIntent.getBroadcast(mService, 100,
+ new Intent(com.android.onemedia.playback.RequestUtils.ACTION_FFWD).setPackage(pkg),
+ PendingIntent.FLAG_CANCEL_CURRENT));
+ }
+
+ /**
+ * Posts the notification and starts tracking the session to keep it
+ * updated. The notification will automatically be removed if the session is
+ * destroyed before {@link #onStop} is called.
+ */
+ public void onStart() {
+ mController.addCallback(mCb);
+ IntentFilter filter = new IntentFilter();
+ filter.addAction(RequestUtils.ACTION_FFWD);
+ filter.addAction(RequestUtils.ACTION_NEXT);
+ filter.addAction(RequestUtils.ACTION_PAUSE);
+ filter.addAction(RequestUtils.ACTION_PLAY);
+ filter.addAction(RequestUtils.ACTION_PREV);
+ filter.addAction(RequestUtils.ACTION_REW);
+ mService.registerReceiver(this, filter);
+
+ mMetadata = mController.getMetadata();
+ mPlaybackState = mController.getPlaybackState();
+
+ mStarted = true;
+ // The notification must be updated after setting started to true
+ updateNotification();
+ }
+
+ /**
+ * Removes the notification and stops tracking the session. If the session
+ * was destroyed this has no effect.
+ */
+ public void onStop() {
+ mStarted = false;
+ mController.removeCallback(mCb);
+ mService.unregisterReceiver(this);
+ updateNotification();
+ }
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ final String action = intent.getAction();
+ Log.d(TAG, "Received intent with action " + action);
+ if (RequestUtils.ACTION_PAUSE.equals(action)) {
+ mTransportControls.pause();
+ } else if (RequestUtils.ACTION_PLAY.equals(action)) {
+ mTransportControls.play();
+ } else if (RequestUtils.ACTION_NEXT.equals(action)) {
+ mTransportControls.skipToNext();
+ } else if (RequestUtils.ACTION_PREV.equals(action)) {
+ mTransportControls.skipToPrevious();
+ } else if (RequestUtils.ACTION_REW.equals(action)) {
+ mTransportControls.rewind();
+ } else if (RequestUtils.ACTION_FFWD.equals(action)) {
+ mTransportControls.fastForward();
+ }
+
+ }
+
+ private final MediaController.Callback mCb = new MediaController.Callback() {
+ @Override
+ public void onPlaybackStateChanged(PlaybackState state) {
+ mPlaybackState = state;
+ Log.d(TAG, "Received new playback state" + state);
+ updateNotification();
+ }
+
+ @Override
+ public void onMetadataChanged(MediaMetadata metadata) {
+ mMetadata = metadata;
+ Log.d(TAG, "Received new metadata " + metadata);
+ updateNotification();
+ }
+ };
+
+ NotificationManager mNoMan = null;
+
+ private void updateNotification() {
+ if (mNoMan == null) {
+ mNoMan = (NotificationManager) mService.getSystemService(Context.NOTIFICATION_SERVICE);
+ }
+ if (mPlaybackState == null) {
+ mNoMan.cancel(NOTIFICATION_ID);
+ return;
+ }
+ if (!mStarted) {
+ mNoMan.cancel(NOTIFICATION_ID);
+ return;
+ }
+
+ String status;
+ final int state = mPlaybackState.getState();
+ switch (state) {
+ case PlaybackState.STATE_PLAYING:
+ status = "PLAYING: ";
+ break;
+ case PlaybackState.STATE_PAUSED:
+ status = "PAUSED: ";
+ break;
+ case PlaybackState.STATE_STOPPED:
+ status = "STOPPED: ";
+ break;
+ case PlaybackState.STATE_ERROR:
+ status = "ERROR: ";
+ break;
+ case PlaybackState.STATE_BUFFERING:
+ status = "BUFFERING: ";
+ break;
+ case PlaybackState.STATE_NONE:
+ default:
+ status = "";
+ break;
+ }
+ CharSequence title, text;
+ Bitmap art;
+ if (mMetadata == null) {
+ title = status;
+ text = "Empty metadata!";
+ art = null;
+ } else {
+ MediaMetadata.Description description = mMetadata.getDescription();
+ title = description.getTitle();
+ text = description.getSubtitle();
+ art = description.getIcon();
+ }
+
+ String playPauseLabel = "";
+ int playPauseIcon;
+ if (state == PlaybackState.STATE_PLAYING) {
+ playPauseLabel = "Pause";
+ playPauseIcon = R.drawable.ic_pause;
+ } else {
+ playPauseLabel = "Play";
+ playPauseIcon = R.drawable.ic_play_arrow;
+ }
+
+ final long pos = mPlaybackState.getPosition();
+ final long end = mMetadata == null ? 0 : mMetadata
+ .getLong(MediaMetadata.METADATA_KEY_DURATION);
+ Notification notification = new Notification.Builder(mService)
+ .setSmallIcon(android.R.drawable.stat_notify_chat)
+ .setContentTitle(title)
+ .setContentText(text)
+ .setShowWhen(false)
+ .setContentInfo(DateUtils.formatElapsedTime(pos))
+ .setProgress((int) end, (int) pos, false)
+ .setLargeIcon(art)
+ .addAction(R.drawable.ic_skip_previous, "Previous",
+ mIntents.get(R.drawable.ic_skip_previous))
+ .addAction(R.drawable.ic_fast_rewind, "Rewind",
+ mIntents.get(R.drawable.ic_fast_rewind))
+ .addAction(playPauseIcon, playPauseLabel,
+ mIntents.get(playPauseIcon))
+ .addAction(R.drawable.ic_fast_forward, "Fast Forward",
+ mIntents.get(R.drawable.ic_fast_forward))
+ .addAction(R.drawable.ic_skip_next, "Next",
+ mIntents.get(R.drawable.ic_skip_next))
+ .setStyle(new Notification.MediaStyle()
+ .setShowActionsInCompactView(2)
+ .setMediaSession(mSession.getSessionToken()))
+ .setColor(0xFFDB4437)
+ .build();
+
+ mService.startForeground(NOTIFICATION_ID, notification);
+ }
+
+}
diff --git a/tests/OneMedia/src/com/android/onemedia/OnePlayerActivity.java b/tests/OneMedia/src/com/android/onemedia/OnePlayerActivity.java
index 894377bf28fd..2ff3e2026cc0 100644
--- a/tests/OneMedia/src/com/android/onemedia/OnePlayerActivity.java
+++ b/tests/OneMedia/src/com/android/onemedia/OnePlayerActivity.java
@@ -17,20 +17,35 @@ package com.android.onemedia;
import android.app.Activity;
+import android.app.Notification;
+import android.app.NotificationManager;
+import android.app.PendingIntent;
+import android.content.ComponentName;
+import android.content.Intent;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
import android.media.MediaMetadata;
import android.media.session.PlaybackState;
+import android.net.Uri;
import android.os.Bundle;
+import android.provider.MediaStore;
+import android.text.format.DateUtils;
import android.util.Log;
import android.view.Menu;
import android.view.View;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.EditText;
+import android.widget.ImageView;
import android.widget.TextView;
+import java.io.IOException;
+
public class OnePlayerActivity extends Activity {
private static final String TAG = "OnePlayerActivity";
+ private static final int READ_REQUEST_CODE = 42;
+
protected PlayerController mPlayer;
private Button mStartButton;
@@ -41,8 +56,10 @@ public class OnePlayerActivity extends Activity {
private EditText mContentText;
private EditText mNextContentText;
private CheckBox mHasVideo;
+ private ImageView mArtView;
- private int mPlaybackState;
+ private PlaybackState mPlaybackState;
+ private Bitmap mAlbumArtBitmap;
@Override
protected void onCreate(Bundle savedInstanceState) {
@@ -58,6 +75,10 @@ public class OnePlayerActivity extends Activity {
mContentText = (EditText) findViewById(R.id.content);
mNextContentText = (EditText) findViewById(R.id.next_content);
mHasVideo = (CheckBox) findViewById(R.id.has_video);
+ mArtView = (ImageView) findViewById(R.id.art);
+
+ final Button artPicker = (Button) findViewById(R.id.art_picker);
+ artPicker.setOnClickListener(mButtonListener);
mStartButton.setOnClickListener(mButtonListener);
mPlayButton.setOnClickListener(mButtonListener);
@@ -86,6 +107,31 @@ public class OnePlayerActivity extends Activity {
super.onPause();
}
+ @Override
+ public void onActivityResult(int requestCode, int resultCode,
+ Intent resultData) {
+ if (requestCode == READ_REQUEST_CODE && resultCode == Activity.RESULT_OK) {
+ Uri uri = null;
+ if (resultData != null) {
+ uri = resultData.getData();
+ Log.i(TAG, "Uri: " + uri.toString());
+ mAlbumArtBitmap = null;
+ try {
+ mAlbumArtBitmap = MediaStore.Images.Media.getBitmap(this.getContentResolver(), uri);
+ } catch (IOException e) {
+ Log.v(TAG, "Couldn't load album art", e);
+ }
+ mArtView.setImageBitmap(mAlbumArtBitmap);
+ if (mAlbumArtBitmap != null) {
+ mArtView.setVisibility(View.VISIBLE);
+ } else {
+ mArtView.setVisibility(View.GONE);
+ }
+ mPlayer.setArt(mAlbumArtBitmap);
+ }
+ }
+ }
+
private void setControlsEnabled(boolean enabled) {
mStartButton.setEnabled(enabled);
mPlayButton.setEnabled(enabled);
@@ -94,36 +140,46 @@ public class OnePlayerActivity extends Activity {
private View.OnClickListener mButtonListener = new View.OnClickListener() {
@Override
public void onClick(View v) {
+ final int state = mPlaybackState.getState();
switch (v.getId()) {
case R.id.play_button:
- Log.d(TAG, "Play button pressed, in state " + mPlaybackState);
- if (mPlaybackState == PlaybackState.STATE_PAUSED
- || mPlaybackState == PlaybackState.STATE_STOPPED) {
+ Log.d(TAG, "Play button pressed, in state " + state);
+ if (state == PlaybackState.STATE_PAUSED
+ || state == PlaybackState.STATE_STOPPED) {
mPlayer.play();
- } else if (mPlaybackState == PlaybackState.STATE_PLAYING) {
+ } else if (state == PlaybackState.STATE_PLAYING) {
mPlayer.pause();
}
break;
case R.id.start_button:
- Log.d(TAG, "Start button pressed, in state " + mPlaybackState);
+ Log.d(TAG, "Start button pressed, in state " + state);
mPlayer.setContent(mContentText.getText().toString());
break;
case R.id.route_button:
mPlayer.showRoutePicker();
break;
+ case R.id.art_picker:
+ Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
+ intent.addCategory(Intent.CATEGORY_OPENABLE);
+ intent.setType("image/*");
+
+ startActivityForResult(intent, READ_REQUEST_CODE);
+ break;
}
}
};
private PlayerController.Listener mListener = new PlayerController.Listener() {
+ public MediaMetadata mMetadata;
+
@Override
public void onPlaybackStateChange(PlaybackState state) {
- mPlaybackState = state.getState();
+ mPlaybackState = state;
boolean enablePlay = false;
boolean enableControls = true;
StringBuilder statusBuilder = new StringBuilder();
- switch (mPlaybackState) {
+ switch (mPlaybackState.getState()) {
case PlaybackState.STATE_PLAYING:
statusBuilder.append("playing");
mPlayButton.setText("Pause");
@@ -172,7 +228,7 @@ public class OnePlayerActivity extends Activity {
@Override
public void onMetadataChange(MediaMetadata metadata) {
- Log.d(TAG, "Metadata update! Title: " + metadata);
+ mMetadata = metadata;
}
};
}
diff --git a/tests/OneMedia/src/com/android/onemedia/PlayerController.java b/tests/OneMedia/src/com/android/onemedia/PlayerController.java
index c0799fcb3359..c8d72ca6087a 100644
--- a/tests/OneMedia/src/com/android/onemedia/PlayerController.java
+++ b/tests/OneMedia/src/com/android/onemedia/PlayerController.java
@@ -30,6 +30,7 @@ import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
+import android.graphics.Bitmap;
import android.util.Log;
import com.android.onemedia.playback.RequestUtils;
@@ -52,6 +53,7 @@ public class PlayerController {
private Handler mHandler = new Handler();
private boolean mResumed;
+ private Bitmap mArt;
public PlayerController(Activity context, Intent serviceIntent) {
mContext = context;
@@ -89,6 +91,16 @@ public class PlayerController {
unbindFromService();
}
+ public void setArt(Bitmap art) {
+ mArt = art;
+ if (mBinder != null) {
+ try {
+ mBinder.setIcon(art);
+ } catch (RemoteException e) {
+ }
+ }
+ }
+
public void play() {
if (mTransportControls != null) {
mTransportControls.play();
@@ -125,6 +137,16 @@ public class PlayerController {
// TODO
}
+ public MediaSession.Token getSessionToken() {
+ if (mBinder != null) {
+ try {
+ return mBinder.getSessionToken();
+ } catch (RemoteException e) {
+ }
+ }
+ return null;
+ }
+
private void unbindFromService() {
mContext.unbindService(mServiceConnection);
}
@@ -165,6 +187,9 @@ public class PlayerController {
mContext.setMediaController(mController);
mController.addCallback(mControllerCb, mHandler);
mTransportControls = mController.getTransportControls();
+ if (mArt != null) {
+ setArt(mArt);
+ }
Log.d(TAG, "Ready to use PlayerService");
if (mListener != null) {
@@ -194,6 +219,9 @@ public class PlayerController {
return;
}
Log.d(TAG, "Received metadata change, " + metadata.getDescription());
+ if (mListener != null) {
+ mListener.onMetadataChange(metadata);
+ }
}
}
diff --git a/tests/OneMedia/src/com/android/onemedia/PlayerService.java b/tests/OneMedia/src/com/android/onemedia/PlayerService.java
index 58ee4a187ebf..9967c994741a 100644
--- a/tests/OneMedia/src/com/android/onemedia/PlayerService.java
+++ b/tests/OneMedia/src/com/android/onemedia/PlayerService.java
@@ -17,6 +17,7 @@ package com.android.onemedia;
import android.app.Service;
import android.content.Intent;
+import android.graphics.Bitmap;
import android.media.session.MediaSession;
import android.media.session.PlaybackState;
import android.os.Bundle;
@@ -34,6 +35,7 @@ public class PlayerService extends Service {
private PlayerBinder mBinder;
private PlayerSession mSession;
+ private NotificationHelper mNotifyHelper;
private Intent mIntent;
private boolean mStarted = false;
@@ -47,6 +49,7 @@ public class PlayerService extends Service {
mSession = onCreatePlayerController();
mSession.createSession();
mSession.setListener(mPlayerListener);
+ mNotifyHelper = new NotificationHelper(this, mSession.mSession);
}
}
@@ -75,6 +78,7 @@ public class PlayerService extends Service {
if (!mStarted) {
Log.d(TAG, "Starting self");
startService(onCreateServiceIntent());
+ mNotifyHelper.onStart();
mStarted = true;
}
}
@@ -82,6 +86,7 @@ public class PlayerService extends Service {
public void onPlaybackEnded() {
if (mStarted) {
Log.d(TAG, "Stopping self");
+ mNotifyHelper.onStop();
stopSelf();
mStarted = false;
}
@@ -150,8 +155,17 @@ public class PlayerService extends Service {
@Override
public MediaSession.Token getSessionToken() throws RemoteException {
+ if (mSession == null) {
+ Log.e(TAG, "Error in PlayerService: mSession=null in getSessionToken()");
+ return null;
+ }
return mSession.getSessionToken();
}
+
+ @Override
+ public void setIcon(Bitmap icon) {
+ mSession.setIcon(icon);
+ }
}
}
diff --git a/tests/OneMedia/src/com/android/onemedia/PlayerSession.java b/tests/OneMedia/src/com/android/onemedia/PlayerSession.java
index 890d68dfb4af..9afcf24c55c2 100644
--- a/tests/OneMedia/src/com/android/onemedia/PlayerSession.java
+++ b/tests/OneMedia/src/com/android/onemedia/PlayerSession.java
@@ -17,6 +17,8 @@ package com.android.onemedia;
import android.content.Context;
import android.content.Intent;
+import android.graphics.Bitmap;
+import android.media.MediaMetadata;
import android.media.routing.MediaRouteSelector;
import android.media.routing.MediaRouter;
import android.media.routing.MediaRouter.ConnectionRequest;
@@ -50,6 +52,7 @@ public class PlayerSession {
protected Renderer mRenderer;
protected MediaSession.Callback mCallback;
protected Renderer.Listener mRenderListener;
+ protected MediaMetadata.Builder mMetadataBuilder;
protected PlaybackState mPlaybackState;
protected Listener mListener;
@@ -66,6 +69,8 @@ public class PlayerSession {
mPlaybackState = psBob.build();
mRenderer.registerListener(mRenderListener);
+
+ initMetadata();
}
public void createSession() {
@@ -92,6 +97,7 @@ public class PlayerSession {
| MediaSession.FLAG_HANDLES_MEDIA_BUTTONS);
mSession.setMediaRouter(mRouter);
mSession.setActive(true);
+ updateMetadata();
}
public void onDestroy() {
@@ -130,6 +136,19 @@ public class PlayerSession {
mRenderer.setNextContent(request);
}
+ public void setIcon(Bitmap icon) {
+ mMetadataBuilder.putBitmap(MediaMetadata.METADATA_KEY_DISPLAY_ICON, icon);
+ updateMetadata();
+ }
+
+ private void updateMetadata() {
+ // This is a mild abuse of metadata and shouldn't be duplicated in real
+ // code
+ if (mSession != null && mSession.isActive()) {
+ mSession.setMetadata(mMetadataBuilder.build());
+ }
+ }
+
private void updateState(int newState) {
float rate = newState == PlaybackState.STATE_PLAYING ? 1 : 0;
long position = mRenderer == null ? -1 : mRenderer.getSeekPosition();
@@ -140,6 +159,14 @@ public class PlayerSession {
mSession.setPlaybackState(mPlaybackState);
}
+ private void initMetadata() {
+ mMetadataBuilder = new MediaMetadata.Builder();
+ mMetadataBuilder.putString(MediaMetadata.METADATA_KEY_DISPLAY_TITLE,
+ "OneMedia display title");
+ mMetadataBuilder.putString(MediaMetadata.METADATA_KEY_DISPLAY_SUBTITLE,
+ "OneMedia display subtitle");
+ }
+
public interface Listener {
public void onPlayStateChanged(PlaybackState state);
}
diff --git a/tests/OneMedia/src/com/android/onemedia/playback/RequestUtils.java b/tests/OneMedia/src/com/android/onemedia/playback/RequestUtils.java
index 3778c5f94621..1688395c65c5 100644
--- a/tests/OneMedia/src/com/android/onemedia/playback/RequestUtils.java
+++ b/tests/OneMedia/src/com/android/onemedia/playback/RequestUtils.java
@@ -26,6 +26,12 @@ import java.util.Map;
public class RequestUtils {
public static final String ACTION_SET_CONTENT = "set_content";
public static final String ACTION_SET_NEXT_CONTENT = "set_next_content";
+ public static final String ACTION_PAUSE = "com.android.onemedia.pause";
+ public static final String ACTION_PLAY = "com.android.onemedia.play";
+ public static final String ACTION_REW = "com.android.onemedia.rew";
+ public static final String ACTION_FFWD = "com.android.onemedia.ffwd";
+ public static final String ACTION_PREV = "com.android.onemedia.prev";
+ public static final String ACTION_NEXT = "com.android.onemedia.next";
public static final String EXTRA_KEY_SOURCE = "source";
public static final String EXTRA_KEY_METADATA = "metadata";
diff --git a/tests/UsesFeature2Test/AndroidManifest.xml b/tests/UsesFeature2Test/AndroidManifest.xml
index 6b6c4dab67f8..8caf4a158867 100644
--- a/tests/UsesFeature2Test/AndroidManifest.xml
+++ b/tests/UsesFeature2Test/AndroidManifest.xml
@@ -33,12 +33,5 @@
<uses-feature android:name="android.hardware.opengles.aep" />
</feature-group>
- <application android:label="@string/app_title">
- <activity android:name="ActivityMain">
- <intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
- </intent-filter>
- </activity>
- </application>
+ <application android:label="@string/app_title" android:hasCode="false" />
</manifest>
diff --git a/tools/aapt/Command.cpp b/tools/aapt/Command.cpp
index 41102fe7491d..5d146d65bded 100644
--- a/tools/aapt/Command.cpp
+++ b/tools/aapt/Command.cpp
@@ -764,12 +764,9 @@ int doDump(Bundle* bundle)
return 1;
}
+ // The dynamicRefTable can be null if there are no resources for this asset cookie.
+ // This fine.
const DynamicRefTable* dynamicRefTable = res.getDynamicRefTableForCookie(assetsCookie);
- if (dynamicRefTable == NULL) {
- fprintf(stderr, "ERROR: failed to find dynamic reference table for asset cookie %d\n",
- assetsCookie);
- return 1;
- }
Asset* asset = NULL;
@@ -992,6 +989,10 @@ int doDump(Bundle* bundle)
bool hasReadCallLogPermission = false;
bool hasWriteCallLogPermission = false;
+ // If an app declares itself as multiArch, we report the
+ // native libraries differently.
+ bool hasMultiArch = false;
+
// This next group of variables is used to implement a group of
// backward-compatibility heuristics necessitated by the addition of
// some new uses-feature constants in 2.1 and 2.2. In most cases, the
@@ -1236,6 +1237,20 @@ int doDump(Bundle* bundle)
if (debuggable != 0) {
printf("application-debuggable\n");
}
+
+ // We must search by name because the multiArch flag hasn't been API
+ // frozen yet.
+ int32_t multiArchIndex = tree.indexOfAttribute(RESOURCES_ANDROID_NAMESPACE,
+ "multiArch");
+ if (multiArchIndex >= 0) {
+ Res_value value;
+ if (tree.getAttributeValue(multiArchIndex, &value) != NO_ERROR) {
+ if (value.dataType >= Res_value::TYPE_FIRST_INT &&
+ value.dataType <= Res_value::TYPE_LAST_INT) {
+ hasMultiArch = value.data;
+ }
+ }
+ }
} else if (tag == "uses-sdk") {
int32_t code = getIntegerAttribute(tree, MIN_SDK_VERSION_ATTR, &error);
if (error != "") {
@@ -1676,12 +1691,8 @@ int doDump(Bundle* bundle)
String8 name = getResolvedAttribute(&res, tree, NAME_ATTR, &error);
if (name != "" && error == "") {
- int required = getIntegerAttribute(tree, REQUIRED_ATTR, NULL, 1);
- top.features.add(name, required);
- if (required) {
- addParentFeatures(&top, name);
- }
-
+ top.features.add(name, true);
+ addParentFeatures(&top, name);
} else {
int vers = getIntegerAttribute(tree, GL_ES_VERSION_ATTR, &error);
if (error == "") {
@@ -2051,12 +2062,54 @@ int doDump(Bundle* bundle)
AssetDir* dir = assets.openNonAssetDir(assetsCookie, "lib");
if (dir != NULL) {
if (dir->getFileCount() > 0) {
- printf("native-code:");
+ SortedVector<String8> architectures;
for (size_t i=0; i<dir->getFileCount(); i++) {
- printf(" '%s'", ResTable::normalizeForOutput(
- dir->getFileName(i).string()).string());
+ architectures.add(ResTable::normalizeForOutput(
+ dir->getFileName(i).string()));
+ }
+
+ bool outputAltNativeCode = false;
+ // A multiArch package is one that contains 64-bit and
+ // 32-bit versions of native code and expects 3rd-party
+ // apps to load these native code libraries. Since most
+ // 64-bit systems also support 32-bit apps, the apps
+ // loading this multiArch package's code may be either
+ // 32-bit or 64-bit.
+ if (hasMultiArch) {
+ // If this is a multiArch package, report the 64-bit
+ // version only. Then as a separate entry, report the
+ // rest.
+ //
+ // If we report the 32-bit architecture, this APK will
+ // be installed on a 32-bit device, causing a large waste
+ // of bandwidth and disk space. This assumes that
+ // the developer of the multiArch package has also
+ // made a version that is 32-bit only.
+ String8 intel64("x86_64");
+ String8 arm64("arm64-v8a");
+ ssize_t index = architectures.indexOf(intel64);
+ if (index < 0) {
+ index = architectures.indexOf(arm64);
+ }
+
+ if (index >= 0) {
+ printf("native-code: '%s'\n", architectures[index].string());
+ architectures.removeAt(index);
+ outputAltNativeCode = true;
+ }
+ }
+
+ const size_t archCount = architectures.size();
+ if (archCount > 0) {
+ if (outputAltNativeCode) {
+ printf("alt-");
+ }
+ printf("native-code:");
+ for (size_t i = 0; i < archCount; i++) {
+ printf(" '%s'", architectures[i].string());
+ }
+ printf("\n");
}
- printf("\n");
}
delete dir;
}
diff --git a/tools/aapt/Resource.cpp b/tools/aapt/Resource.cpp
index 010d59ba1923..0a808059a56d 100644
--- a/tools/aapt/Resource.cpp
+++ b/tools/aapt/Resource.cpp
@@ -1470,6 +1470,8 @@ status_t buildResources(Bundle* bundle, const sp<AaptAssets>& assets, sp<ApkBuil
String16 action16("action");
String16 category16("category");
String16 data16("scheme");
+ String16 feature_group16("feature-group");
+ String16 uses_feature16("uses-feature");
const char* packageIdentChars = "abcdefghijklmnopqrstuvwxyz"
"ABCDEFGHIJKLMNOPQRSTUVWXYZ._0123456789";
const char* packageIdentCharsWithTheStupid = "abcdefghijklmnopqrstuvwxyz"
@@ -1680,10 +1682,43 @@ status_t buildResources(Bundle* bundle, const sp<AaptAssets>& assets, sp<ApkBuil
schemeIdentChars, true) != ATTR_OKAY) {
hasErrors = true;
}
+ } else if (strcmp16(block.getElementName(&len), feature_group16.string()) == 0) {
+ int depth = 1;
+ while ((code=block.next()) != ResXMLTree::END_DOCUMENT
+ && code > ResXMLTree::BAD_DOCUMENT) {
+ if (code == ResXMLTree::START_TAG) {
+ depth++;
+ if (strcmp16(block.getElementName(&len), uses_feature16.string()) == 0) {
+ ssize_t idx = block.indexOfAttribute(
+ RESOURCES_ANDROID_NAMESPACE, "required");
+ if (idx < 0) {
+ continue;
+ }
+
+ int32_t data = block.getAttributeData(idx);
+ if (data == 0) {
+ fprintf(stderr, "%s:%d: Tag <uses-feature> can not have "
+ "android:required=\"false\" when inside a "
+ "<feature-group> tag.\n",
+ manifestPath.string(), block.getLineNumber());
+ hasErrors = true;
+ }
+ }
+ } else if (code == ResXMLTree::END_TAG) {
+ depth--;
+ if (depth == 0) {
+ break;
+ }
+ }
+ }
}
}
}
+ if (hasErrors) {
+ return UNKNOWN_ERROR;
+ }
+
if (resFile != NULL) {
// These resources are now considered to be a part of the included
// resources, for others to reference.