summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Android.bp27
-rw-r--r--apex/appsearch/service/java/com/android/server/appsearch/impl/FakeIcing.java18
-rw-r--r--api/current.txt74
-rw-r--r--api/removed.txt2
-rw-r--r--api/system-current.txt110
-rw-r--r--api/test-lint-baseline.txt400
-rw-r--r--cmds/statsd/src/StatsService.cpp2
-rw-r--r--cmds/statsd/src/atoms.proto133
-rw-r--r--cmds/telecom/src/com/android/commands/telecom/Telecom.java17
-rw-r--r--core/java/android/app/ApplicationPackageManager.java18
-rw-r--r--core/java/android/app/IActivityManager.aidl1
-rw-r--r--core/java/android/app/StatsManager.java31
-rw-r--r--core/java/android/app/SystemServiceRegistry.java3
-rw-r--r--core/java/android/app/admin/DeviceAdminInfo.java8
-rw-r--r--core/java/android/app/admin/DevicePolicyManager.java9
-rw-r--r--core/java/android/app/timezonedetector/TimeZoneDetector.java35
-rw-r--r--core/java/android/bluetooth/BluetoothA2dp.java2
-rw-r--r--core/java/android/bluetooth/BluetoothHeadset.java5
-rw-r--r--core/java/android/bluetooth/BluetoothHeadsetClient.java2
-rw-r--r--core/java/android/bluetooth/BluetoothUuid.java258
-rw-r--r--core/java/android/content/Context.java8
-rw-r--r--core/java/android/content/Intent.java7
-rw-r--r--core/java/android/content/pm/DataLoaderManager.java87
-rw-r--r--core/java/android/content/pm/IDataLoader.aidl (renamed from tools/processors/unsupportedappusage/src/android/processor/unsupportedappusage/SourcePosition.java)30
-rw-r--r--core/java/android/content/pm/IDataLoaderManager.aidl29
-rw-r--r--core/java/android/content/pm/IDataLoaderStatusListener.aidl (renamed from core/java/android/service/incremental/IIncrementalDataLoaderStatusListener.aidl)8
-rw-r--r--core/java/android/content/pm/IPackageInstallerSession.aidl1
-rw-r--r--core/java/android/content/pm/IPackageManager.aidl3
-rw-r--r--core/java/android/content/pm/InstallSourceInfo.aidl19
-rw-r--r--core/java/android/content/pm/InstallSourceInfo.java110
-rw-r--r--core/java/android/content/pm/InstallationFile.aidl23
-rw-r--r--core/java/android/content/pm/InstallationFile.java118
-rw-r--r--core/java/android/content/pm/PackageInstaller.java47
-rw-r--r--core/java/android/content/pm/PackageManager.java19
-rw-r--r--core/java/android/os/incremental/IIncrementalServiceProxy.aidl4
-rw-r--r--core/java/android/os/incremental/IncrementalFileStorages.java280
-rw-r--r--core/java/android/permission/PermissionManager.java54
-rw-r--r--core/java/android/provider/MediaStore.java119
-rw-r--r--core/java/android/provider/Settings.java41
-rw-r--r--core/java/android/provider/Telephony.java3
-rw-r--r--core/java/android/service/controls/BooleanAction.aidl19
-rw-r--r--core/java/android/service/controls/BooleanAction.java93
-rw-r--r--core/java/android/service/controls/Control.aidl19
-rw-r--r--core/java/android/service/controls/Control.java284
-rw-r--r--core/java/android/service/controls/ControlAction.aidl19
-rw-r--r--core/java/android/service/controls/ControlAction.java189
-rw-r--r--core/java/android/service/controls/ControlButton.aidl19
-rw-r--r--core/java/android/service/controls/ControlButton.java103
-rw-r--r--core/java/android/service/controls/ControlState.aidl19
-rw-r--r--core/java/android/service/controls/ControlState.java318
-rw-r--r--core/java/android/service/controls/ControlTemplate.aidl19
-rw-r--r--core/java/android/service/controls/ControlTemplate.java167
-rw-r--r--core/java/android/service/controls/DiscreteToggleTemplate.java110
-rw-r--r--core/java/android/service/controls/FloatAction.aidl19
-rw-r--r--core/java/android/service/controls/FloatAction.java90
-rw-r--r--core/java/android/service/controls/IControlsProvider.aidl30
-rw-r--r--core/java/android/service/controls/IControlsProviderCallback.aidl29
-rw-r--r--core/java/android/service/controls/RangeTemplate.aidl19
-rw-r--r--core/java/android/service/controls/RangeTemplate.java190
-rw-r--r--core/java/android/service/controls/ThumbnailTemplate.aidl19
-rw-r--r--core/java/android/service/controls/ThumbnailTemplate.java95
-rw-r--r--core/java/android/service/controls/ToggleTemplate.aidl19
-rw-r--r--core/java/android/service/controls/ToggleTemplate.java86
-rw-r--r--core/java/android/service/incremental/IIncrementalDataLoaderService.aidl34
-rw-r--r--core/java/android/service/notification/IConditionProvider.aidl2
-rw-r--r--core/java/android/telephony/DataConnectionRealTimeInfo.aidl (renamed from telephony/java/android/telephony/DataConnectionRealTimeInfo.aidl)0
-rw-r--r--core/java/android/telephony/DataConnectionRealTimeInfo.java (renamed from telephony/java/android/telephony/DataConnectionRealTimeInfo.java)0
-rw-r--r--core/java/android/telephony/TelephonyRegistryManager.java17
-rw-r--r--core/java/android/util/StatsEvent.java6
-rw-r--r--core/java/android/view/InsetsController.java5
-rw-r--r--core/java/android/view/InsetsSourceConsumer.java3
-rw-r--r--core/java/android/view/SurfaceControl.java7
-rw-r--r--core/java/android/view/WindowManager.java28
-rw-r--r--core/java/com/android/internal/util/AsyncChannel.java10
-rw-r--r--core/java/com/android/internal/util/AsyncService.java6
-rw-r--r--core/java/com/android/internal/view/BaseIWindow.java9
-rw-r--r--core/proto/android/stats/mediaprovider/mediaprovider_enums.proto30
-rw-r--r--core/res/res/values/config.xml8
-rw-r--r--core/res/res/values/strings.xml18
-rw-r--r--core/res/res/values/symbols.xml4
-rw-r--r--core/tests/coretests/src/android/service/controls/ControlActionTest.java69
-rw-r--r--core/tests/coretests/src/android/service/controls/ControlTemplateTest.java139
-rw-r--r--core/tests/coretests/src/android/util/StatsEventTest.java7
-rw-r--r--media/Android.bp5
-rw-r--r--media/apex/java/android/media/MediaParser.java743
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java9
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBarModule.java7
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java4
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpSinkProfile.java4
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothDeviceFilter.java8
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java5
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/bluetooth/HeadsetProfile.java2
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/bluetooth/HfpClientProfile.java2
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java44
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/bluetooth/PbapServerProfile.java2
-rw-r--r--packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManagerTest.java2
-rw-r--r--packages/SettingsProvider/src/android/provider/settings/backup/GlobalSettings.java2
-rw-r--r--packages/SettingsProvider/src/android/provider/settings/validators/GlobalSettingsValidators.java2
-rw-r--r--packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java1
-rw-r--r--packages/SystemUI/AndroidManifest.xml5
-rw-r--r--packages/SystemUI/src/com/android/systemui/ForegroundServiceController.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/ForegroundServiceNotificationListener.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/assist/AssistHandleService.kt37
-rw-r--r--packages/SystemUI/src/com/android/systemui/assist/AssistModule.java9
-rw-r--r--packages/SystemUI/src/com/android/systemui/assist/IAssistHandleService.aidl24
-rw-r--r--packages/SystemUI/src/com/android/systemui/bubbles/Bubble.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java15
-rw-r--r--packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java27
-rw-r--r--packages/SystemUI/src/com/android/systemui/bubbles/BubbleExperimentConfig.java11
-rw-r--r--packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/dagger/SystemUIRootComponent.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/dagger/qualifiers/Background.java30
-rw-r--r--packages/SystemUI/src/com/android/systemui/dagger/qualifiers/Main.java30
-rw-r--r--packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/glwallpaper/ImageRevealHelper.java12
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java22
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/OverviewProxyRecentsImpl.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/FeatureFlags.java9
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java9
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationListController.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationRankingManager.kt71
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.java11
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeServiceHost.java9
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenWallpaper.java1
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/ShadeController.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java38
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarComponent.java57
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarModule.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java21
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowViewController.java10
-rw-r--r--packages/SystemUI/src/com/android/systemui/util/concurrency/ConcurrencyModule.java88
-rw-r--r--packages/SystemUI/src/com/android/systemui/util/concurrency/DelayableExecutor.java72
-rw-r--r--packages/SystemUI/src/com/android/systemui/util/concurrency/ExecutorImpl.java58
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/customize/TileQueryHelperTest.java41
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationRankingManagerTest.kt79
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeServiceHostTest.java8
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java22
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java13
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java12
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarWindowViewTest.java7
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/util/concurrency/FakeExecutor.java227
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/util/concurrency/FakeExecutorTest.java366
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/util/time/FakeSystemClock.java70
-rw-r--r--services/accessibility/java/com/android/server/accessibility/AccessibilityWindowManager.java20
-rw-r--r--services/accessibility/java/com/android/server/accessibility/SystemActionPerformer.java241
-rw-r--r--services/core/java/com/android/server/OWNERS3
-rw-r--r--services/core/java/com/android/server/TelephonyRegistry.java22
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerService.java25
-rw-r--r--services/core/java/com/android/server/am/BugReportHandlerUtil.java179
-rw-r--r--services/core/java/com/android/server/am/OomAdjuster.java23
-rw-r--r--services/core/java/com/android/server/connectivity/NetworkNotificationManager.java4
-rw-r--r--services/core/java/com/android/server/pm/AppsFilter.java7
-rw-r--r--services/core/java/com/android/server/pm/DataLoaderManagerService.java246
-rw-r--r--services/core/java/com/android/server/pm/PackageInstallerSession.java47
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerService.java91
-rw-r--r--services/core/java/com/android/server/pm/Settings.java8
-rw-r--r--services/core/java/com/android/server/policy/PermissionPolicyService.java19
-rw-r--r--services/core/java/com/android/server/power/PowerManagerService.java43
-rw-r--r--services/core/java/com/android/server/power/SystemPropertiesWrapper.java51
-rw-r--r--services/core/java/com/android/server/utils/TimingsTraceAndSlog.java11
-rw-r--r--services/core/java/com/android/server/wallpaper/WallpaperManagerService.java100
-rw-r--r--services/core/java/com/android/server/wm/DisplayPolicy.java13
-rw-r--r--services/core/java/com/android/server/wm/Task.java11
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerInternal.java6
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerService.java21
-rw-r--r--services/core/java/com/android/server/wm/WindowState.java14
-rw-r--r--services/core/jni/com_android_server_VibratorService.cpp2
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java52
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java29
-rw-r--r--services/tests/servicestests/src/com/android/server/accessibility/SystemActionPerformerTest.java286
-rw-r--r--services/tests/servicestests/src/com/android/server/appsearch/impl/FakeIcingTest.java6
-rw-r--r--services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java6
-rw-r--r--services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java23
-rw-r--r--services/tests/servicestests/src/com/android/server/devicepolicy/MockSystemServices.java3
-rw-r--r--services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java24
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java17
-rw-r--r--telecomm/java/android/telecom/Call.java25
-rw-r--r--telecomm/java/android/telecom/Connection.java57
-rw-r--r--telecomm/java/android/telecom/ConnectionService.java6
-rw-r--r--telecomm/java/android/telecom/ParcelableCall.java20
-rw-r--r--telecomm/java/android/telecom/ParcelableConnection.java19
-rw-r--r--telephony/java/android/telephony/TelephonyManager.java11
-rw-r--r--tools/processors/unsupportedappusage/Android.bp34
-rw-r--r--tools/processors/unsupportedappusage/META-INF/services/javax.annotation.processing.Processor1
-rw-r--r--tools/processors/unsupportedappusage/src/android/processor/unsupportedappusage/SignatureBuilder.java258
-rw-r--r--tools/processors/unsupportedappusage/src/android/processor/unsupportedappusage/UnsupportedAppUsageProcessor.java246
-rw-r--r--tools/processors/unsupportedappusage/test/Android.bp28
-rw-r--r--tools/processors/unsupportedappusage/test/src/android/processor/unsupportedappusage/CsvReader.java61
-rw-r--r--tools/processors/unsupportedappusage/test/src/android/processor/unsupportedappusage/UnsupportedAppUsageProcessorTest.java154
-rw-r--r--wifi/java/android/net/wifi/ScanResult.java14
-rw-r--r--wifi/java/android/net/wifi/WifiScanner.java8
-rw-r--r--wifi/tests/src/android/net/wifi/WifiScannerTest.java8
196 files changed, 7581 insertions, 1990 deletions
diff --git a/Android.bp b/Android.bp
index 412a8ec79437..9426a9c503ed 100644
--- a/Android.bp
+++ b/Android.bp
@@ -803,10 +803,9 @@ filegroup {
}
filegroup {
- name: "incremental_data_loader_aidl",
+ name: "dataloader_aidl",
srcs: [
- "core/java/android/service/incremental/IIncrementalDataLoaderStatusListener.aidl",
- "core/java/android/service/incremental/IIncrementalDataLoaderService.aidl",
+ "core/java/android/content/pm/IDataLoaderStatusListener.aidl",
],
path: "core/java",
}
@@ -815,7 +814,27 @@ aidl_interface {
name: "libincremental_aidl",
srcs: [
":incremental_aidl",
- ":incremental_data_loader_aidl",
+ ],
+ imports: [
+ "libdataloader_aidl",
+ ],
+ backend: {
+ java: {
+ sdk_version: "28",
+ },
+ cpp: {
+ enabled: true,
+ },
+ ndk: {
+ enabled: true,
+ },
+ },
+}
+
+aidl_interface {
+ name: "libdataloader_aidl",
+ srcs: [
+ ":dataloader_aidl",
],
backend: {
java: {
diff --git a/apex/appsearch/service/java/com/android/server/appsearch/impl/FakeIcing.java b/apex/appsearch/service/java/com/android/server/appsearch/impl/FakeIcing.java
index 5ac922c4a9b6..3dbb5cffe908 100644
--- a/apex/appsearch/service/java/com/android/server/appsearch/impl/FakeIcing.java
+++ b/apex/appsearch/service/java/com/android/server/appsearch/impl/FakeIcing.java
@@ -24,10 +24,8 @@ import android.util.SparseArray;
import com.google.android.icing.proto.DocumentProto;
import com.google.android.icing.proto.PropertyProto;
+import com.google.android.icing.proto.SearchResultProto;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
@@ -94,23 +92,25 @@ public class FakeIcing {
* Returns documents containing the given term.
*
* @param term A single exact term to look up in the index.
- * @return The matching documents, or an empty {@code List} if no documents match.
+ * @return A {@link SearchResultProto} containing the matching documents, which may have no
+ * results if no documents match.
*/
@NonNull
- public List<DocumentProto> query(@NonNull String term) {
+ public SearchResultProto query(@NonNull String term) {
String normTerm = normalizeString(term);
Set<Integer> docIds = mIndex.get(normTerm);
if (docIds == null || docIds.isEmpty()) {
- return Collections.emptyList();
+ return SearchResultProto.getDefaultInstance();
}
- List<DocumentProto> matches = new ArrayList<>(docIds.size());
+ SearchResultProto.Builder results = SearchResultProto.newBuilder();
for (int docId : docIds) {
DocumentProto document = mDocStore.get(docId);
if (document != null) {
- matches.add(document);
+ results.addResults(
+ SearchResultProto.ResultProto.newBuilder().setDocument(document));
}
}
- return matches;
+ return results.build();
}
/**
diff --git a/api/current.txt b/api/current.txt
index 6ad8ddd4097e..8533ab197148 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -11365,6 +11365,15 @@ package android.content.pm {
field public int version;
}
+ public final class InstallSourceInfo implements android.os.Parcelable {
+ method public int describeContents();
+ method @Nullable public String getInitiatingPackageName();
+ method @Nullable public String getInstallingPackageName();
+ method @Nullable public String getOriginatingPackageName();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.content.pm.InstallSourceInfo> CREATOR;
+ }
+
public class InstrumentationInfo extends android.content.pm.PackageItemInfo implements android.os.Parcelable {
ctor public InstrumentationInfo();
ctor public InstrumentationInfo(android.content.pm.InstrumentationInfo);
@@ -11729,10 +11738,11 @@ package android.content.pm {
method public abstract int getComponentEnabledSetting(@NonNull android.content.ComponentName);
method @NonNull public abstract android.graphics.drawable.Drawable getDefaultActivityIcon();
method @Nullable public abstract android.graphics.drawable.Drawable getDrawable(@NonNull String, @DrawableRes int, @Nullable android.content.pm.ApplicationInfo);
+ method @NonNull public android.content.pm.InstallSourceInfo getInstallSourceInfo(@NonNull String) throws android.content.pm.PackageManager.NameNotFoundException;
method @NonNull public abstract java.util.List<android.content.pm.ApplicationInfo> getInstalledApplications(int);
method @NonNull public java.util.List<android.content.pm.ModuleInfo> getInstalledModules(int);
method @NonNull public abstract java.util.List<android.content.pm.PackageInfo> getInstalledPackages(int);
- method @Nullable public abstract String getInstallerPackageName(@NonNull String);
+ method @Deprecated @Nullable public abstract String getInstallerPackageName(@NonNull String);
method @NonNull public abstract byte[] getInstantAppCookie();
method public abstract int getInstantAppCookieMaxBytes();
method @NonNull public abstract android.content.pm.InstrumentationInfo getInstrumentationInfo(@NonNull android.content.ComponentName, int) throws android.content.pm.PackageManager.NameNotFoundException;
@@ -25605,6 +25615,50 @@ package android.media {
field public static final int MUXER_OUTPUT_WEBM = 1; // 0x1
}
+ public final class MediaParser {
+ method public boolean advance(@NonNull android.media.MediaParser.SeekableInputReader) throws java.io.IOException, java.lang.InterruptedException;
+ method @NonNull public static android.media.MediaParser create(@NonNull android.media.MediaParser.OutputConsumer, @NonNull java.lang.String...);
+ method @NonNull public static android.media.MediaParser createByName(@NonNull String, @NonNull android.media.MediaParser.OutputConsumer);
+ method @Nullable public String getExtractorName();
+ method @NonNull public static java.util.List<java.lang.String> getExtractorNames(@NonNull android.media.MediaFormat);
+ method public void release();
+ method public void seek(@NonNull android.media.MediaParser.SeekPoint);
+ }
+
+ public static interface MediaParser.InputReader {
+ method public long getLength();
+ method public long getPosition();
+ method public int read(@NonNull byte[], int, int) throws java.io.IOException, java.lang.InterruptedException;
+ }
+
+ public static interface MediaParser.OutputConsumer {
+ method public void onFormat(int, @NonNull android.media.MediaFormat);
+ method public void onSampleCompleted(int, long, int, int, int, @Nullable android.media.MediaCodec.CryptoInfo);
+ method public void onSampleData(int, @NonNull android.media.MediaParser.InputReader) throws java.io.IOException, java.lang.InterruptedException;
+ method public void onSeekMap(@NonNull android.media.MediaParser.SeekMap);
+ method public void onTracksFound(int);
+ }
+
+ public static interface MediaParser.SeekMap {
+ method public long getDurationUs();
+ method @NonNull public android.util.Pair<android.media.MediaParser.SeekPoint,android.media.MediaParser.SeekPoint> getSeekPoints(long);
+ method public boolean isSeekable();
+ field public static final int UNKNOWN_DURATION = -2147483648; // 0x80000000
+ }
+
+ public static final class MediaParser.SeekPoint {
+ field @NonNull public static final android.media.MediaParser.SeekPoint START;
+ field public final long position;
+ field public final long timeUs;
+ }
+
+ public static interface MediaParser.SeekableInputReader extends android.media.MediaParser.InputReader {
+ method public void seekToPosition(long);
+ }
+
+ public static final class MediaParser.UnrecognizedInputFormatException extends java.io.IOException {
+ }
+
public class MediaPlayer implements android.media.AudioRouting android.media.VolumeAutomation {
ctor public MediaPlayer();
method public void addOnRoutingChangedListener(android.media.AudioRouting.OnRoutingChangedListener, android.os.Handler);
@@ -38618,15 +38672,13 @@ package android.provider {
ctor public MediaStore();
method @Nullable public static android.net.Uri getDocumentUri(@NonNull android.content.Context, @NonNull android.net.Uri);
method @NonNull public static java.util.Set<java.lang.String> getExternalVolumeNames(@NonNull android.content.Context);
- method public static boolean getIncludePending(@NonNull android.net.Uri);
method public static android.net.Uri getMediaScannerUri();
method @Nullable public static android.net.Uri getMediaUri(@NonNull android.content.Context, @NonNull android.net.Uri);
method public static boolean getRequireOriginal(@NonNull android.net.Uri);
method @NonNull public static String getVersion(@NonNull android.content.Context);
method @NonNull public static String getVersion(@NonNull android.content.Context, @NonNull String);
method @NonNull public static String getVolumeName(@NonNull android.net.Uri);
- method @NonNull public static android.net.Uri setIncludePending(@NonNull android.net.Uri);
- method @NonNull public static android.net.Uri setIncludeTrashed(@NonNull android.net.Uri);
+ method @Deprecated @NonNull public static android.net.Uri setIncludePending(@NonNull android.net.Uri);
method @NonNull public static android.net.Uri setRequireOriginal(@NonNull android.net.Uri);
method public static void trash(@NonNull android.content.Context, @NonNull android.net.Uri);
method public static void trash(@NonNull android.content.Context, @NonNull android.net.Uri, long);
@@ -38662,9 +38714,17 @@ package android.provider {
field public static final String INTENT_ACTION_TEXT_OPEN_FROM_SEARCH = "android.media.action.TEXT_OPEN_FROM_SEARCH";
field public static final String INTENT_ACTION_VIDEO_CAMERA = "android.media.action.VIDEO_CAMERA";
field public static final String INTENT_ACTION_VIDEO_PLAY_FROM_SEARCH = "android.media.action.VIDEO_PLAY_FROM_SEARCH";
+ field public static final int MATCH_DEFAULT = 0; // 0x0
+ field public static final int MATCH_EXCLUDE = 2; // 0x2
+ field public static final int MATCH_INCLUDE = 1; // 0x1
+ field public static final int MATCH_ONLY = 3; // 0x3
field public static final String MEDIA_IGNORE_FILENAME = ".nomedia";
field public static final String MEDIA_SCANNER_VOLUME = "volume";
field public static final String META_DATA_STILL_IMAGE_CAMERA_PREWARM_SERVICE = "android.media.still_image_camera_preview_service";
+ field public static final String QUERY_ARG_MATCH_FAVORITE = "android:query-arg-match-favorite";
+ field public static final String QUERY_ARG_MATCH_PENDING = "android:query-arg-match-pending";
+ field public static final String QUERY_ARG_MATCH_TRASHED = "android:query-arg-match-trashed";
+ field public static final String QUERY_ARG_RELATED_URI = "android:query-arg-related-uri";
field public static final String UNKNOWN_STRING = "<unknown>";
field public static final String VOLUME_EXTERNAL = "external";
field public static final String VOLUME_EXTERNAL_PRIMARY = "external_primary";
@@ -43487,6 +43547,7 @@ package android.telecom {
method public int getCallProperties();
method public String getCallerDisplayName();
method public int getCallerDisplayNamePresentation();
+ method public int getCallerNumberVerificationStatus();
method public final long getConnectTimeMillis();
method public long getCreationTimeMillis();
method public android.telecom.DisconnectCause getDisconnectCause();
@@ -43668,6 +43729,7 @@ package android.telecom {
method public final android.telecom.CallAudioState getCallAudioState();
method public final String getCallerDisplayName();
method public final int getCallerDisplayNamePresentation();
+ method public int getCallerNumberVerificationStatus();
method public final android.telecom.Conference getConference();
method public final java.util.List<android.telecom.Conferenceable> getConferenceables();
method public final int getConnectionCapabilities();
@@ -43719,6 +43781,7 @@ package android.telecom {
method public final void setAudioModeIsVoip(boolean);
method public final void setAudioRoute(int);
method public final void setCallerDisplayName(String, int);
+ method public void setCallerNumberVerificationStatus(int);
method public final void setConferenceableConnections(java.util.List<android.telecom.Connection>);
method public final void setConferenceables(java.util.List<android.telecom.Conferenceable>);
method public final void setConnectionCapabilities(int);
@@ -43814,6 +43877,9 @@ package android.telecom {
field public static final int STATE_NEW = 1; // 0x1
field public static final int STATE_PULLING_CALL = 7; // 0x7
field public static final int STATE_RINGING = 2; // 0x2
+ field public static final int VERIFICATION_STATUS_FAILED = 2; // 0x2
+ field public static final int VERIFICATION_STATUS_NOT_VERIFIED = 0; // 0x0
+ field public static final int VERIFICATION_STATUS_PASSED = 1; // 0x1
}
public static final class Connection.RttModifyStatus {
diff --git a/api/removed.txt b/api/removed.txt
index e0e26f7d65a7..1a2f43450d7b 100644
--- a/api/removed.txt
+++ b/api/removed.txt
@@ -438,7 +438,9 @@ package android.provider {
public final class MediaStore {
method @Deprecated @NonNull public static android.net.Uri createPending(@NonNull android.content.Context, @NonNull android.provider.MediaStore.PendingParams);
method @Deprecated @NonNull public static java.util.Set<java.lang.String> getAllVolumeNames(@NonNull android.content.Context);
+ method @Deprecated public static boolean getIncludePending(@NonNull android.net.Uri);
method @Deprecated @NonNull public static android.provider.MediaStore.PendingSession openPending(@NonNull android.content.Context, @NonNull android.net.Uri);
+ method @Deprecated @NonNull public static android.net.Uri setIncludeTrashed(@NonNull android.net.Uri);
}
public static interface MediaStore.Audio.AudioColumns extends android.provider.MediaStore.MediaColumns {
diff --git a/api/system-current.txt b/api/system-current.txt
index 7fdf9edec911..fe9c0d1a7ff2 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -1399,6 +1399,7 @@ package android.bluetooth {
public final class BluetoothHeadset implements android.bluetooth.BluetoothProfile {
method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) public boolean connect(android.bluetooth.BluetoothDevice);
method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) public boolean disconnect(android.bluetooth.BluetoothDevice);
+ method @Nullable @RequiresPermission(android.Manifest.permission.BLUETOOTH) public android.bluetooth.BluetoothDevice getActiveDevice();
method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public int getConnectionPolicy(@NonNull android.bluetooth.BluetoothDevice);
method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) public boolean setConnectionPolicy(@NonNull android.bluetooth.BluetoothDevice, int);
method @Deprecated @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) public boolean setPriority(android.bluetooth.BluetoothDevice, int);
@@ -1433,6 +1434,37 @@ package android.bluetooth {
field @Deprecated public static final int PRIORITY_ON = 100; // 0x64
}
+ public final class BluetoothUuid {
+ method public static boolean containsAnyUuid(@Nullable android.os.ParcelUuid[], @Nullable android.os.ParcelUuid[]);
+ method @NonNull public static android.os.ParcelUuid parseUuidFrom(@Nullable byte[]);
+ field @NonNull public static final android.os.ParcelUuid A2DP_SINK;
+ field @NonNull public static final android.os.ParcelUuid A2DP_SOURCE;
+ field @NonNull public static final android.os.ParcelUuid ADV_AUDIO_DIST;
+ field @NonNull public static final android.os.ParcelUuid AVRCP_CONTROLLER;
+ field @NonNull public static final android.os.ParcelUuid AVRCP_TARGET;
+ field @NonNull public static final android.os.ParcelUuid BASE_UUID;
+ field @NonNull public static final android.os.ParcelUuid BNEP;
+ field @NonNull public static final android.os.ParcelUuid HEARING_AID;
+ field @NonNull public static final android.os.ParcelUuid HFP;
+ field @NonNull public static final android.os.ParcelUuid HFP_AG;
+ field @NonNull public static final android.os.ParcelUuid HID;
+ field @NonNull public static final android.os.ParcelUuid HOGP;
+ field @NonNull public static final android.os.ParcelUuid HSP;
+ field @NonNull public static final android.os.ParcelUuid HSP_AG;
+ field @NonNull public static final android.os.ParcelUuid MAP;
+ field @NonNull public static final android.os.ParcelUuid MAS;
+ field @NonNull public static final android.os.ParcelUuid MNS;
+ field @NonNull public static final android.os.ParcelUuid NAP;
+ field @NonNull public static final android.os.ParcelUuid OBEX_OBJECT_PUSH;
+ field @NonNull public static final android.os.ParcelUuid PANU;
+ field @NonNull public static final android.os.ParcelUuid PBAP_PCE;
+ field @NonNull public static final android.os.ParcelUuid PBAP_PSE;
+ field @NonNull public static final android.os.ParcelUuid SAP;
+ field public static final int UUID_BYTES_128_BIT = 16; // 0x10
+ field public static final int UUID_BYTES_16_BIT = 2; // 0x2
+ field public static final int UUID_BYTES_32_BIT = 4; // 0x4
+ }
+
}
package android.bluetooth.le {
@@ -4733,7 +4765,7 @@ package android.net.ipsec.ike {
method @NonNull public java.util.List<android.net.ipsec.ike.IkeTrafficSelector> getOutboundTrafficSelectors();
}
- public abstract class ChildSessionOptions {
+ public abstract class ChildSessionParams {
}
public class IkeFqdnIdentification extends android.net.ipsec.ike.IkeIdentification {
@@ -4778,11 +4810,11 @@ package android.net.ipsec.ike {
}
public final class IkeSession implements java.lang.AutoCloseable {
- ctor public IkeSession(@NonNull android.content.Context, @NonNull android.net.ipsec.ike.IkeSessionOptions, @NonNull android.net.ipsec.ike.ChildSessionOptions, @NonNull java.util.concurrent.Executor, @NonNull android.net.ipsec.ike.IkeSessionCallback, @NonNull android.net.ipsec.ike.ChildSessionCallback);
+ ctor public IkeSession(@NonNull android.content.Context, @NonNull android.net.ipsec.ike.IkeSessionParams, @NonNull android.net.ipsec.ike.ChildSessionParams, @NonNull java.util.concurrent.Executor, @NonNull android.net.ipsec.ike.IkeSessionCallback, @NonNull android.net.ipsec.ike.ChildSessionCallback);
method public void close();
method public void closeChildSession(@NonNull android.net.ipsec.ike.ChildSessionCallback);
method public void kill();
- method public void openChildSession(@NonNull android.net.ipsec.ike.ChildSessionOptions, @NonNull android.net.ipsec.ike.ChildSessionCallback);
+ method public void openChildSession(@NonNull android.net.ipsec.ike.ChildSessionParams, @NonNull android.net.ipsec.ike.ChildSessionCallback);
}
public interface IkeSessionCallback {
@@ -4800,21 +4832,21 @@ package android.net.ipsec.ike {
field public static final int EXTENSION_TYPE_MOBIKE = 2; // 0x2
}
- public final class IkeSessionOptions {
+ public final class IkeSessionParams {
}
- public static final class IkeSessionOptions.Builder {
- ctor public IkeSessionOptions.Builder();
- method @NonNull public android.net.ipsec.ike.IkeSessionOptions.Builder addSaProposal(@NonNull android.net.ipsec.ike.IkeSaProposal);
- method @NonNull public android.net.ipsec.ike.IkeSessionOptions build();
- method @NonNull public android.net.ipsec.ike.IkeSessionOptions.Builder setAuthDigitalSignature(@NonNull java.security.cert.X509Certificate, @NonNull java.security.cert.X509Certificate, @NonNull java.security.PrivateKey);
- method @NonNull public android.net.ipsec.ike.IkeSessionOptions.Builder setAuthDigitalSignature(@NonNull java.security.cert.X509Certificate, @NonNull java.security.cert.X509Certificate, @NonNull java.util.List<java.security.cert.X509Certificate>, @NonNull java.security.PrivateKey);
- method @NonNull public android.net.ipsec.ike.IkeSessionOptions.Builder setAuthEap(@NonNull java.security.cert.X509Certificate, @NonNull android.net.eap.EapSessionConfig);
- method @NonNull public android.net.ipsec.ike.IkeSessionOptions.Builder setAuthPsk(@NonNull byte[]);
- method @NonNull public android.net.ipsec.ike.IkeSessionOptions.Builder setLocalIdentification(@NonNull android.net.ipsec.ike.IkeIdentification);
- method @NonNull public android.net.ipsec.ike.IkeSessionOptions.Builder setRemoteIdentification(@NonNull android.net.ipsec.ike.IkeIdentification);
- method @NonNull public android.net.ipsec.ike.IkeSessionOptions.Builder setServerAddress(@NonNull java.net.InetAddress);
- method @NonNull public android.net.ipsec.ike.IkeSessionOptions.Builder setUdpEncapsulationSocket(@NonNull android.net.IpSecManager.UdpEncapsulationSocket);
+ public static final class IkeSessionParams.Builder {
+ ctor public IkeSessionParams.Builder();
+ method @NonNull public android.net.ipsec.ike.IkeSessionParams.Builder addSaProposal(@NonNull android.net.ipsec.ike.IkeSaProposal);
+ method @NonNull public android.net.ipsec.ike.IkeSessionParams build();
+ method @NonNull public android.net.ipsec.ike.IkeSessionParams.Builder setAuthDigitalSignature(@NonNull java.security.cert.X509Certificate, @NonNull java.security.cert.X509Certificate, @NonNull java.security.PrivateKey);
+ method @NonNull public android.net.ipsec.ike.IkeSessionParams.Builder setAuthDigitalSignature(@NonNull java.security.cert.X509Certificate, @NonNull java.security.cert.X509Certificate, @NonNull java.util.List<java.security.cert.X509Certificate>, @NonNull java.security.PrivateKey);
+ method @NonNull public android.net.ipsec.ike.IkeSessionParams.Builder setAuthEap(@NonNull java.security.cert.X509Certificate, @NonNull android.net.eap.EapSessionConfig);
+ method @NonNull public android.net.ipsec.ike.IkeSessionParams.Builder setAuthPsk(@NonNull byte[]);
+ method @NonNull public android.net.ipsec.ike.IkeSessionParams.Builder setLocalIdentification(@NonNull android.net.ipsec.ike.IkeIdentification);
+ method @NonNull public android.net.ipsec.ike.IkeSessionParams.Builder setRemoteIdentification(@NonNull android.net.ipsec.ike.IkeIdentification);
+ method @NonNull public android.net.ipsec.ike.IkeSessionParams.Builder setServerAddress(@NonNull java.net.InetAddress);
+ method @NonNull public android.net.ipsec.ike.IkeSessionParams.Builder setUdpEncapsulationSocket(@NonNull android.net.IpSecManager.UdpEncapsulationSocket);
}
public final class IkeTrafficSelector {
@@ -4851,33 +4883,33 @@ package android.net.ipsec.ike {
field public static final int PSEUDORANDOM_FUNCTION_HMAC_SHA1 = 2; // 0x2
}
- public final class TransportModeChildSessionOptions extends android.net.ipsec.ike.ChildSessionOptions {
+ public final class TransportModeChildSessionParams extends android.net.ipsec.ike.ChildSessionParams {
}
- public static final class TransportModeChildSessionOptions.Builder {
- ctor public TransportModeChildSessionOptions.Builder();
- method @NonNull public android.net.ipsec.ike.TransportModeChildSessionOptions.Builder addInboundTrafficSelectors(@NonNull android.net.ipsec.ike.IkeTrafficSelector);
- method @NonNull public android.net.ipsec.ike.TransportModeChildSessionOptions.Builder addOutboundTrafficSelectors(@NonNull android.net.ipsec.ike.IkeTrafficSelector);
- method @NonNull public android.net.ipsec.ike.TransportModeChildSessionOptions.Builder addSaProposal(@NonNull android.net.ipsec.ike.ChildSaProposal);
- method @NonNull public android.net.ipsec.ike.TransportModeChildSessionOptions build();
+ public static final class TransportModeChildSessionParams.Builder {
+ ctor public TransportModeChildSessionParams.Builder();
+ method @NonNull public android.net.ipsec.ike.TransportModeChildSessionParams.Builder addInboundTrafficSelectors(@NonNull android.net.ipsec.ike.IkeTrafficSelector);
+ method @NonNull public android.net.ipsec.ike.TransportModeChildSessionParams.Builder addOutboundTrafficSelectors(@NonNull android.net.ipsec.ike.IkeTrafficSelector);
+ method @NonNull public android.net.ipsec.ike.TransportModeChildSessionParams.Builder addSaProposal(@NonNull android.net.ipsec.ike.ChildSaProposal);
+ method @NonNull public android.net.ipsec.ike.TransportModeChildSessionParams build();
}
- public final class TunnelModeChildSessionOptions extends android.net.ipsec.ike.ChildSessionOptions {
+ public final class TunnelModeChildSessionParams extends android.net.ipsec.ike.ChildSessionParams {
}
- public static final class TunnelModeChildSessionOptions.Builder {
- ctor public TunnelModeChildSessionOptions.Builder();
- method @NonNull public android.net.ipsec.ike.TunnelModeChildSessionOptions.Builder addInboundTrafficSelectors(@NonNull android.net.ipsec.ike.IkeTrafficSelector);
- method @NonNull public android.net.ipsec.ike.TunnelModeChildSessionOptions.Builder addInternalAddressRequest(int);
- method @NonNull public android.net.ipsec.ike.TunnelModeChildSessionOptions.Builder addInternalAddressRequest(@NonNull java.net.InetAddress, int);
- method @NonNull public android.net.ipsec.ike.TunnelModeChildSessionOptions.Builder addInternalDhcpServerRequest(int);
- method @NonNull public android.net.ipsec.ike.TunnelModeChildSessionOptions.Builder addInternalDhcpServerRequest(@NonNull java.net.InetAddress);
- method @NonNull public android.net.ipsec.ike.TunnelModeChildSessionOptions.Builder addInternalDnsServerRequest(int);
- method @NonNull public android.net.ipsec.ike.TunnelModeChildSessionOptions.Builder addInternalDnsServerRequest(@NonNull java.net.InetAddress);
- method @NonNull public android.net.ipsec.ike.TunnelModeChildSessionOptions.Builder addInternalSubnetRequest(int);
- method @NonNull public android.net.ipsec.ike.TunnelModeChildSessionOptions.Builder addOutboundTrafficSelectors(@NonNull android.net.ipsec.ike.IkeTrafficSelector);
- method @NonNull public android.net.ipsec.ike.TunnelModeChildSessionOptions.Builder addSaProposal(@NonNull android.net.ipsec.ike.ChildSaProposal);
- method @NonNull public android.net.ipsec.ike.TunnelModeChildSessionOptions build();
+ public static final class TunnelModeChildSessionParams.Builder {
+ ctor public TunnelModeChildSessionParams.Builder();
+ method @NonNull public android.net.ipsec.ike.TunnelModeChildSessionParams.Builder addInboundTrafficSelectors(@NonNull android.net.ipsec.ike.IkeTrafficSelector);
+ method @NonNull public android.net.ipsec.ike.TunnelModeChildSessionParams.Builder addInternalAddressRequest(int);
+ method @NonNull public android.net.ipsec.ike.TunnelModeChildSessionParams.Builder addInternalAddressRequest(@NonNull java.net.InetAddress, int);
+ method @NonNull public android.net.ipsec.ike.TunnelModeChildSessionParams.Builder addInternalDhcpServerRequest(int);
+ method @NonNull public android.net.ipsec.ike.TunnelModeChildSessionParams.Builder addInternalDhcpServerRequest(@NonNull java.net.InetAddress);
+ method @NonNull public android.net.ipsec.ike.TunnelModeChildSessionParams.Builder addInternalDnsServerRequest(int);
+ method @NonNull public android.net.ipsec.ike.TunnelModeChildSessionParams.Builder addInternalDnsServerRequest(@NonNull java.net.InetAddress);
+ method @NonNull public android.net.ipsec.ike.TunnelModeChildSessionParams.Builder addInternalSubnetRequest(int);
+ method @NonNull public android.net.ipsec.ike.TunnelModeChildSessionParams.Builder addOutboundTrafficSelectors(@NonNull android.net.ipsec.ike.IkeTrafficSelector);
+ method @NonNull public android.net.ipsec.ike.TunnelModeChildSessionParams.Builder addSaProposal(@NonNull android.net.ipsec.ike.ChildSaProposal);
+ method @NonNull public android.net.ipsec.ike.TunnelModeChildSessionParams build();
}
}
@@ -6718,6 +6750,8 @@ package android.permission {
public final class PermissionManager {
method @IntRange(from=0) @RequiresPermission(android.Manifest.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY) public int getRuntimePermissionsVersion();
method @NonNull public java.util.List<android.permission.PermissionManager.SplitPermissionInfo> getSplitPermissions();
+ method @RequiresPermission(android.Manifest.permission.GRANT_RUNTIME_PERMISSIONS_TO_TELEPHONY_DEFAULTS) public void grantDefaultPermissionsToLuiApp(@NonNull String, @NonNull android.os.UserHandle, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Boolean>);
+ method @RequiresPermission(android.Manifest.permission.GRANT_RUNTIME_PERMISSIONS_TO_TELEPHONY_DEFAULTS) public void revokeDefaultPermissionsFromLuiApps(@NonNull String[], @NonNull android.os.UserHandle, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Boolean>);
method @RequiresPermission(android.Manifest.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY) public void setRuntimePermissionsVersion(@IntRange(from=0) int);
}
@@ -7078,6 +7112,8 @@ package android.provider {
field public static final String DEVICE_DEMO_MODE = "device_demo_mode";
field public static final String DEVICE_PROVISIONING_MOBILE_DATA_ENABLED = "device_provisioning_mobile_data";
field public static final String EUICC_PROVISIONED = "euicc_provisioned";
+ field public static final String EUICC_SUPPORTED_COUNTRIES = "euicc_supported_countries";
+ field public static final String EUICC_UNSUPPORTED_COUNTRIES = "euicc_unsupported_countries";
field public static final String INSTALL_CARRIER_APP_NOTIFICATION_PERSISTENT = "install_carrier_app_notification_persistent";
field public static final String INSTALL_CARRIER_APP_NOTIFICATION_SLEEP_MILLIS = "install_carrier_app_notification_sleep_millis";
field public static final String OTA_DISABLE_AUTOMATIC_UPDATE = "ota_disable_automatic_update";
diff --git a/api/test-lint-baseline.txt b/api/test-lint-baseline.txt
index 3aa8187c0a79..a8c4db38c841 100644
--- a/api/test-lint-baseline.txt
+++ b/api/test-lint-baseline.txt
@@ -8,35 +8,35 @@ AcronymName: android.app.NotificationChannel#setImportanceLockedByOEM(boolean):
ActionValue: android.location.Location#EXTRA_NO_GPS_LOCATION:
ActionValue: android.telephony.ims.ImsCallProfile#EXTRA_ADDITIONAL_CALL_INFO:
- Inconsistent extra value; expected `android.telephony.ims.extra.ADDITIONAL_CALL_INFO`, was `AdditionalCallInfo`
+
ActionValue: android.telephony.ims.ImsCallProfile#EXTRA_CALL_RAT_TYPE:
- Inconsistent extra value; expected `android.telephony.ims.extra.CALL_RAT_TYPE`, was `CallRadioTech`
+
ActionValue: android.telephony.ims.ImsCallProfile#EXTRA_CHILD_NUMBER:
- Inconsistent extra value; expected `android.telephony.ims.extra.CHILD_NUMBER`, was `ChildNum`
+
ActionValue: android.telephony.ims.ImsCallProfile#EXTRA_CNA:
- Inconsistent extra value; expected `android.telephony.ims.extra.CNA`, was `cna`
+
ActionValue: android.telephony.ims.ImsCallProfile#EXTRA_CNAP:
- Inconsistent extra value; expected `android.telephony.ims.extra.CNAP`, was `cnap`
+
ActionValue: android.telephony.ims.ImsCallProfile#EXTRA_CODEC:
- Inconsistent extra value; expected `android.telephony.ims.extra.CODEC`, was `Codec`
+
ActionValue: android.telephony.ims.ImsCallProfile#EXTRA_DIALSTRING:
- Inconsistent extra value; expected `android.telephony.ims.extra.DIALSTRING`, was `dialstring`
+
ActionValue: android.telephony.ims.ImsCallProfile#EXTRA_DISPLAY_TEXT:
- Inconsistent extra value; expected `android.telephony.ims.extra.DISPLAY_TEXT`, was `DisplayText`
+
ActionValue: android.telephony.ims.ImsCallProfile#EXTRA_EMERGENCY_CALL:
- Inconsistent extra value; expected `android.telephony.ims.extra.EMERGENCY_CALL`, was `e_call`
+
ActionValue: android.telephony.ims.ImsCallProfile#EXTRA_IS_CALL_PULL:
- Inconsistent extra value; expected `android.telephony.ims.extra.IS_CALL_PULL`, was `CallPull`
+
ActionValue: android.telephony.ims.ImsCallProfile#EXTRA_OI:
- Inconsistent extra value; expected `android.telephony.ims.extra.OI`, was `oi`
+
ActionValue: android.telephony.ims.ImsCallProfile#EXTRA_OIR:
- Inconsistent extra value; expected `android.telephony.ims.extra.OIR`, was `oir`
+
ActionValue: android.telephony.ims.ImsCallProfile#EXTRA_REMOTE_URI:
- Inconsistent extra value; expected `android.telephony.ims.extra.REMOTE_URI`, was `remote_uri`
+
ActionValue: android.telephony.ims.ImsCallProfile#EXTRA_USSD:
- Inconsistent extra value; expected `android.telephony.ims.extra.USSD`, was `ussd`
+
ActionValue: android.telephony.ims.ImsReasonInfo#EXTRA_MSG_SERVICE_NOT_AUTHORIZED:
- Inconsistent extra value; expected `android.telephony.ims.extra.MSG_SERVICE_NOT_AUTHORIZED`, was `Forbidden. Not Authorized for Service`
+
ActionValue: android.telephony.mbms.vendor.VendorUtils#ACTION_CLEANUP:
ActionValue: android.telephony.mbms.vendor.VendorUtils#ACTION_DOWNLOAD_RESULT_INTERNAL:
@@ -100,13 +100,13 @@ ArrayReturn: android.os.NativeHandle#getFileDescriptors():
ArrayReturn: android.security.keystore.AttestationUtils#attestDeviceIds(android.content.Context, int[], byte[]):
ArrayReturn: android.telephony.ims.ImsUtListener#onUtConfigurationCallBarringQueried(int, android.telephony.ims.ImsSsInfo[]) parameter #1:
- Method parameter should be Collection<ImsSsInfo> (or subclass) instead of raw array; was `android.telephony.ims.ImsSsInfo[]`
+
ArrayReturn: android.telephony.ims.ImsUtListener#onUtConfigurationCallForwardQueried(int, android.telephony.ims.ImsCallForwardInfo[]) parameter #1:
- Method parameter should be Collection<ImsCallForwardInfo> (or subclass) instead of raw array; was `android.telephony.ims.ImsCallForwardInfo[]`
+
ArrayReturn: android.telephony.ims.ImsUtListener#onUtConfigurationCallWaitingQueried(int, android.telephony.ims.ImsSsInfo[]) parameter #1:
- Method parameter should be Collection<ImsSsInfo> (or subclass) instead of raw array; was `android.telephony.ims.ImsSsInfo[]`
+
ArrayReturn: android.telephony.ims.stub.ImsRegistrationImplBase#onSubscriberAssociatedUriChanged(android.net.Uri[]) parameter #0:
- Method parameter should be Collection<Uri> (or subclass) instead of raw array; was `android.net.Uri[]`
+
ArrayReturn: android.view.FocusFinder#sort(android.view.View[], int, int, android.view.ViewGroup, boolean) parameter #0:
ArrayReturn: android.view.contentcapture.ViewNode#getAutofillOptions():
@@ -268,7 +268,7 @@ ConcreteCollection: android.service.autofill.InternalTransformation#batchApply(a
ConcreteCollection: android.service.autofill.UserData#getFieldClassificationAlgorithms():
ConcreteCollection: android.telephony.ims.ImsConferenceState#mParticipants:
- Field type is concrete collection (`java.util.HashMap`); must be higher-level interface
+
ContextFirst: android.os.VibrationEffect#get(android.net.Uri, android.content.Context) parameter #1:
@@ -338,9 +338,9 @@ ExecutorRegistration: android.os.RemoteCallback#RemoteCallback(android.os.Remote
ExecutorRegistration: android.permission.PermissionControllerManager#getAppPermissions(String, android.permission.PermissionControllerManager.OnGetAppPermissionResultCallback, android.os.Handler):
ExecutorRegistration: android.telephony.ims.stub.ImsCallSessionImplBase#setListener(android.telephony.ims.ImsCallSessionListener):
- Registration methods should have overload that accepts delivery Executor: `setListener`
+
ExecutorRegistration: android.telephony.ims.stub.ImsUtImplBase#setListener(android.telephony.ims.ImsUtListener):
- Registration methods should have overload that accepts delivery Executor: `setListener`
+
ExecutorRegistration: android.telephony.mbms.vendor.MbmsDownloadServiceBase#addProgressListener(android.telephony.mbms.DownloadRequest, android.telephony.mbms.DownloadProgressListener):
ExecutorRegistration: android.telephony.mbms.vendor.MbmsDownloadServiceBase#addStatusListener(android.telephony.mbms.DownloadRequest, android.telephony.mbms.DownloadStatusListener):
@@ -460,11 +460,13 @@ InterfaceConstant: android.telecom.PhoneAccountSuggestionService#SERVICE_INTERFA
InternalField: android.telephony.ims.ImsConferenceState#mParticipants:
- Internal field mParticipants must not be exposed
+
KotlinOperator: android.os.WorkSource#get(int):
+KotlinOperator: android.util.SparseArrayMap#get(int, String):
+ Method can be invoked with an indexing operator from Kotlin: `get` (this is usually desirable; just make sure it makes sense for this type of object)
ListenerInterface: android.media.audiopolicy.AudioPolicy.AudioPolicyFocusListener:
@@ -474,9 +476,9 @@ ListenerInterface: android.media.audiopolicy.AudioPolicy.AudioPolicyStatusListen
ListenerInterface: android.os.IncidentManager.AuthListener:
ListenerInterface: android.telephony.ims.ImsCallSessionListener:
- Listeners should be an interface, or otherwise renamed Callback: ImsCallSessionListener
+
ListenerInterface: android.telephony.ims.ImsUtListener:
- Listeners should be an interface, or otherwise renamed Callback: ImsUtListener
+
ListenerLast: android.hardware.camera2.CameraDevice#createCustomCaptureSession(android.hardware.camera2.params.InputConfiguration, java.util.List<android.hardware.camera2.params.OutputConfiguration>, int, android.hardware.camera2.CameraCaptureSession.StateCallback, android.os.Handler) parameter #4:
@@ -496,17 +498,17 @@ ManagerConstructor: android.content.pm.ShortcutManager#ShortcutManager(android.c
ManagerLookup: android.telephony.ims.ImsMmTelManager#createForSubscriptionId(int):
- Managers must always be obtained from Context (`createForSubscriptionId`)
+
ManagerLookup: android.telephony.ims.ProvisioningManager#createForSubscriptionId(int):
- Managers must always be obtained from Context (`createForSubscriptionId`)
+
MethodNameTense: android.telephony.ims.feature.CapabilityChangeRequest#getCapabilitiesToEnable():
- Unexpected tense; probably meant `enabled`, was `getCapabilitiesToEnable`
+
MethodNameUnits: android.telephony.ims.ImsCallForwardInfo#getTimeSeconds():
- Returned time values must be in milliseconds, was `getTimeSeconds`
+
MinMaxConstant: android.os.UserHandle#MIN_SECONDARY_USER_ID:
@@ -1460,7 +1462,7 @@ MissingNullability: android.telecom.PhoneAccountSuggestionService#onBind(android
MissingNullability: android.telecom.PhoneAccountSuggestionService#onBind(android.content.Intent) parameter #0:
MissingNullability: android.telephony.CallQuality#writeToParcel(android.os.Parcel, int) parameter #0:
- Missing nullability on parameter `dest` in method `writeToParcel`
+
MissingNullability: android.telephony.DataSpecificRegistrationInfo#writeToParcel(android.os.Parcel, int) parameter #0:
MissingNullability: android.telephony.LteVopsSupportInfo#writeToParcel(android.os.Parcel, int) parameter #0:
@@ -1478,9 +1480,9 @@ MissingNullability: android.telephony.SmsManager#checkSmsShortCodeDestination(St
MissingNullability: android.telephony.TelephonyManager#checkCarrierPrivilegesForPackage(String) parameter #0:
MissingNullability: android.telephony.TelephonyManager#getCarrierPackageNamesForIntent(android.content.Intent):
- Missing nullability on method `getCarrierPackageNamesForIntent` return
+
MissingNullability: android.telephony.TelephonyManager#getCarrierPackageNamesForIntent(android.content.Intent) parameter #0:
- Missing nullability on parameter `intent` in method `getCarrierPackageNamesForIntent`
+
MissingNullability: android.telephony.TelephonyManager#getLine1AlphaTag():
MissingNullability: android.telephony.TelephonyManager#getRadioHalVersion():
@@ -1518,315 +1520,315 @@ MissingNullability: android.telephony.TelephonyManager#setCarrierTestOverride(St
MissingNullability: android.telephony.TelephonyManager#setCarrierTestOverride(String, String, String, String, String, String, String, String, String) parameter #8:
MissingNullability: android.telephony.ims.ImsCallForwardInfo#getNumber():
- Missing nullability on method `getNumber` return
+
MissingNullability: android.telephony.ims.ImsCallForwardInfo#writeToParcel(android.os.Parcel, int) parameter #0:
- Missing nullability on parameter `out` in method `writeToParcel`
+
MissingNullability: android.telephony.ims.ImsCallProfile#ImsCallProfile(int, int, android.os.Bundle, android.telephony.ims.ImsStreamMediaProfile) parameter #2:
- Missing nullability on parameter `callExtras` in method `ImsCallProfile`
+
MissingNullability: android.telephony.ims.ImsCallProfile#ImsCallProfile(int, int, android.os.Bundle, android.telephony.ims.ImsStreamMediaProfile) parameter #3:
- Missing nullability on parameter `mediaProfile` in method `ImsCallProfile`
+
MissingNullability: android.telephony.ims.ImsCallProfile#getCallExtra(String):
- Missing nullability on method `getCallExtra` return
+
MissingNullability: android.telephony.ims.ImsCallProfile#getCallExtra(String) parameter #0:
- Missing nullability on parameter `name` in method `getCallExtra`
+
MissingNullability: android.telephony.ims.ImsCallProfile#getCallExtra(String, String):
- Missing nullability on method `getCallExtra` return
+
MissingNullability: android.telephony.ims.ImsCallProfile#getCallExtra(String, String) parameter #0:
- Missing nullability on parameter `name` in method `getCallExtra`
+
MissingNullability: android.telephony.ims.ImsCallProfile#getCallExtra(String, String) parameter #1:
- Missing nullability on parameter `defaultValue` in method `getCallExtra`
+
MissingNullability: android.telephony.ims.ImsCallProfile#getCallExtraBoolean(String) parameter #0:
- Missing nullability on parameter `name` in method `getCallExtraBoolean`
+
MissingNullability: android.telephony.ims.ImsCallProfile#getCallExtraBoolean(String, boolean) parameter #0:
- Missing nullability on parameter `name` in method `getCallExtraBoolean`
+
MissingNullability: android.telephony.ims.ImsCallProfile#getCallExtraInt(String) parameter #0:
- Missing nullability on parameter `name` in method `getCallExtraInt`
+
MissingNullability: android.telephony.ims.ImsCallProfile#getCallExtraInt(String, int) parameter #0:
- Missing nullability on parameter `name` in method `getCallExtraInt`
+
MissingNullability: android.telephony.ims.ImsCallProfile#getCallExtras():
- Missing nullability on method `getCallExtras` return
+
MissingNullability: android.telephony.ims.ImsCallProfile#getMediaProfile():
- Missing nullability on method `getMediaProfile` return
+
MissingNullability: android.telephony.ims.ImsCallProfile#getVideoStateFromImsCallProfile(android.telephony.ims.ImsCallProfile) parameter #0:
- Missing nullability on parameter `callProfile` in method `getVideoStateFromImsCallProfile`
+
MissingNullability: android.telephony.ims.ImsCallProfile#setCallExtra(String, String) parameter #0:
- Missing nullability on parameter `name` in method `setCallExtra`
+
MissingNullability: android.telephony.ims.ImsCallProfile#setCallExtra(String, String) parameter #1:
- Missing nullability on parameter `value` in method `setCallExtra`
+
MissingNullability: android.telephony.ims.ImsCallProfile#setCallExtraBoolean(String, boolean) parameter #0:
- Missing nullability on parameter `name` in method `setCallExtraBoolean`
+
MissingNullability: android.telephony.ims.ImsCallProfile#setCallExtraInt(String, int) parameter #0:
- Missing nullability on parameter `name` in method `setCallExtraInt`
+
MissingNullability: android.telephony.ims.ImsCallProfile#updateCallExtras(android.telephony.ims.ImsCallProfile) parameter #0:
- Missing nullability on parameter `profile` in method `updateCallExtras`
+
MissingNullability: android.telephony.ims.ImsCallProfile#updateCallType(android.telephony.ims.ImsCallProfile) parameter #0:
- Missing nullability on parameter `profile` in method `updateCallType`
+
MissingNullability: android.telephony.ims.ImsCallProfile#updateMediaProfile(android.telephony.ims.ImsCallProfile) parameter #0:
- Missing nullability on parameter `profile` in method `updateMediaProfile`
+
MissingNullability: android.telephony.ims.ImsCallProfile#writeToParcel(android.os.Parcel, int) parameter #0:
- Missing nullability on parameter `out` in method `writeToParcel`
+
MissingNullability: android.telephony.ims.ImsCallSessionListener#callSessionConferenceExtendFailed(android.telephony.ims.ImsReasonInfo) parameter #0:
- Missing nullability on parameter `reasonInfo` in method `callSessionConferenceExtendFailed`
+
MissingNullability: android.telephony.ims.ImsCallSessionListener#callSessionConferenceExtendReceived(android.telephony.ims.stub.ImsCallSessionImplBase, android.telephony.ims.ImsCallProfile) parameter #0:
- Missing nullability on parameter `newSession` in method `callSessionConferenceExtendReceived`
+
MissingNullability: android.telephony.ims.ImsCallSessionListener#callSessionConferenceExtendReceived(android.telephony.ims.stub.ImsCallSessionImplBase, android.telephony.ims.ImsCallProfile) parameter #1:
- Missing nullability on parameter `profile` in method `callSessionConferenceExtendReceived`
+
MissingNullability: android.telephony.ims.ImsCallSessionListener#callSessionConferenceExtended(android.telephony.ims.stub.ImsCallSessionImplBase, android.telephony.ims.ImsCallProfile) parameter #0:
- Missing nullability on parameter `newSession` in method `callSessionConferenceExtended`
+
MissingNullability: android.telephony.ims.ImsCallSessionListener#callSessionConferenceExtended(android.telephony.ims.stub.ImsCallSessionImplBase, android.telephony.ims.ImsCallProfile) parameter #1:
- Missing nullability on parameter `profile` in method `callSessionConferenceExtended`
+
MissingNullability: android.telephony.ims.ImsCallSessionListener#callSessionConferenceStateUpdated(android.telephony.ims.ImsConferenceState) parameter #0:
- Missing nullability on parameter `state` in method `callSessionConferenceStateUpdated`
+
MissingNullability: android.telephony.ims.ImsCallSessionListener#callSessionHandover(int, int, android.telephony.ims.ImsReasonInfo) parameter #2:
- Missing nullability on parameter `reasonInfo` in method `callSessionHandover`
+
MissingNullability: android.telephony.ims.ImsCallSessionListener#callSessionHandoverFailed(int, int, android.telephony.ims.ImsReasonInfo) parameter #2:
- Missing nullability on parameter `reasonInfo` in method `callSessionHandoverFailed`
+
MissingNullability: android.telephony.ims.ImsCallSessionListener#callSessionHeld(android.telephony.ims.ImsCallProfile) parameter #0:
- Missing nullability on parameter `profile` in method `callSessionHeld`
+
MissingNullability: android.telephony.ims.ImsCallSessionListener#callSessionHoldFailed(android.telephony.ims.ImsReasonInfo) parameter #0:
- Missing nullability on parameter `reasonInfo` in method `callSessionHoldFailed`
+
MissingNullability: android.telephony.ims.ImsCallSessionListener#callSessionHoldReceived(android.telephony.ims.ImsCallProfile) parameter #0:
- Missing nullability on parameter `profile` in method `callSessionHoldReceived`
+
MissingNullability: android.telephony.ims.ImsCallSessionListener#callSessionInitiated(android.telephony.ims.ImsCallProfile) parameter #0:
- Missing nullability on parameter `profile` in method `callSessionInitiated`
+
MissingNullability: android.telephony.ims.ImsCallSessionListener#callSessionInitiatedFailed(android.telephony.ims.ImsReasonInfo) parameter #0:
- Missing nullability on parameter `reasonInfo` in method `callSessionInitiatedFailed`
+
MissingNullability: android.telephony.ims.ImsCallSessionListener#callSessionInviteParticipantsRequestFailed(android.telephony.ims.ImsReasonInfo) parameter #0:
- Missing nullability on parameter `reasonInfo` in method `callSessionInviteParticipantsRequestFailed`
+
MissingNullability: android.telephony.ims.ImsCallSessionListener#callSessionMergeComplete(android.telephony.ims.stub.ImsCallSessionImplBase) parameter #0:
- Missing nullability on parameter `newSession` in method `callSessionMergeComplete`
+
MissingNullability: android.telephony.ims.ImsCallSessionListener#callSessionMergeFailed(android.telephony.ims.ImsReasonInfo) parameter #0:
- Missing nullability on parameter `reasonInfo` in method `callSessionMergeFailed`
+
MissingNullability: android.telephony.ims.ImsCallSessionListener#callSessionMergeStarted(android.telephony.ims.stub.ImsCallSessionImplBase, android.telephony.ims.ImsCallProfile) parameter #0:
- Missing nullability on parameter `newSession` in method `callSessionMergeStarted`
+
MissingNullability: android.telephony.ims.ImsCallSessionListener#callSessionMergeStarted(android.telephony.ims.stub.ImsCallSessionImplBase, android.telephony.ims.ImsCallProfile) parameter #1:
- Missing nullability on parameter `profile` in method `callSessionMergeStarted`
+
MissingNullability: android.telephony.ims.ImsCallSessionListener#callSessionProgressing(android.telephony.ims.ImsStreamMediaProfile) parameter #0:
- Missing nullability on parameter `profile` in method `callSessionProgressing`
+
MissingNullability: android.telephony.ims.ImsCallSessionListener#callSessionRemoveParticipantsRequestFailed(android.telephony.ims.ImsReasonInfo) parameter #0:
- Missing nullability on parameter `reasonInfo` in method `callSessionRemoveParticipantsRequestFailed`
+
MissingNullability: android.telephony.ims.ImsCallSessionListener#callSessionResumeFailed(android.telephony.ims.ImsReasonInfo) parameter #0:
- Missing nullability on parameter `reasonInfo` in method `callSessionResumeFailed`
+
MissingNullability: android.telephony.ims.ImsCallSessionListener#callSessionResumeReceived(android.telephony.ims.ImsCallProfile) parameter #0:
- Missing nullability on parameter `profile` in method `callSessionResumeReceived`
+
MissingNullability: android.telephony.ims.ImsCallSessionListener#callSessionResumed(android.telephony.ims.ImsCallProfile) parameter #0:
- Missing nullability on parameter `profile` in method `callSessionResumed`
+
MissingNullability: android.telephony.ims.ImsCallSessionListener#callSessionRttMessageReceived(String) parameter #0:
- Missing nullability on parameter `rttMessage` in method `callSessionRttMessageReceived`
+
MissingNullability: android.telephony.ims.ImsCallSessionListener#callSessionRttModifyRequestReceived(android.telephony.ims.ImsCallProfile) parameter #0:
- Missing nullability on parameter `callProfile` in method `callSessionRttModifyRequestReceived`
+
MissingNullability: android.telephony.ims.ImsCallSessionListener#callSessionSuppServiceReceived(android.telephony.ims.ImsSuppServiceNotification) parameter #0:
- Missing nullability on parameter `suppSrvNotification` in method `callSessionSuppServiceReceived`
+
MissingNullability: android.telephony.ims.ImsCallSessionListener#callSessionTerminated(android.telephony.ims.ImsReasonInfo) parameter #0:
- Missing nullability on parameter `reasonInfo` in method `callSessionTerminated`
+
MissingNullability: android.telephony.ims.ImsCallSessionListener#callSessionUpdateFailed(android.telephony.ims.ImsReasonInfo) parameter #0:
- Missing nullability on parameter `reasonInfo` in method `callSessionUpdateFailed`
+
MissingNullability: android.telephony.ims.ImsCallSessionListener#callSessionUpdateReceived(android.telephony.ims.ImsCallProfile) parameter #0:
- Missing nullability on parameter `profile` in method `callSessionUpdateReceived`
+
MissingNullability: android.telephony.ims.ImsCallSessionListener#callSessionUpdated(android.telephony.ims.ImsCallProfile) parameter #0:
- Missing nullability on parameter `profile` in method `callSessionUpdated`
+
MissingNullability: android.telephony.ims.ImsCallSessionListener#callSessionUssdMessageReceived(int, String) parameter #1:
- Missing nullability on parameter `ussdMessage` in method `callSessionUssdMessageReceived`
+
MissingNullability: android.telephony.ims.ImsConferenceState#getConnectionStateForStatus(String) parameter #0:
- Missing nullability on parameter `status` in method `getConnectionStateForStatus`
+
MissingNullability: android.telephony.ims.ImsConferenceState#mParticipants:
- Missing nullability on field `mParticipants` in class `class android.telephony.ims.ImsConferenceState`
+
MissingNullability: android.telephony.ims.ImsConferenceState#writeToParcel(android.os.Parcel, int) parameter #0:
- Missing nullability on parameter `out` in method `writeToParcel`
+
MissingNullability: android.telephony.ims.ImsExternalCallState#writeToParcel(android.os.Parcel, int) parameter #0:
- Missing nullability on parameter `out` in method `writeToParcel`
+
MissingNullability: android.telephony.ims.ImsReasonInfo#ImsReasonInfo(int, int, String) parameter #2:
- Missing nullability on parameter `extraMessage` in method `ImsReasonInfo`
+
MissingNullability: android.telephony.ims.ImsReasonInfo#getExtraMessage():
- Missing nullability on method `getExtraMessage` return
+
MissingNullability: android.telephony.ims.ImsReasonInfo#writeToParcel(android.os.Parcel, int) parameter #0:
- Missing nullability on parameter `out` in method `writeToParcel`
+
MissingNullability: android.telephony.ims.ImsService#createMmTelFeature(int):
- Missing nullability on method `createMmTelFeature` return
+
MissingNullability: android.telephony.ims.ImsService#createRcsFeature(int):
- Missing nullability on method `createRcsFeature` return
+
MissingNullability: android.telephony.ims.ImsService#getConfig(int):
- Missing nullability on method `getConfig` return
+
MissingNullability: android.telephony.ims.ImsService#getRegistration(int):
- Missing nullability on method `getRegistration` return
+
MissingNullability: android.telephony.ims.ImsService#onUpdateSupportedImsFeatures(android.telephony.ims.stub.ImsFeatureConfiguration) parameter #0:
- Missing nullability on parameter `c` in method `onUpdateSupportedImsFeatures`
+
MissingNullability: android.telephony.ims.ImsService#querySupportedImsFeatures():
- Missing nullability on method `querySupportedImsFeatures` return
+
MissingNullability: android.telephony.ims.ImsSsData#writeToParcel(android.os.Parcel, int) parameter #0:
- Missing nullability on parameter `out` in method `writeToParcel`
+
MissingNullability: android.telephony.ims.ImsSsInfo#writeToParcel(android.os.Parcel, int) parameter #0:
- Missing nullability on parameter `out` in method `writeToParcel`
+
MissingNullability: android.telephony.ims.ImsStreamMediaProfile#copyFrom(android.telephony.ims.ImsStreamMediaProfile) parameter #0:
- Missing nullability on parameter `profile` in method `copyFrom`
+
MissingNullability: android.telephony.ims.ImsStreamMediaProfile#writeToParcel(android.os.Parcel, int) parameter #0:
- Missing nullability on parameter `out` in method `writeToParcel`
+
MissingNullability: android.telephony.ims.ImsSuppServiceNotification#ImsSuppServiceNotification(int, int, int, int, String, String[]) parameter #4:
- Missing nullability on parameter `number` in method `ImsSuppServiceNotification`
+
MissingNullability: android.telephony.ims.ImsSuppServiceNotification#ImsSuppServiceNotification(int, int, int, int, String, String[]) parameter #5:
- Missing nullability on parameter `history` in method `ImsSuppServiceNotification`
+
MissingNullability: android.telephony.ims.ImsSuppServiceNotification#history:
- Missing nullability on field `history` in class `class android.telephony.ims.ImsSuppServiceNotification`
+
MissingNullability: android.telephony.ims.ImsSuppServiceNotification#number:
- Missing nullability on field `number` in class `class android.telephony.ims.ImsSuppServiceNotification`
+
MissingNullability: android.telephony.ims.ImsSuppServiceNotification#writeToParcel(android.os.Parcel, int) parameter #0:
- Missing nullability on parameter `out` in method `writeToParcel`
+
MissingNullability: android.telephony.ims.ImsUtListener#onSupplementaryServiceIndication(android.telephony.ims.ImsSsData) parameter #0:
- Missing nullability on parameter `ssData` in method `onSupplementaryServiceIndication`
+
MissingNullability: android.telephony.ims.ImsUtListener#onUtConfigurationCallBarringQueried(int, android.telephony.ims.ImsSsInfo[]) parameter #1:
- Missing nullability on parameter `cbInfo` in method `onUtConfigurationCallBarringQueried`
+
MissingNullability: android.telephony.ims.ImsUtListener#onUtConfigurationCallForwardQueried(int, android.telephony.ims.ImsCallForwardInfo[]) parameter #1:
- Missing nullability on parameter `cfInfo` in method `onUtConfigurationCallForwardQueried`
+
MissingNullability: android.telephony.ims.ImsUtListener#onUtConfigurationCallWaitingQueried(int, android.telephony.ims.ImsSsInfo[]) parameter #1:
- Missing nullability on parameter `cwInfo` in method `onUtConfigurationCallWaitingQueried`
+
MissingNullability: android.telephony.ims.ImsUtListener#onUtConfigurationQueried(int, android.os.Bundle) parameter #1:
- Missing nullability on parameter `configuration` in method `onUtConfigurationQueried`
+
MissingNullability: android.telephony.ims.ImsUtListener#onUtConfigurationQueryFailed(int, android.telephony.ims.ImsReasonInfo) parameter #1:
- Missing nullability on parameter `error` in method `onUtConfigurationQueryFailed`
+
MissingNullability: android.telephony.ims.ImsUtListener#onUtConfigurationUpdateFailed(int, android.telephony.ims.ImsReasonInfo) parameter #1:
- Missing nullability on parameter `error` in method `onUtConfigurationUpdateFailed`
+
MissingNullability: android.telephony.ims.ImsVideoCallProvider#changeCameraCapabilities(android.telecom.VideoProfile.CameraCapabilities) parameter #0:
- Missing nullability on parameter `CameraCapabilities` in method `changeCameraCapabilities`
+
MissingNullability: android.telephony.ims.ImsVideoCallProvider#onSendSessionModifyRequest(android.telecom.VideoProfile, android.telecom.VideoProfile) parameter #0:
- Missing nullability on parameter `fromProfile` in method `onSendSessionModifyRequest`
+
MissingNullability: android.telephony.ims.ImsVideoCallProvider#onSendSessionModifyRequest(android.telecom.VideoProfile, android.telecom.VideoProfile) parameter #1:
- Missing nullability on parameter `toProfile` in method `onSendSessionModifyRequest`
+
MissingNullability: android.telephony.ims.ImsVideoCallProvider#onSendSessionModifyResponse(android.telecom.VideoProfile) parameter #0:
- Missing nullability on parameter `responseProfile` in method `onSendSessionModifyResponse`
+
MissingNullability: android.telephony.ims.ImsVideoCallProvider#onSetCamera(String) parameter #0:
- Missing nullability on parameter `cameraId` in method `onSetCamera`
+
MissingNullability: android.telephony.ims.ImsVideoCallProvider#onSetCamera(String, int) parameter #0:
- Missing nullability on parameter `cameraId` in method `onSetCamera`
+
MissingNullability: android.telephony.ims.ImsVideoCallProvider#onSetDisplaySurface(android.view.Surface) parameter #0:
- Missing nullability on parameter `surface` in method `onSetDisplaySurface`
+
MissingNullability: android.telephony.ims.ImsVideoCallProvider#onSetPauseImage(android.net.Uri) parameter #0:
- Missing nullability on parameter `uri` in method `onSetPauseImage`
+
MissingNullability: android.telephony.ims.ImsVideoCallProvider#onSetPreviewSurface(android.view.Surface) parameter #0:
- Missing nullability on parameter `surface` in method `onSetPreviewSurface`
+
MissingNullability: android.telephony.ims.ImsVideoCallProvider#receiveSessionModifyRequest(android.telecom.VideoProfile) parameter #0:
- Missing nullability on parameter `VideoProfile` in method `receiveSessionModifyRequest`
+
MissingNullability: android.telephony.ims.ImsVideoCallProvider#receiveSessionModifyResponse(int, android.telecom.VideoProfile, android.telecom.VideoProfile) parameter #1:
- Missing nullability on parameter `requestedProfile` in method `receiveSessionModifyResponse`
+
MissingNullability: android.telephony.ims.ImsVideoCallProvider#receiveSessionModifyResponse(int, android.telecom.VideoProfile, android.telecom.VideoProfile) parameter #2:
- Missing nullability on parameter `responseProfile` in method `receiveSessionModifyResponse`
+
MissingNullability: android.telephony.ims.feature.CapabilityChangeRequest#getCapabilitiesToDisable():
- Missing nullability on method `getCapabilitiesToDisable` return
+
MissingNullability: android.telephony.ims.feature.CapabilityChangeRequest#getCapabilitiesToEnable():
- Missing nullability on method `getCapabilitiesToEnable` return
+
MissingNullability: android.telephony.ims.feature.CapabilityChangeRequest#writeToParcel(android.os.Parcel, int) parameter #0:
- Missing nullability on parameter `dest` in method `writeToParcel`
+
MissingNullability: android.telephony.ims.feature.ImsFeature#changeEnabledCapabilities(android.telephony.ims.feature.CapabilityChangeRequest, android.telephony.ims.feature.ImsFeature.CapabilityCallbackProxy) parameter #0:
- Missing nullability on parameter `request` in method `changeEnabledCapabilities`
+
MissingNullability: android.telephony.ims.feature.ImsFeature#changeEnabledCapabilities(android.telephony.ims.feature.CapabilityChangeRequest, android.telephony.ims.feature.ImsFeature.CapabilityCallbackProxy) parameter #1:
- Missing nullability on parameter `c` in method `changeEnabledCapabilities`
+
MissingNullability: android.telephony.ims.feature.MmTelFeature#queryCapabilityStatus():
- Missing nullability on method `queryCapabilityStatus` return
+
MissingNullability: android.telephony.ims.feature.MmTelFeature.MmTelCapabilities#MmTelCapabilities(android.telephony.ims.feature.ImsFeature.Capabilities) parameter #0:
- Missing nullability on parameter `c` in method `MmTelCapabilities`
+
MissingNullability: android.telephony.ims.stub.ImsCallSessionImplBase#accept(int, android.telephony.ims.ImsStreamMediaProfile) parameter #1:
- Missing nullability on parameter `profile` in method `accept`
+
MissingNullability: android.telephony.ims.stub.ImsCallSessionImplBase#deflect(String) parameter #0:
- Missing nullability on parameter `deflectNumber` in method `deflect`
+
MissingNullability: android.telephony.ims.stub.ImsCallSessionImplBase#extendToConference(String[]) parameter #0:
- Missing nullability on parameter `participants` in method `extendToConference`
+
MissingNullability: android.telephony.ims.stub.ImsCallSessionImplBase#getCallId():
- Missing nullability on method `getCallId` return
+
MissingNullability: android.telephony.ims.stub.ImsCallSessionImplBase#getCallProfile():
- Missing nullability on method `getCallProfile` return
+
MissingNullability: android.telephony.ims.stub.ImsCallSessionImplBase#getImsVideoCallProvider():
- Missing nullability on method `getImsVideoCallProvider` return
+
MissingNullability: android.telephony.ims.stub.ImsCallSessionImplBase#getLocalCallProfile():
- Missing nullability on method `getLocalCallProfile` return
+
MissingNullability: android.telephony.ims.stub.ImsCallSessionImplBase#getProperty(String):
- Missing nullability on method `getProperty` return
+
MissingNullability: android.telephony.ims.stub.ImsCallSessionImplBase#getProperty(String) parameter #0:
- Missing nullability on parameter `name` in method `getProperty`
+
MissingNullability: android.telephony.ims.stub.ImsCallSessionImplBase#getRemoteCallProfile():
- Missing nullability on method `getRemoteCallProfile` return
+
MissingNullability: android.telephony.ims.stub.ImsCallSessionImplBase#hold(android.telephony.ims.ImsStreamMediaProfile) parameter #0:
- Missing nullability on parameter `profile` in method `hold`
+
MissingNullability: android.telephony.ims.stub.ImsCallSessionImplBase#inviteParticipants(String[]) parameter #0:
- Missing nullability on parameter `participants` in method `inviteParticipants`
+
MissingNullability: android.telephony.ims.stub.ImsCallSessionImplBase#removeParticipants(String[]) parameter #0:
- Missing nullability on parameter `participants` in method `removeParticipants`
+
MissingNullability: android.telephony.ims.stub.ImsCallSessionImplBase#resume(android.telephony.ims.ImsStreamMediaProfile) parameter #0:
- Missing nullability on parameter `profile` in method `resume`
+
MissingNullability: android.telephony.ims.stub.ImsCallSessionImplBase#sendDtmf(char, android.os.Message) parameter #1:
- Missing nullability on parameter `result` in method `sendDtmf`
+
MissingNullability: android.telephony.ims.stub.ImsCallSessionImplBase#sendRttMessage(String) parameter #0:
- Missing nullability on parameter `rttMessage` in method `sendRttMessage`
+
MissingNullability: android.telephony.ims.stub.ImsCallSessionImplBase#sendRttModifyRequest(android.telephony.ims.ImsCallProfile) parameter #0:
- Missing nullability on parameter `toProfile` in method `sendRttModifyRequest`
+
MissingNullability: android.telephony.ims.stub.ImsCallSessionImplBase#sendUssd(String) parameter #0:
- Missing nullability on parameter `ussdMessage` in method `sendUssd`
+
MissingNullability: android.telephony.ims.stub.ImsCallSessionImplBase#setListener(android.telephony.ims.ImsCallSessionListener) parameter #0:
- Missing nullability on parameter `listener` in method `setListener`
+
MissingNullability: android.telephony.ims.stub.ImsCallSessionImplBase#start(String, android.telephony.ims.ImsCallProfile) parameter #0:
- Missing nullability on parameter `callee` in method `start`
+
MissingNullability: android.telephony.ims.stub.ImsCallSessionImplBase#start(String, android.telephony.ims.ImsCallProfile) parameter #1:
- Missing nullability on parameter `profile` in method `start`
+
MissingNullability: android.telephony.ims.stub.ImsCallSessionImplBase#startConference(String[], android.telephony.ims.ImsCallProfile) parameter #0:
- Missing nullability on parameter `participants` in method `startConference`
+
MissingNullability: android.telephony.ims.stub.ImsCallSessionImplBase#startConference(String[], android.telephony.ims.ImsCallProfile) parameter #1:
- Missing nullability on parameter `profile` in method `startConference`
+
MissingNullability: android.telephony.ims.stub.ImsCallSessionImplBase#update(int, android.telephony.ims.ImsStreamMediaProfile) parameter #1:
- Missing nullability on parameter `profile` in method `update`
+
MissingNullability: android.telephony.ims.stub.ImsCallSessionImplBase.State#toString(int):
- Missing nullability on method `toString` return
+
MissingNullability: android.telephony.ims.stub.ImsConfigImplBase#getConfigString(int):
- Missing nullability on method `getConfigString` return
+
MissingNullability: android.telephony.ims.stub.ImsConfigImplBase#notifyProvisionedValueChanged(int, String) parameter #1:
- Missing nullability on parameter `value` in method `notifyProvisionedValueChanged`
+
MissingNullability: android.telephony.ims.stub.ImsConfigImplBase#setConfig(int, String) parameter #1:
- Missing nullability on parameter `value` in method `setConfig`
+
MissingNullability: android.telephony.ims.stub.ImsFeatureConfiguration#getServiceFeatures():
- Missing nullability on method `getServiceFeatures` return
+
MissingNullability: android.telephony.ims.stub.ImsFeatureConfiguration#writeToParcel(android.os.Parcel, int) parameter #0:
- Missing nullability on parameter `dest` in method `writeToParcel`
+
MissingNullability: android.telephony.ims.stub.ImsFeatureConfiguration.Builder#addFeature(int, int):
- Missing nullability on method `addFeature` return
+
MissingNullability: android.telephony.ims.stub.ImsFeatureConfiguration.Builder#build():
- Missing nullability on method `build` return
+
MissingNullability: android.telephony.ims.stub.ImsMultiEndpointImplBase#onImsExternalCallStateUpdate(java.util.List<android.telephony.ims.ImsExternalCallState>) parameter #0:
- Missing nullability on parameter `externalCallDialogs` in method `onImsExternalCallStateUpdate`
+
MissingNullability: android.telephony.ims.stub.ImsRegistrationImplBase#onDeregistered(android.telephony.ims.ImsReasonInfo) parameter #0:
- Missing nullability on parameter `info` in method `onDeregistered`
+
MissingNullability: android.telephony.ims.stub.ImsRegistrationImplBase#onSubscriberAssociatedUriChanged(android.net.Uri[]) parameter #0:
- Missing nullability on parameter `uris` in method `onSubscriberAssociatedUriChanged`
+
MissingNullability: android.telephony.ims.stub.ImsRegistrationImplBase#onTechnologyChangeFailed(int, android.telephony.ims.ImsReasonInfo) parameter #1:
- Missing nullability on parameter `info` in method `onTechnologyChangeFailed`
+
MissingNullability: android.telephony.ims.stub.ImsSmsImplBase#getSmsFormat():
- Missing nullability on method `getSmsFormat` return
+
MissingNullability: android.telephony.ims.stub.ImsSmsImplBase#onSmsReceived(int, String, byte[]) parameter #1:
- Missing nullability on parameter `format` in method `onSmsReceived`
+
MissingNullability: android.telephony.ims.stub.ImsSmsImplBase#onSmsReceived(int, String, byte[]) parameter #2:
- Missing nullability on parameter `pdu` in method `onSmsReceived`
+
MissingNullability: android.telephony.ims.stub.ImsSmsImplBase#onSmsStatusReportReceived(int, String, byte[]) parameter #1:
- Missing nullability on parameter `format` in method `onSmsStatusReportReceived`
+
MissingNullability: android.telephony.ims.stub.ImsSmsImplBase#onSmsStatusReportReceived(int, String, byte[]) parameter #2:
- Missing nullability on parameter `pdu` in method `onSmsStatusReportReceived`
+
MissingNullability: android.telephony.ims.stub.ImsSmsImplBase#onSmsStatusReportReceived(int, int, String, byte[]) parameter #2:
- Missing nullability on parameter `format` in method `onSmsStatusReportReceived`
+
MissingNullability: android.telephony.ims.stub.ImsSmsImplBase#onSmsStatusReportReceived(int, int, String, byte[]) parameter #3:
- Missing nullability on parameter `pdu` in method `onSmsStatusReportReceived`
+
MissingNullability: android.telephony.ims.stub.ImsSmsImplBase#sendSms(int, int, String, String, boolean, byte[]) parameter #2:
- Missing nullability on parameter `format` in method `sendSms`
+
MissingNullability: android.telephony.ims.stub.ImsSmsImplBase#sendSms(int, int, String, String, boolean, byte[]) parameter #3:
- Missing nullability on parameter `smsc` in method `sendSms`
+
MissingNullability: android.telephony.ims.stub.ImsSmsImplBase#sendSms(int, int, String, String, boolean, byte[]) parameter #5:
- Missing nullability on parameter `pdu` in method `sendSms`
+
MissingNullability: android.telephony.ims.stub.ImsUtImplBase#queryCallForward(int, String) parameter #1:
- Missing nullability on parameter `number` in method `queryCallForward`
+
MissingNullability: android.telephony.ims.stub.ImsUtImplBase#setListener(android.telephony.ims.ImsUtListener) parameter #0:
- Missing nullability on parameter `listener` in method `setListener`
+
MissingNullability: android.telephony.ims.stub.ImsUtImplBase#transact(android.os.Bundle) parameter #0:
- Missing nullability on parameter `ssInfo` in method `transact`
+
MissingNullability: android.telephony.ims.stub.ImsUtImplBase#updateCallBarring(int, int, String[]) parameter #2:
- Missing nullability on parameter `barrList` in method `updateCallBarring`
+
MissingNullability: android.telephony.ims.stub.ImsUtImplBase#updateCallBarringForServiceClass(int, int, String[], int) parameter #2:
- Missing nullability on parameter `barrList` in method `updateCallBarringForServiceClass`
+
MissingNullability: android.telephony.ims.stub.ImsUtImplBase#updateCallForward(int, int, String, int, int) parameter #2:
- Missing nullability on parameter `number` in method `updateCallForward`
+
MissingNullability: android.telephony.mbms.DownloadRequest.Builder#setServiceId(String):
MissingNullability: android.telephony.mbms.DownloadRequest.Builder#setServiceId(String) parameter #0:
@@ -2278,7 +2280,7 @@ NotCloseable: android.app.prediction.AppPredictor:
NotCloseable: android.os.HwParcel:
NotCloseable: android.telephony.ims.stub.ImsUtImplBase:
- Classes that release resources (close()) should implement AutoClosable and CloseGuard: class android.telephony.ims.stub.ImsUtImplBase
+
OnNameExpected: android.service.autofill.augmented.AugmentedAutofillService#dump(java.io.PrintWriter, String[]):
@@ -2292,21 +2294,21 @@ OnNameExpected: android.service.notification.NotificationAssistantService#attach
OnNameExpected: android.service.quicksettings.TileService#isQuickSettingsSupported():
OnNameExpected: android.telephony.ims.ImsService#createMmTelFeature(int):
- If implemented by developer, should follow the on<Something> style; otherwise consider marking final
+
OnNameExpected: android.telephony.ims.ImsService#createRcsFeature(int):
- If implemented by developer, should follow the on<Something> style; otherwise consider marking final
+
OnNameExpected: android.telephony.ims.ImsService#disableIms(int):
- If implemented by developer, should follow the on<Something> style; otherwise consider marking final
+
OnNameExpected: android.telephony.ims.ImsService#enableIms(int):
- If implemented by developer, should follow the on<Something> style; otherwise consider marking final
+
OnNameExpected: android.telephony.ims.ImsService#getConfig(int):
- If implemented by developer, should follow the on<Something> style; otherwise consider marking final
+
OnNameExpected: android.telephony.ims.ImsService#getRegistration(int):
- If implemented by developer, should follow the on<Something> style; otherwise consider marking final
+
OnNameExpected: android.telephony.ims.ImsService#querySupportedImsFeatures():
- If implemented by developer, should follow the on<Something> style; otherwise consider marking final
+
OnNameExpected: android.telephony.ims.ImsService#readyForFeatureCreation():
- If implemented by developer, should follow the on<Something> style; otherwise consider marking final
+
OnNameExpected: android.telephony.mbms.vendor.MbmsGroupCallServiceBase#dispose(int):
OnNameExpected: android.telephony.mbms.vendor.MbmsGroupCallServiceBase#initialize(android.telephony.mbms.MbmsGroupCallSessionCallback, int):
@@ -2446,7 +2448,7 @@ RethrowRemoteException: android.os.HwBinder#transact(int, android.os.HwParcel, a
RethrowRemoteException: android.os.IHwBinder#transact(int, android.os.HwParcel, android.os.HwParcel, int):
RethrowRemoteException: android.telephony.ims.ImsService#onUpdateSupportedImsFeatures(android.telephony.ims.stub.ImsFeatureConfiguration):
- Methods calling system APIs should rethrow `RemoteException` as `RuntimeException` (but do not list it in the throws clause)
+
RethrowRemoteException: android.telephony.mbms.vendor.MbmsDownloadServiceBase#addProgressListener(android.telephony.mbms.DownloadRequest, android.telephony.mbms.DownloadProgressListener):
RethrowRemoteException: android.telephony.mbms.vendor.MbmsDownloadServiceBase#addStatusListener(android.telephony.mbms.DownloadRequest, android.telephony.mbms.DownloadStatusListener):
@@ -2526,7 +2528,7 @@ SamShouldBeLast: android.service.autofill.ImageTransformation#apply(android.serv
SamShouldBeLast: android.service.autofill.InternalTransformation#batchApply(android.service.autofill.ValueFinder, android.widget.RemoteViews, java.util.ArrayList<android.util.Pair<java.lang.Integer,android.service.autofill.InternalTransformation>>):
SamShouldBeLast: android.telephony.ims.ImsMmTelManager#getFeatureState(java.util.function.Consumer<java.lang.Integer>, java.util.concurrent.Executor):
- SAM-compatible parameters (such as parameter 1, "callback", in android.telephony.ims.ImsMmTelManager.getFeatureState) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
+
SamShouldBeLast: android.view.Choreographer#postCallback(int, Runnable, Object):
SamShouldBeLast: android.view.Choreographer#postCallbackDelayed(int, Runnable, Object, long):
@@ -2599,6 +2601,8 @@ UserHandle: android.app.role.RoleManager#removeOnRoleHoldersChangedListenerAsUse
UserHandle: android.app.role.RoleManager#removeRoleHolderAsUser(String, String, int, android.os.UserHandle, java.util.concurrent.Executor, java.util.function.Consumer<java.lang.Boolean>):
+UserHandle: android.companion.CompanionDeviceManager#isDeviceAssociated(String, android.net.MacAddress, android.os.UserHandle):
+ When a method overload is needed to target a specific UserHandle, callers should be directed to use Context.createPackageContextAsUser() and re-obtain the relevant Manager, and no new API should be added
UserHandle: android.content.pm.PackageManager#getInstallReason(String, android.os.UserHandle):
UserHandle: android.content.pm.PackageManager#getPermissionFlags(String, String, android.os.UserHandle):
diff --git a/cmds/statsd/src/StatsService.cpp b/cmds/statsd/src/StatsService.cpp
index 1fd3abfc5adc..e8c0e1540e9c 100644
--- a/cmds/statsd/src/StatsService.cpp
+++ b/cmds/statsd/src/StatsService.cpp
@@ -1275,7 +1275,7 @@ Status StatsService::sendAppBreadcrumbAtom(int32_t label, int32_t state) {
// Permission check not necessary as it's meant for applications to write to
// statsd.
android::util::stats_write(util::APP_BREADCRUMB_REPORTED,
- IPCThreadState::self()->getCallingUid(), label,
+ (int32_t) IPCThreadState::self()->getCallingUid(), label,
state);
return Status::ok();
}
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index b9051daab6ae..2efb78943812 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -50,6 +50,7 @@ import "frameworks/base/core/proto/android/stats/intelligence/enums.proto";
import "frameworks/base/core/proto/android/stats/launcher/launcher.proto";
import "frameworks/base/core/proto/android/stats/location/location_enums.proto";
import "frameworks/base/core/proto/android/stats/mediametrics/mediametrics.proto";
+import "frameworks/base/core/proto/android/stats/mediaprovider/mediaprovider_enums.proto";
import "frameworks/base/core/proto/android/stats/storage/storage_enums.proto";
import "frameworks/base/core/proto/android/stats/style/style_enums.proto";
import "frameworks/base/core/proto/android/telecomm/enums.proto";
@@ -342,6 +343,16 @@ message Atom {
VmsClientConnectionStateChanged vms_client_connection_state_changed = 230;
GpsLocationStatusReported gps_location_status_reported = 231;
GpsTimeToFirstFixReported gps_time_to_first_fix_reported = 232;
+ MediaProviderScanEvent media_provider_scan_event =
+ 233 [(log_from_module) = "mediaprovider"];
+ MediaProviderDeletionEvent media_provider_deletion_event =
+ 234 [(log_from_module) = "mediaprovider"];
+ MediaProviderPermissionEvent media_provider_permission_event =
+ 235 [(log_from_module) = "mediaprovider"];
+ MediaProviderSchemaChange media_provider_schema_change =
+ 236 [(log_from_module) = "mediaprovider"];
+ MediaProviderIdleMaintenance media_provider_idle_maintenance =
+ 237 [(log_from_module) = "mediaprovider"];
}
// Pulled events will start at field 10000.
@@ -3799,6 +3810,124 @@ message VmsClientConnectionStateChanged {
optional State state = 2;
}
+/**
+ * Logs when MediaProvider has successfully finished scanning a storage volume.
+ *
+ * Logged from:
+ * packages/providers/MediaProvider/src/com/android/providers/media/scan/ModernMediaScanner.java
+ */
+message MediaProviderScanEvent {
+ enum Reason {
+ // Scan triggered due to unknown reason
+ UNKNOWN = 0;
+ // Scan triggered due to storage volume being mounted
+ MOUNTED = 1;
+ // Scan triggered due to explicit user action or app request
+ DEMAND = 2;
+ // Scan triggered due to idle maintenance
+ IDLE = 3;
+ }
+
+ // Volume type that this event pertains to
+ optional android.stats.mediaprovider.VolumeType volume_type = 1;
+ // Reason why this scan was triggered
+ optional Reason reason = 2;
+ // Total number of files scanned
+ optional int64 item_count = 3;
+ // Duration of scan, normalized per file
+ optional float normalized_duration_millis = 4;
+ // Number of database inserts, normalized per file
+ optional float normalized_insert_count = 5;
+ // Number of database updates, normalized per file
+ optional float normalized_update_count = 6;
+ // Number of database deletes, normalized per file
+ optional float normalized_delete_count = 7;
+}
+
+/**
+ * Logs when an app has asked MediaProvider to delete media belonging to the user.
+ *
+ * Logged from:
+ * packages/providers/MediaProvider/src/com/android/providers/media/MediaProvider.java
+ */
+message MediaProviderDeletionEvent {
+ // Volume type that this event pertains to
+ optional android.stats.mediaprovider.VolumeType volume_type = 1;
+ // Device timestamp when this deletion event occurred
+ optional int64 timestamp_millis = 2;
+ // App that requested deletion
+ optional string package_name = 3;
+ // Number of items that were deleted
+ optional int32 item_count = 4;
+}
+
+/**
+ * Logs when an app has asked MediaProvider to grant them access to media belonging to the user.
+ *
+ * Logged from:
+ * packages/providers/MediaProvider/src/com/android/providers/media/PermissionActivity.java
+ */
+message MediaProviderPermissionEvent {
+ enum Result {
+ UNKNOWN = 0;
+ USER_GRANTED = 1;
+ AUTO_GRANTED = 2;
+ USER_DENIED = 3;
+ USER_DENIED_WITH_PREJUDICE = 4;
+ AUTO_DENIED = 5;
+ }
+
+ // Volume type that this event pertains to
+ optional android.stats.mediaprovider.VolumeType volume_type = 1;
+ // Device timestamp when this permission event occurred
+ optional int64 timestamp_millis = 2;
+ // App that requested permission
+ optional string package_name = 3;
+ // Number of items that were requested
+ optional int32 item_count = 4;
+ // Result of this request
+ optional Result result = 5;
+}
+
+/**
+ * Logs when MediaProvider has finished upgrading or downgrading its database schema.
+ *
+ * Logged from:
+ * packages/providers/MediaProvider/src/com/android/providers/media/DatabaseHelper.java
+ */
+message MediaProviderSchemaChange {
+ // Volume type that this event pertains to
+ optional android.stats.mediaprovider.VolumeType volume_type = 1;
+ // Old database version code
+ optional int32 version_from = 2;
+ // New database version code
+ optional int32 version_to = 3;
+ // Total number of files in database
+ optional int64 item_count = 4;
+ // Duration of schema change, normalized per file
+ optional float normalized_duration_millis = 5;
+}
+
+/**
+ * Logs when MediaProvider has finished an idle maintenance job.
+ *
+ * Logged from:
+ * packages/providers/MediaProvider/src/com/android/providers/media/MediaProvider.java
+ */
+message MediaProviderIdleMaintenance {
+ // Volume type that this event pertains to
+ optional android.stats.mediaprovider.VolumeType volume_type = 1;
+
+ // Total number of files in database
+ optional int64 item_count = 2;
+ // Duration of idle maintenance, normalized per file
+ optional float normalized_duration_millis = 3;
+ // Number of thumbnails found to be stale, normalized per file
+ optional float normalized_stale_thumbnails = 4;
+ // Number of items found to be expired, normalized per file
+ optional float normalized_expired_media = 5;
+}
+
//////////////////////////////////////////////////////////////////////
// Pulled atoms below this line //
//////////////////////////////////////////////////////////////////////
@@ -5798,10 +5927,10 @@ message PermissionGrantRequestResultReported {
optional int64 request_id = 1;
// UID of package requesting the permission grant
- optional int32 requesting_uid = 2 [(is_uid) = true];
+ optional int32 uid = 2 [(is_uid) = true];
// Name of package requesting the permission grant
- optional string requesting_package_name = 3;
+ optional string package_name = 3;
// The permission to be granted
optional string permission_name = 4;
diff --git a/cmds/telecom/src/com/android/commands/telecom/Telecom.java b/cmds/telecom/src/com/android/commands/telecom/Telecom.java
index 03b08f785f74..1987440106f5 100644
--- a/cmds/telecom/src/com/android/commands/telecom/Telecom.java
+++ b/cmds/telecom/src/com/android/commands/telecom/Telecom.java
@@ -16,10 +16,12 @@
package com.android.commands.telecom;
+import android.app.ActivityThread;
import android.content.ComponentName;
import android.content.Context;
import android.net.Uri;
import android.os.IUserManager;
+import android.os.Looper;
import android.os.Process;
import android.os.RemoteException;
import android.os.ServiceManager;
@@ -33,7 +35,6 @@ import android.text.TextUtils;
import com.android.internal.os.BaseCommand;
import com.android.internal.telecom.ITelecomService;
-import com.android.internal.telephony.ITelephony;
import java.io.PrintStream;
@@ -82,7 +83,7 @@ public final class Telecom extends BaseCommand {
private ComponentName mComponent;
private String mAccountId;
private ITelecomService mTelecomService;
- private ITelephony mTelephonyService;
+ private TelephonyManager mTelephonyManager;
private IUserManager mUserManager;
@Override
@@ -153,9 +154,10 @@ public final class Telecom extends BaseCommand {
return;
}
- mTelephonyService = ITelephony.Stub.asInterface(
- ServiceManager.getService(Context.TELEPHONY_SERVICE));
- if (mTelephonyService == null) {
+ Looper.prepareMainLooper();
+ Context context = ActivityThread.systemMain().getSystemContext();
+ mTelephonyManager = context.getSystemService(TelephonyManager.class);
+ if (mTelephonyManager == null) {
Log.w(this, "onRun: Can't access telephony service.");
showError("Error: Could not access the Telephony Service. Is the system running?");
return;
@@ -351,7 +353,7 @@ public final class Telecom extends BaseCommand {
}
int numSims = Integer.parseInt(nextArgRequired());
System.out.println("Setting sim count to " + numSims + ". Device may reboot");
- mTelephonyService.switchMultiSimConfig(numSims);
+ mTelephonyManager.switchMultiSimConfig(numSims);
}
/**
@@ -365,8 +367,7 @@ public final class Telecom extends BaseCommand {
private void runGetMaxPhones() throws RemoteException {
// This assumes the max number of SIMs is 2, which it currently is
- if (TelephonyManager.MULTISIM_ALLOWED
- == mTelephonyService.isMultiSimSupported("com.android.commands.telecom", null)) {
+ if (TelephonyManager.MULTISIM_ALLOWED == mTelephonyManager.isMultiSimSupported()) {
System.out.println("2");
} else {
System.out.println("1");
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index 0113f6912183..034826a8d5fa 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -39,6 +39,7 @@ import android.content.pm.IPackageDeleteObserver;
import android.content.pm.IPackageManager;
import android.content.pm.IPackageMoveObserver;
import android.content.pm.IPackageStatsObserver;
+import android.content.pm.InstallSourceInfo;
import android.content.pm.InstantAppInfo;
import android.content.pm.InstrumentationInfo;
import android.content.pm.IntentFilterVerificationInfo;
@@ -2085,6 +2086,21 @@ public class ApplicationPackageManager extends PackageManager {
}
@Override
+ @NonNull
+ public InstallSourceInfo getInstallSourceInfo(String packageName) throws NameNotFoundException {
+ final InstallSourceInfo installSourceInfo;
+ try {
+ installSourceInfo = mPM.getInstallSourceInfo(packageName);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ if (installSourceInfo == null) {
+ throw new NameNotFoundException(packageName);
+ }
+ return installSourceInfo;
+ }
+
+ @Override
public int getMoveStatus(int moveId) {
try {
return mPM.getMoveStatus(moveId);
@@ -2782,7 +2798,7 @@ public class ApplicationPackageManager extends PackageManager {
public Drawable loadUnbadgedItemIcon(@NonNull PackageItemInfo itemInfo,
@Nullable ApplicationInfo appInfo) {
if (itemInfo.showUserIcon != UserHandle.USER_NULL) {
- // Indicates itemInfo is for a different user (e.g. a profile's parent), so use a
+ // Indicates itemInfo is for a different user (e.g. a profile's parent), so use a
// generic user icon (users generally lack permission to view each other's actual icons)
int targetUserId = itemInfo.showUserIcon;
return UserIcons.getDefaultUserIcon(
diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl
index 50d0dab62ea1..aa8a3023a40f 100644
--- a/core/java/android/app/IActivityManager.aidl
+++ b/core/java/android/app/IActivityManager.aidl
@@ -387,6 +387,7 @@ interface IActivityManager {
void requestInteractiveBugReport();
void requestFullBugReport();
void requestRemoteBugReport();
+ boolean launchBugReportHandlerApp();
@UnsupportedAppUsage
Intent getIntentForIntentSender(in IIntentSender sender);
diff --git a/core/java/android/app/StatsManager.java b/core/java/android/app/StatsManager.java
index 11d6528ab6af..2ef05105825a 100644
--- a/core/java/android/app/StatsManager.java
+++ b/core/java/android/app/StatsManager.java
@@ -51,12 +51,13 @@ public final class StatsManager {
private static final String TAG = "StatsManager";
private static final boolean DEBUG = false;
+ private static final Object sLock = new Object();
private final Context mContext;
- @GuardedBy("this")
+ @GuardedBy("sLock")
private IStatsManager mService;
- @GuardedBy("this")
+ @GuardedBy("sLock")
private IStatsCompanionService mStatsCompanion;
/**
@@ -125,7 +126,7 @@ public final class StatsManager {
*/
@RequiresPermission(allOf = { DUMP, PACKAGE_USAGE_STATS })
public void addConfig(long configKey, byte[] config) throws StatsUnavailableException {
- synchronized (this) {
+ synchronized (sLock) {
try {
IStatsManager service = getIStatsManagerLocked();
// can throw IllegalArgumentException
@@ -162,7 +163,7 @@ public final class StatsManager {
*/
@RequiresPermission(allOf = { DUMP, PACKAGE_USAGE_STATS })
public void removeConfig(long configKey) throws StatsUnavailableException {
- synchronized (this) {
+ synchronized (sLock) {
try {
IStatsManager service = getIStatsManagerLocked();
service.removeConfiguration(configKey, mContext.getOpPackageName());
@@ -223,7 +224,7 @@ public final class StatsManager {
public void setBroadcastSubscriber(
PendingIntent pendingIntent, long configKey, long subscriberId)
throws StatsUnavailableException {
- synchronized (this) {
+ synchronized (sLock) {
try {
IStatsManager service = getIStatsManagerLocked();
if (pendingIntent != null) {
@@ -277,7 +278,7 @@ public final class StatsManager {
@RequiresPermission(allOf = { DUMP, PACKAGE_USAGE_STATS })
public void setFetchReportsOperation(PendingIntent pendingIntent, long configKey)
throws StatsUnavailableException {
- synchronized (this) {
+ synchronized (sLock) {
try {
IStatsManager service = getIStatsManagerLocked();
if (pendingIntent == null) {
@@ -315,7 +316,7 @@ public final class StatsManager {
@RequiresPermission(allOf = { DUMP, PACKAGE_USAGE_STATS })
public @NonNull long[] setActiveConfigsChangedOperation(@Nullable PendingIntent pendingIntent)
throws StatsUnavailableException {
- synchronized (this) {
+ synchronized (sLock) {
try {
IStatsManager service = getIStatsManagerLocked();
if (pendingIntent == null) {
@@ -363,7 +364,7 @@ public final class StatsManager {
*/
@RequiresPermission(allOf = { DUMP, PACKAGE_USAGE_STATS })
public byte[] getReports(long configKey) throws StatsUnavailableException {
- synchronized (this) {
+ synchronized (sLock) {
try {
IStatsManager service = getIStatsManagerLocked();
return service.getData(configKey, mContext.getOpPackageName());
@@ -400,7 +401,7 @@ public final class StatsManager {
*/
@RequiresPermission(allOf = { DUMP, PACKAGE_USAGE_STATS })
public byte[] getStatsMetadata() throws StatsUnavailableException {
- synchronized (this) {
+ synchronized (sLock) {
try {
IStatsManager service = getIStatsManagerLocked();
return service.getMetadata(mContext.getOpPackageName());
@@ -435,7 +436,7 @@ public final class StatsManager {
@RequiresPermission(allOf = {DUMP, PACKAGE_USAGE_STATS})
public long[] getRegisteredExperimentIds()
throws StatsUnavailableException {
- synchronized (this) {
+ synchronized (sLock) {
try {
IStatsManager service = getIStatsManagerLocked();
if (service == null) {
@@ -472,7 +473,7 @@ public final class StatsManager {
@RequiresPermission(allOf = { DUMP, PACKAGE_USAGE_STATS })
public void setPullerCallback(int atomTag, IStatsPullerCallback callback)
throws StatsUnavailableException {
- synchronized (this) {
+ synchronized (sLock) {
try {
IStatsManager service = getIStatsManagerLocked();
if (callback == null) {
@@ -515,7 +516,7 @@ public final class StatsManager {
if (additiveFields == null) {
additiveFields = new int[0];
}
- synchronized (this) {
+ synchronized (sLock) {
IStatsCompanionService service = getIStatsCompanionServiceLocked();
PullAtomCallbackInternal rec =
new PullAtomCallbackInternal(atomTag, callback, executor);
@@ -649,13 +650,13 @@ public final class StatsManager {
private class StatsdDeathRecipient implements IBinder.DeathRecipient {
@Override
public void binderDied() {
- synchronized (this) {
+ synchronized (sLock) {
mService = null;
}
}
}
- @GuardedBy("this")
+ @GuardedBy("sLock")
private IStatsManager getIStatsManagerLocked() throws StatsUnavailableException {
if (mService != null) {
return mService;
@@ -672,7 +673,7 @@ public final class StatsManager {
return mService;
}
- @GuardedBy("this")
+ @GuardedBy("sLock")
private IStatsCompanionService getIStatsCompanionServiceLocked() {
if (mStatsCompanion != null) {
return mStatsCompanion;
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index 1829f74700fd..601b65863db1 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -1137,7 +1137,8 @@ public final class SystemServiceRegistry {
registerService(Context.PERMISSION_SERVICE, PermissionManager.class,
new CachedServiceFetcher<PermissionManager>() {
@Override
- public PermissionManager createService(ContextImpl ctx) {
+ public PermissionManager createService(ContextImpl ctx)
+ throws ServiceNotFoundException {
IPackageManager packageManager = AppGlobals.getPackageManager();
return new PermissionManager(ctx.getOuterContext(), packageManager);
}});
diff --git a/core/java/android/app/admin/DeviceAdminInfo.java b/core/java/android/app/admin/DeviceAdminInfo.java
index 00903c43b291..63bc40b86aa7 100644
--- a/core/java/android/app/admin/DeviceAdminInfo.java
+++ b/core/java/android/app/admin/DeviceAdminInfo.java
@@ -55,6 +55,14 @@ public final class DeviceAdminInfo implements Parcelable {
static final String TAG = "DeviceAdminInfo";
/**
+ * A type of policy that this device admin can use: profile owner on an organization-owned
+ * device.
+ *
+ * @hide
+ */
+ public static final int USES_POLICY_ORGANIZATION_OWNED_PROFILE_OWNER = -3;
+
+ /**
* A type of policy that this device admin can use: device owner meta-policy
* for an admin that is designated as owner of the device.
*
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 39dc51e307f1..34ceb08f39bf 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -9135,7 +9135,14 @@ public class DevicePolicyManager {
}
/**
- * Called by device owner to get the MAC address of the Wi-Fi device.
+ * Called by device owner, or profile owner on organization-owned device, to get the MAC
+ * address of the Wi-Fi device.
+ *
+ * NOTE: The MAC address returned here should only be used for inventory management and is
+ * not likely to be the MAC address used by the device to connect to Wi-Fi networks: MAC
+ * addresses used for scanning and connecting to Wi-Fi networks are randomized by default.
+ * To get the randomized MAC address used, call
+ * {@link android.net.wifi.WifiConfiguration#getRandomizedMacAddress}.
*
* @param admin Which device owner this request is associated with.
* @return the MAC address of the Wi-Fi device, or null when the information is not available.
diff --git a/core/java/android/app/timezonedetector/TimeZoneDetector.java b/core/java/android/app/timezonedetector/TimeZoneDetector.java
index 909cbc2ccdf7..387a36bba608 100644
--- a/core/java/android/app/timezonedetector/TimeZoneDetector.java
+++ b/core/java/android/app/timezonedetector/TimeZoneDetector.java
@@ -17,6 +17,7 @@
package android.app.timezonedetector;
import android.annotation.NonNull;
+import android.annotation.RequiresPermission;
import android.annotation.SystemService;
import android.content.Context;
import android.os.RemoteException;
@@ -26,10 +27,11 @@ import android.util.Log;
/**
* The interface through which system components can send signals to the TimeZoneDetectorService.
+ *
* @hide
*/
@SystemService(Context.TIME_ZONE_DETECTOR_SERVICE)
-public final class TimeZoneDetector {
+public class TimeZoneDetector {
private static final String TAG = "timezonedetector.TimeZoneDetector";
private static final boolean DEBUG = false;
@@ -41,10 +43,11 @@ public final class TimeZoneDetector {
}
/**
- * Suggests the current time zone to the detector. The detector may ignore the signal if better
- * signals are available such as those that come from more reliable sources or were
- * determined more recently.
+ * Suggests the current time zone, determined using telephony signals, to the detector. The
+ * detector may ignore the signal based on system settings, whether better information is
+ * available, and so on.
*/
+ @RequiresPermission(android.Manifest.permission.SET_TIME_ZONE)
public void suggestPhoneTimeZone(@NonNull PhoneTimeZoneSuggestion timeZoneSuggestion) {
if (DEBUG) {
Log.d(TAG, "suggestPhoneTimeZone called: " + timeZoneSuggestion);
@@ -56,4 +59,28 @@ public final class TimeZoneDetector {
}
}
+ /**
+ * Suggests the current time zone, determined for the user's manually information, to the
+ * detector. The detector may ignore the signal based on system settings.
+ */
+ @RequiresPermission(android.Manifest.permission.SET_TIME_ZONE)
+ public void suggestManualTimeZone(@NonNull ManualTimeZoneSuggestion timeZoneSuggestion) {
+ if (DEBUG) {
+ Log.d(TAG, "suggestManualTimeZone called: " + timeZoneSuggestion);
+ }
+ try {
+ mITimeZoneDetectorService.suggestManualTimeZone(timeZoneSuggestion);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * A shared utility method to create a {@link ManualTimeZoneSuggestion}.
+ */
+ public static ManualTimeZoneSuggestion createManualTimeZoneSuggestion(String tzId, String why) {
+ ManualTimeZoneSuggestion suggestion = new ManualTimeZoneSuggestion(tzId);
+ suggestion.addDebugInfo(why);
+ return suggestion;
+ }
}
diff --git a/core/java/android/bluetooth/BluetoothA2dp.java b/core/java/android/bluetooth/BluetoothA2dp.java
index accdd8dc64bd..8ed61b6c87e3 100644
--- a/core/java/android/bluetooth/BluetoothA2dp.java
+++ b/core/java/android/bluetooth/BluetoothA2dp.java
@@ -610,7 +610,7 @@ public final class BluetoothA2dp implements BluetoothProfile {
if (uuids == null) return false;
for (ParcelUuid uuid : uuids) {
- if (BluetoothUuid.isAvrcpTarget(uuid)) {
+ if (uuid.equals(BluetoothUuid.AVRCP_TARGET)) {
return true;
}
}
diff --git a/core/java/android/bluetooth/BluetoothHeadset.java b/core/java/android/bluetooth/BluetoothHeadset.java
index ea3831a869fc..0955b103a8e8 100644
--- a/core/java/android/bluetooth/BluetoothHeadset.java
+++ b/core/java/android/bluetooth/BluetoothHeadset.java
@@ -559,7 +559,7 @@ public final class BluetoothHeadset implements BluetoothProfile {
*
* <p> The device should already be paired.
* Priority can be one of {@link BluetoothProfile#PRIORITY_ON} or
- * {@link BluetoothProfile#PRIORITY_OFF},
+ * {@link BluetoothProfile#PRIORITY_OFF}
*
* @param device Paired bluetooth device
* @param priority
@@ -1133,8 +1133,9 @@ public final class BluetoothHeadset implements BluetoothProfile {
* is active.
* @hide
*/
+ @SystemApi
+ @Nullable
@RequiresPermission(android.Manifest.permission.BLUETOOTH)
- @UnsupportedAppUsage
public BluetoothDevice getActiveDevice() {
if (VDBG) {
Log.d(TAG, "getActiveDevice");
diff --git a/core/java/android/bluetooth/BluetoothHeadsetClient.java b/core/java/android/bluetooth/BluetoothHeadsetClient.java
index a8e1fd26ad44..7ee29ff1c50b 100644
--- a/core/java/android/bluetooth/BluetoothHeadsetClient.java
+++ b/core/java/android/bluetooth/BluetoothHeadsetClient.java
@@ -557,7 +557,7 @@ public final class BluetoothHeadsetClient implements BluetoothProfile {
* Set priority of the profile
*
* <p> The device should already be paired.
- * Priority can be one of {@link #PRIORITY_ON} or {@link #PRIORITY_OFF},
+ * Priority can be one of {@link #PRIORITY_ON} or {@link #PRIORITY_OFF}
*
* @param device Paired bluetooth device
* @param priority
diff --git a/core/java/android/bluetooth/BluetoothUuid.java b/core/java/android/bluetooth/BluetoothUuid.java
index bc3c9a9ebf4b..7e96c23af4b9 100644
--- a/core/java/android/bluetooth/BluetoothUuid.java
+++ b/core/java/android/bluetooth/BluetoothUuid.java
@@ -16,8 +16,10 @@
package android.bluetooth;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
import android.annotation.UnsupportedAppUsage;
-import android.os.Build;
import android.os.ParcelUuid;
import java.nio.ByteBuffer;
@@ -31,6 +33,7 @@ import java.util.UUID;
*
* @hide
*/
+@SystemApi
public final class BluetoothUuid {
/* See Bluetooth Assigned Numbers document - SDP section, to get the values of UUIDs
@@ -39,167 +42,157 @@ public final class BluetoothUuid {
* The following 128 bit values are calculated as:
* uuid * 2^96 + BASE_UUID
*/
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
- public static final ParcelUuid AudioSink =
+
+ /** @hide */
+ @NonNull
+ @SystemApi
+ public static final ParcelUuid A2DP_SINK =
ParcelUuid.fromString("0000110B-0000-1000-8000-00805F9B34FB");
- public static final ParcelUuid AudioSource =
+ /** @hide */
+ @NonNull
+ @SystemApi
+ public static final ParcelUuid A2DP_SOURCE =
ParcelUuid.fromString("0000110A-0000-1000-8000-00805F9B34FB");
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
- public static final ParcelUuid AdvAudioDist =
+ /** @hide */
+ @NonNull
+ @SystemApi
+ public static final ParcelUuid ADV_AUDIO_DIST =
ParcelUuid.fromString("0000110D-0000-1000-8000-00805F9B34FB");
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
+ /** @hide */
+ @NonNull
+ @SystemApi
public static final ParcelUuid HSP =
ParcelUuid.fromString("00001108-0000-1000-8000-00805F9B34FB");
+ /** @hide */
+ @NonNull
+ @SystemApi
public static final ParcelUuid HSP_AG =
ParcelUuid.fromString("00001112-0000-1000-8000-00805F9B34FB");
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
- public static final ParcelUuid Handsfree =
+ /** @hide */
+ @NonNull
+ @SystemApi
+ public static final ParcelUuid HFP =
ParcelUuid.fromString("0000111E-0000-1000-8000-00805F9B34FB");
- public static final ParcelUuid Handsfree_AG =
+ /** @hide */
+ @NonNull
+ @SystemApi
+ public static final ParcelUuid HFP_AG =
ParcelUuid.fromString("0000111F-0000-1000-8000-00805F9B34FB");
- public static final ParcelUuid AvrcpController =
+ /** @hide */
+ @NonNull
+ @SystemApi
+ public static final ParcelUuid AVRCP_CONTROLLER =
ParcelUuid.fromString("0000110E-0000-1000-8000-00805F9B34FB");
- public static final ParcelUuid AvrcpTarget =
+ /** @hide */
+ @NonNull
+ @SystemApi
+ public static final ParcelUuid AVRCP_TARGET =
ParcelUuid.fromString("0000110C-0000-1000-8000-00805F9B34FB");
- @UnsupportedAppUsage
- public static final ParcelUuid ObexObjectPush =
+ /** @hide */
+ @NonNull
+ @SystemApi
+ public static final ParcelUuid OBEX_OBJECT_PUSH =
ParcelUuid.fromString("00001105-0000-1000-8000-00805f9b34fb");
- public static final ParcelUuid Hid =
+ /** @hide */
+ @NonNull
+ @SystemApi
+ public static final ParcelUuid HID =
ParcelUuid.fromString("00001124-0000-1000-8000-00805f9b34fb");
- @UnsupportedAppUsage
- public static final ParcelUuid Hogp =
+ /** @hide */
+ @NonNull
+ @SystemApi
+ public static final ParcelUuid HOGP =
ParcelUuid.fromString("00001812-0000-1000-8000-00805f9b34fb");
+ /** @hide */
+ @NonNull
+ @SystemApi
public static final ParcelUuid PANU =
ParcelUuid.fromString("00001115-0000-1000-8000-00805F9B34FB");
- @UnsupportedAppUsage
+ /** @hide */
+ @NonNull
+ @SystemApi
public static final ParcelUuid NAP =
ParcelUuid.fromString("00001116-0000-1000-8000-00805F9B34FB");
+ /** @hide */
+ @NonNull
+ @SystemApi
public static final ParcelUuid BNEP =
ParcelUuid.fromString("0000000f-0000-1000-8000-00805F9B34FB");
+ /** @hide */
+ @NonNull
+ @SystemApi
public static final ParcelUuid PBAP_PCE =
ParcelUuid.fromString("0000112e-0000-1000-8000-00805F9B34FB");
- @UnsupportedAppUsage
+ /** @hide */
+ @NonNull
+ @SystemApi
public static final ParcelUuid PBAP_PSE =
ParcelUuid.fromString("0000112f-0000-1000-8000-00805F9B34FB");
+ /** @hide */
+ @NonNull
+ @SystemApi
public static final ParcelUuid MAP =
ParcelUuid.fromString("00001134-0000-1000-8000-00805F9B34FB");
+ /** @hide */
+ @NonNull
+ @SystemApi
public static final ParcelUuid MNS =
ParcelUuid.fromString("00001133-0000-1000-8000-00805F9B34FB");
+ /** @hide */
+ @NonNull
+ @SystemApi
public static final ParcelUuid MAS =
ParcelUuid.fromString("00001132-0000-1000-8000-00805F9B34FB");
+ /** @hide */
+ @NonNull
+ @SystemApi
public static final ParcelUuid SAP =
ParcelUuid.fromString("0000112D-0000-1000-8000-00805F9B34FB");
- public static final ParcelUuid HearingAid =
+ /** @hide */
+ @NonNull
+ @SystemApi
+ public static final ParcelUuid HEARING_AID =
ParcelUuid.fromString("0000FDF0-0000-1000-8000-00805f9b34fb");
+ /** @hide */
+ @NonNull
+ @SystemApi
public static final ParcelUuid BASE_UUID =
ParcelUuid.fromString("00000000-0000-1000-8000-00805F9B34FB");
- /** Length of bytes for 16 bit UUID */
+ /**
+ * Length of bytes for 16 bit UUID
+ *
+ * @hide
+ */
+ @SystemApi
public static final int UUID_BYTES_16_BIT = 2;
- /** Length of bytes for 32 bit UUID */
+ /**
+ * Length of bytes for 32 bit UUID
+ *
+ * @hide
+ */
+ @SystemApi
public static final int UUID_BYTES_32_BIT = 4;
- /** Length of bytes for 128 bit UUID */
- public static final int UUID_BYTES_128_BIT = 16;
-
- @UnsupportedAppUsage
- public static final ParcelUuid[] RESERVED_UUIDS = {
- AudioSink, AudioSource, AdvAudioDist, HSP, Handsfree, AvrcpController, AvrcpTarget,
- ObexObjectPush, PANU, NAP, MAP, MNS, MAS, SAP};
-
- @UnsupportedAppUsage
- public static boolean isAudioSource(ParcelUuid uuid) {
- return uuid.equals(AudioSource);
- }
-
- public static boolean isAudioSink(ParcelUuid uuid) {
- return uuid.equals(AudioSink);
- }
-
- @UnsupportedAppUsage
- public static boolean isAdvAudioDist(ParcelUuid uuid) {
- return uuid.equals(AdvAudioDist);
- }
-
- public static boolean isHandsfree(ParcelUuid uuid) {
- return uuid.equals(Handsfree);
- }
-
- public static boolean isHeadset(ParcelUuid uuid) {
- return uuid.equals(HSP);
- }
-
- public static boolean isAvrcpController(ParcelUuid uuid) {
- return uuid.equals(AvrcpController);
- }
-
- @UnsupportedAppUsage
- public static boolean isAvrcpTarget(ParcelUuid uuid) {
- return uuid.equals(AvrcpTarget);
- }
-
- public static boolean isInputDevice(ParcelUuid uuid) {
- return uuid.equals(Hid);
- }
-
- public static boolean isPanu(ParcelUuid uuid) {
- return uuid.equals(PANU);
- }
-
- public static boolean isNap(ParcelUuid uuid) {
- return uuid.equals(NAP);
- }
-
- public static boolean isBnep(ParcelUuid uuid) {
- return uuid.equals(BNEP);
- }
-
- public static boolean isMap(ParcelUuid uuid) {
- return uuid.equals(MAP);
- }
-
- public static boolean isMns(ParcelUuid uuid) {
- return uuid.equals(MNS);
- }
-
- public static boolean isMas(ParcelUuid uuid) {
- return uuid.equals(MAS);
- }
-
- public static boolean isSap(ParcelUuid uuid) {
- return uuid.equals(SAP);
- }
-
/**
- * Returns true if ParcelUuid is present in uuidArray
+ * Length of bytes for 128 bit UUID
*
- * @param uuidArray - Array of ParcelUuids
- * @param uuid
+ * @hide
*/
- @UnsupportedAppUsage
- public static boolean isUuidPresent(ParcelUuid[] uuidArray, ParcelUuid uuid) {
- if ((uuidArray == null || uuidArray.length == 0) && uuid == null) {
- return true;
- }
-
- if (uuidArray == null) {
- return false;
- }
-
- for (ParcelUuid element : uuidArray) {
- if (element.equals(uuid)) return true;
- }
- return false;
- }
+ @SystemApi
+ public static final int UUID_BYTES_128_BIT = 16;
/**
* Returns true if there any common ParcelUuids in uuidA and uuidB.
*
* @param uuidA - List of ParcelUuids
* @param uuidB - List of ParcelUuids
+ *
+ * @hide
*/
- @UnsupportedAppUsage
- public static boolean containsAnyUuid(ParcelUuid[] uuidA, ParcelUuid[] uuidB) {
+ @SystemApi
+ public static boolean containsAnyUuid(@Nullable ParcelUuid[] uuidA,
+ @Nullable ParcelUuid[] uuidB) {
if (uuidA == null && uuidB == null) return true;
if (uuidA == null) {
@@ -218,29 +211,6 @@ public final class BluetoothUuid {
}
/**
- * Returns true if all the ParcelUuids in ParcelUuidB are present in
- * ParcelUuidA
- *
- * @param uuidA - Array of ParcelUuidsA
- * @param uuidB - Array of ParcelUuidsB
- */
- public static boolean containsAllUuids(ParcelUuid[] uuidA, ParcelUuid[] uuidB) {
- if (uuidA == null && uuidB == null) return true;
-
- if (uuidA == null) {
- return uuidB.length == 0;
- }
-
- if (uuidB == null) return true;
-
- HashSet<ParcelUuid> uuidSet = new HashSet<ParcelUuid>(Arrays.asList(uuidA));
- for (ParcelUuid uuid : uuidB) {
- if (!uuidSet.contains(uuid)) return false;
- }
- return true;
- }
-
- /**
* Extract the Service Identifier or the actual uuid from the Parcel Uuid.
* For example, if 0000110B-0000-1000-8000-00805F9B34FB is the parcel Uuid,
* this function will return 110B
@@ -248,7 +218,7 @@ public final class BluetoothUuid {
* @param parcelUuid
* @return the service identifier.
*/
- public static int getServiceIdentifierFromParcelUuid(ParcelUuid parcelUuid) {
+ private static int getServiceIdentifierFromParcelUuid(ParcelUuid parcelUuid) {
UUID uuid = parcelUuid.getUuid();
long value = (uuid.getMostSignificantBits() & 0xFFFFFFFF00000000L) >>> 32;
return (int) value;
@@ -262,8 +232,12 @@ public final class BluetoothUuid {
* @param uuidBytes Byte representation of uuid.
* @return {@link ParcelUuid} parsed from bytes.
* @throws IllegalArgumentException If the {@code uuidBytes} cannot be parsed.
+ *
+ * @hide
*/
- public static ParcelUuid parseUuidFrom(byte[] uuidBytes) {
+ @NonNull
+ @SystemApi
+ public static ParcelUuid parseUuidFrom(@Nullable byte[] uuidBytes) {
if (uuidBytes == null) {
throw new IllegalArgumentException("uuidBytes cannot be null");
}
@@ -305,6 +279,8 @@ public final class BluetoothUuid {
* @param uuid uuid to parse.
* @return shortest representation of {@code uuid} as bytes.
* @throws IllegalArgumentException If the {@code uuid} is null.
+ *
+ * @hide
*/
public static byte[] uuidToBytes(ParcelUuid uuid) {
if (uuid == null) {
@@ -345,6 +321,8 @@ public final class BluetoothUuid {
*
* @param parcelUuid
* @return true if the parcelUuid can be converted to 16 bit uuid, false otherwise.
+ *
+ * @hide
*/
@UnsupportedAppUsage
public static boolean is16BitUuid(ParcelUuid parcelUuid) {
@@ -361,6 +339,8 @@ public final class BluetoothUuid {
*
* @param parcelUuid
* @return true if the parcelUuid can be converted to 32 bit uuid, false otherwise.
+ *
+ * @hide
*/
@UnsupportedAppUsage
public static boolean is32BitUuid(ParcelUuid parcelUuid) {
@@ -373,4 +353,6 @@ public final class BluetoothUuid {
}
return ((uuid.getMostSignificantBits() & 0xFFFFFFFFL) == 0x1000L);
}
+
+ private BluetoothUuid() {}
}
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 341b5206ba90..d370a380bc3b 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -3427,7 +3427,6 @@ public abstract class Context {
//@hide: TIME_DETECTOR_SERVICE,
//@hide: TIME_ZONE_DETECTOR_SERVICE,
PERMISSION_SERVICE,
- INCREMENTAL_SERVICE,
})
@Retention(RetentionPolicy.SOURCE)
public @interface ServiceName {}
@@ -4971,6 +4970,13 @@ public abstract class Context {
/**
* Use with {@link #getSystemService(String)} to retrieve an
+ * {@link android.content.pm.DataLoaderManager}.
+ * @hide
+ */
+ public static final String DATA_LOADER_MANAGER_SERVICE = "dataloadermanager";
+
+ /**
+ * Use with {@link #getSystemService(String)} to retrieve an
* {@link android.os.incremental.IncrementalManager}.
* @hide
*/
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 40aca0ef2033..af7b98683219 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -4053,6 +4053,13 @@ public class Intent implements Parcelable, Cloneable {
public static final String ACTION_SERVICE_STATE = "android.intent.action.SERVICE_STATE";
/**
+ * Used for looking up a Data Loader Service providers.
+ * @hide
+ */
+ @SdkConstant(SdkConstant.SdkConstantType.SERVICE_ACTION)
+ public static final String ACTION_LOAD_DATA = "android.intent.action.LOAD_DATA";
+
+ /**
* An int extra used with {@link #ACTION_SERVICE_STATE} which indicates voice registration
* state.
* @see android.telephony.ServiceState#STATE_EMERGENCY_ONLY
diff --git a/core/java/android/content/pm/DataLoaderManager.java b/core/java/android/content/pm/DataLoaderManager.java
new file mode 100644
index 000000000000..26880384e502
--- /dev/null
+++ b/core/java/android/content/pm/DataLoaderManager.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.content.pm;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.Bundle;
+import android.os.RemoteException;
+
+/**
+ * Data loader manager takes care of data loaders of different packages. It provides methods to
+ * initialize a data loader binder service (binding and creating it), to return a binder of the data
+ * loader binder service and to destroy a data loader binder service.
+ * @see com.android.server.pm.DataLoaderManagerService
+ * @hide
+ */
+public class DataLoaderManager {
+ private static final String TAG = "DataLoaderManager";
+ private final IDataLoaderManager mService;
+
+ public DataLoaderManager(IDataLoaderManager service) {
+ mService = service;
+ }
+
+ /**
+ * Finds a data loader binder service and binds to it. This requires PackageManager.
+ *
+ * @param dataLoaderId ID for the new data loader binder service.
+ * @param params Bundle that contains parameters to configure the data loader service.
+ * Must contain:
+ * key: "packageName", value: String, package name of data loader service
+ * package;
+ * key: "extras", value: Bundle, client-specific data structures
+ *
+ * @param listener Callback for the data loader service to report status back to the
+ * caller.
+ * @return false if 1) target ID collides with a data loader that is already bound to data
+ * loader manager; 2) package name is not specified; 3) fails to find data loader package;
+ * or 4) fails to bind to the specified data loader service, otherwise return true.
+ */
+ public boolean initializeDataLoader(int dataLoaderId, @NonNull Bundle params,
+ @NonNull IDataLoaderStatusListener listener) {
+ try {
+ return mService.initializeDataLoader(dataLoaderId, params, listener);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Returns a binder interface of the data loader binder service, given its ID.
+ */
+ @Nullable
+ public IDataLoader getDataLoader(int dataLoaderId) {
+ try {
+ return mService.getDataLoader(dataLoaderId);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Destroys the data loader binder service and removes it from data loader manager service.
+ */
+ @Nullable
+ public void destroyDataLoader(int dataLoaderId) {
+ try {
+ mService.destroyDataLoader(dataLoaderId);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+}
diff --git a/tools/processors/unsupportedappusage/src/android/processor/unsupportedappusage/SourcePosition.java b/core/java/android/content/pm/IDataLoader.aidl
index 4ae093c3c2e4..60cc9ba9e141 100644
--- a/tools/processors/unsupportedappusage/src/android/processor/unsupportedappusage/SourcePosition.java
+++ b/core/java/android/content/pm/IDataLoader.aidl
@@ -14,23 +14,21 @@
* limitations under the License.
*/
-package android.processor.unsupportedappusage;
+package android.content.pm;
+
+import android.os.Bundle;
+import android.content.pm.IDataLoaderStatusListener;
+import android.content.pm.InstallationFile;
+import java.util.List;
/**
- * Represents a source position within a source file
+ * TODO: update with new APIs
+ * @hide
*/
-public class SourcePosition {
- public final String filename;
- public final int startLine;
- public final int startCol;
- public final int endLine;
- public final int endCol;
-
- public SourcePosition(String filename, int startLine, int startCol, int endLine, int endCol) {
- this.filename = filename;
- this.startLine = startLine;
- this.startCol = startCol;
- this.endLine = endLine;
- this.endCol = endCol;
- }
+oneway interface IDataLoader {
+ void create(int id, in Bundle params, IDataLoaderStatusListener listener);
+ void start(in List<InstallationFile> fileInfos);
+ void stop();
+ void destroy();
+ void onFileCreated(long inode, in byte[] metadata);
}
diff --git a/core/java/android/content/pm/IDataLoaderManager.aidl b/core/java/android/content/pm/IDataLoaderManager.aidl
new file mode 100644
index 000000000000..f453c9b6c45f
--- /dev/null
+++ b/core/java/android/content/pm/IDataLoaderManager.aidl
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.Bundle;
+import android.content.pm.IDataLoader;
+import android.content.pm.IDataLoaderStatusListener;
+import java.util.List;
+
+/** @hide */
+interface IDataLoaderManager {
+ boolean initializeDataLoader(int id, in Bundle params, IDataLoaderStatusListener listener);
+ IDataLoader getDataLoader(int dataLoaderId);
+ void destroyDataLoader(int dataLoaderId);
+} \ No newline at end of file
diff --git a/core/java/android/service/incremental/IIncrementalDataLoaderStatusListener.aidl b/core/java/android/content/pm/IDataLoaderStatusListener.aidl
index f04242dc6c02..a60d6ee2d28a 100644
--- a/core/java/android/service/incremental/IIncrementalDataLoaderStatusListener.aidl
+++ b/core/java/android/content/pm/IDataLoaderStatusListener.aidl
@@ -14,13 +14,13 @@
* limitations under the License.
*/
-package android.service.incremental;
+package android.content.pm;
/**
- * Callbacks from DataLoaderService to IncrementalService to report data loader status.
+ * Callbacks from a data loader binder service to report data loader status.
* @hide
*/
-oneway interface IIncrementalDataLoaderStatusListener {
+oneway interface IDataLoaderStatusListener {
/** Data loader status */
const int DATA_LOADER_READY = 0;
const int DATA_LOADER_NOT_READY = 1;
@@ -31,6 +31,6 @@ oneway interface IIncrementalDataLoaderStatusListener {
const int DATA_LOADER_CONNECTION_OK = 6;
/** Data loader status callback */
- void onStatusChanged(in int storageId, in int status);
+ void onStatusChanged(in int dataLoaderId, in int status);
}
diff --git a/core/java/android/content/pm/IPackageInstallerSession.aidl b/core/java/android/content/pm/IPackageInstallerSession.aidl
index b74061793f9b..0b3c7654f4fb 100644
--- a/core/java/android/content/pm/IPackageInstallerSession.aidl
+++ b/core/java/android/content/pm/IPackageInstallerSession.aidl
@@ -46,4 +46,5 @@ interface IPackageInstallerSession {
int getParentSessionId();
boolean isStaged();
+ void addFile(in String name, long size, in byte[] metadata);
}
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index a71367d562f7..b3d8eb51e324 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -26,6 +26,7 @@ import android.content.pm.ChangedPackages;
import android.content.pm.InstantAppInfo;
import android.content.pm.FeatureInfo;
import android.content.pm.IDexModuleRegisterCallback;
+import android.content.pm.InstallSourceInfo;
import android.content.pm.IPackageInstaller;
import android.content.pm.IPackageDeleteObserver;
import android.content.pm.IPackageDeleteObserver2;
@@ -237,6 +238,8 @@ interface IPackageManager {
@UnsupportedAppUsage
String getInstallerPackageName(in String packageName);
+ InstallSourceInfo getInstallSourceInfo(in String packageName);
+
void resetApplicationPreferences(int userId);
@UnsupportedAppUsage
diff --git a/core/java/android/content/pm/InstallSourceInfo.aidl b/core/java/android/content/pm/InstallSourceInfo.aidl
new file mode 100644
index 000000000000..21ee4c35b57c
--- /dev/null
+++ b/core/java/android/content/pm/InstallSourceInfo.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 InstallSourceInfo;
diff --git a/core/java/android/content/pm/InstallSourceInfo.java b/core/java/android/content/pm/InstallSourceInfo.java
new file mode 100644
index 000000000000..4d235f1af2f7
--- /dev/null
+++ b/core/java/android/content/pm/InstallSourceInfo.java
@@ -0,0 +1,110 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.content.pm;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * Information about how an app was installed.
+ * @see PackageManager#getInstallSourceInfo(String)
+ */
+public final class InstallSourceInfo implements Parcelable {
+
+ @Nullable private final String mInitiatingPackageName;
+
+ @Nullable private final String mOriginatingPackageName;
+
+ @Nullable private final String mInstallingPackageName;
+
+ /** @hide */
+ public InstallSourceInfo(@Nullable String initiatingPackageName,
+ @Nullable String originatingPackageName, @Nullable String installingPackageName) {
+ this.mInitiatingPackageName = initiatingPackageName;
+ this.mOriginatingPackageName = originatingPackageName;
+ this.mInstallingPackageName = installingPackageName;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ dest.writeString(mInitiatingPackageName);
+ dest.writeString(mOriginatingPackageName);
+ dest.writeString(mInstallingPackageName);
+ }
+
+ private InstallSourceInfo(Parcel source) {
+ mInitiatingPackageName = source.readString();
+ mOriginatingPackageName = source.readString();
+ mInstallingPackageName = source.readString();
+ }
+
+ /** The name of the package that requested the installation, or null if not available. */
+ @Nullable
+ public String getInitiatingPackageName() {
+ return mInitiatingPackageName;
+ }
+
+ /**
+ * The name of the package on behalf of which the initiating package requested the installation,
+ * or null if not available.
+ * <p>
+ * For example if a downloaded APK is installed via the Package Installer this could be the
+ * app that performed the download. This value is provided by the initiating package and not
+ * verified by the framework.
+ * <p>
+ * Note that the {@code InstallSourceInfo} returned by
+ * {@link PackageManager#getInstallSourceInfo(String)} will not have this information
+ * available unless the calling application holds the INSTALL_PACKAGES permission.
+ */
+ @Nullable
+ public String getOriginatingPackageName() {
+ return mOriginatingPackageName;
+ }
+
+ /**
+ * The name of the package responsible for the installation (the installer of record), or null
+ * if not available.
+ * Note that this may differ from the initiating package name and can be modified.
+ *
+ * @see PackageManager#setInstallerPackageName(String, String)
+ */
+ @Nullable
+ public String getInstallingPackageName() {
+ return mInstallingPackageName;
+ }
+
+ @NonNull
+ public static final Parcelable.Creator<InstallSourceInfo> CREATOR =
+ new Creator<InstallSourceInfo>() {
+ @Override
+ public InstallSourceInfo createFromParcel(Parcel source) {
+ return new InstallSourceInfo(source);
+ }
+
+ @Override
+ public InstallSourceInfo[] newArray(int size) {
+ return new InstallSourceInfo[size];
+ }
+ };
+}
diff --git a/core/java/android/content/pm/InstallationFile.aidl b/core/java/android/content/pm/InstallationFile.aidl
new file mode 100644
index 000000000000..1edff9d6c7aa
--- /dev/null
+++ b/core/java/android/content/pm/InstallationFile.aidl
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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;
+
+/**
+ * Describes a file which is part of a package installation.
+ */
+parcelable InstallationFile;
+
diff --git a/core/java/android/content/pm/InstallationFile.java b/core/java/android/content/pm/InstallationFile.java
new file mode 100644
index 000000000000..ac5fd1e41075
--- /dev/null
+++ b/core/java/android/content/pm/InstallationFile.java
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Defines the properties of a file in an installation session.
+ * TODO(b/136132412): update with new APIs.
+ *
+ * @hide
+ */
+public final class InstallationFile implements Parcelable {
+ public static final int FILE_TYPE_UNKNOWN = -1;
+ public static final int FILE_TYPE_APK = 0;
+ public static final int FILE_TYPE_LIB = 1;
+ public static final int FILE_TYPE_OBB = 2;
+
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(prefix = {"FILE_TYPE_"}, value = {
+ FILE_TYPE_APK,
+ FILE_TYPE_LIB,
+ FILE_TYPE_OBB,
+ })
+ public @interface FileType {
+ }
+
+ private String mFileName;
+ private @FileType int mFileType;
+ private long mFileSize;
+ private byte[] mMetadata;
+
+ public InstallationFile(@NonNull String fileName, long fileSize,
+ @Nullable byte[] metadata) {
+ mFileName = fileName;
+ mFileSize = fileSize;
+ mMetadata = metadata;
+ if (fileName.toLowerCase().endsWith(".apk")) {
+ mFileType = FILE_TYPE_APK;
+ } else if (fileName.toLowerCase().endsWith(".obb")) {
+ mFileType = FILE_TYPE_OBB;
+ } else if (fileName.toLowerCase().endsWith(".so") && fileName.toLowerCase().startsWith(
+ "lib/")) {
+ mFileType = FILE_TYPE_LIB;
+ } else {
+ mFileType = FILE_TYPE_UNKNOWN;
+ }
+ }
+
+ public @FileType int getFileType() {
+ return mFileType;
+ }
+
+ public @NonNull String getName() {
+ return mFileName;
+ }
+
+ public long getSize() {
+ return mFileSize;
+ }
+
+ public @Nullable byte[] getMetadata() {
+ return mMetadata;
+ }
+
+ private InstallationFile(Parcel source) {
+ mFileName = source.readString();
+ mFileType = source.readInt();
+ mFileSize = source.readLong();
+ mMetadata = source.createByteArray();
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ dest.writeString(mFileName);
+ dest.writeInt(mFileType);
+ dest.writeLong(mFileSize);
+ dest.writeByteArray(mMetadata);
+ }
+
+ public static final @NonNull Creator<InstallationFile> CREATOR =
+ new Creator<InstallationFile>() {
+ public InstallationFile createFromParcel(Parcel source) {
+ return new InstallationFile(source);
+ }
+
+ public InstallationFile[] newArray(int size) {
+ return new InstallationFile[size];
+ }
+ };
+
+}
diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java
index 4ab6f3cd92b4..e9fc8f6acfc6 100644
--- a/core/java/android/content/pm/PackageInstaller.java
+++ b/core/java/android/content/pm/PackageInstaller.java
@@ -50,6 +50,8 @@ import android.os.ParcelableException;
import android.os.RemoteException;
import android.os.SystemProperties;
import android.os.UserHandle;
+import android.os.incremental.IncrementalDataLoaderParams;
+import android.os.incremental.IncrementalDataLoaderParamsParcel;
import android.system.ErrnoException;
import android.system.Os;
import android.util.ArraySet;
@@ -1212,6 +1214,27 @@ public class PackageInstaller {
}
/**
+ * Configure files for an installation session.
+ *
+ * Currently only for Incremental installation session. Once this method is called,
+ * the files and their paths, as specified in the parameters, will be created and properly
+ * configured in the Incremental File System.
+ *
+ * TODO(b/136132412): update this and InstallationFile class with latest API design.
+ *
+ * @throws IllegalStateException if {@link SessionParams#incrementalParams} is null.
+ *
+ * @hide
+ */
+ public void addFile(@NonNull String name, long size, @NonNull byte[] metadata) {
+ try {
+ mSession.addFile(name, size, metadata);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* Release this session object. You can open the session again if it
* hasn't been finalized.
*/
@@ -1398,6 +1421,8 @@ public class PackageInstaller {
public boolean isStaged;
/** {@hide} */
public long requiredInstalledVersionCode = PackageManager.VERSION_CODE_HIGHEST;
+ /** {@hide} */
+ public IncrementalDataLoaderParams incrementalParams;
/**
* Construct parameters for a new package install session.
@@ -1431,6 +1456,12 @@ public class PackageInstaller {
isMultiPackage = source.readBoolean();
isStaged = source.readBoolean();
requiredInstalledVersionCode = source.readLong();
+ IncrementalDataLoaderParamsParcel dataLoaderParamsParcel = source.readParcelable(
+ IncrementalDataLoaderParamsParcel.class.getClassLoader());
+ if (dataLoaderParamsParcel != null) {
+ incrementalParams = new IncrementalDataLoaderParams(
+ dataLoaderParamsParcel);
+ }
}
/** {@hide} */
@@ -1454,6 +1485,7 @@ public class PackageInstaller {
ret.isMultiPackage = isMultiPackage;
ret.isStaged = isStaged;
ret.requiredInstalledVersionCode = requiredInstalledVersionCode;
+ ret.incrementalParams = incrementalParams;
return ret;
}
@@ -1782,6 +1814,16 @@ public class PackageInstaller {
return (installFlags & PackageManager.INSTALL_ENABLE_ROLLBACK) != 0;
}
+ /**
+ * Set Incremental data loader params.
+ *
+ * {@hide}
+ */
+ @RequiresPermission(Manifest.permission.INSTALL_PACKAGES)
+ public void setIncrementalParams(@NonNull IncrementalDataLoaderParams incrementalParams) {
+ this.incrementalParams = incrementalParams;
+ }
+
/** {@hide} */
public void dump(IndentingPrintWriter pw) {
pw.printPair("mode", mode);
@@ -1831,6 +1873,11 @@ public class PackageInstaller {
dest.writeBoolean(isMultiPackage);
dest.writeBoolean(isStaged);
dest.writeLong(requiredInstalledVersionCode);
+ if (incrementalParams != null) {
+ dest.writeParcelable(incrementalParams.getData(), flags);
+ } else {
+ dest.writeParcelable(null, flags);
+ }
}
public static final Parcelable.Creator<SessionParams>
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index bbfdf910a9da..6e890ba0d827 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -5989,11 +5989,30 @@ public abstract class PackageManager {
*
* @param packageName The name of the package to query
* @throws IllegalArgumentException if the given package name is not installed
+ *
+ * @deprecated use {@link #getInstallSourceInfo(String)} instead
*/
+ @Deprecated
@Nullable
public abstract String getInstallerPackageName(@NonNull String packageName);
/**
+ * Retrieves information about how a package was installed or updated.
+ * <p>
+ * If the calling application does not hold the INSTALL_PACKAGES permission then
+ * the result will always return {@code null} from
+ * {@link InstallSourceInfo#getOriginatingPackageName()}.
+ *
+ * @param packageName The name of the package to query
+ * @throws NameNotFoundException if the given package name is not installed
+ */
+ @NonNull
+ public InstallSourceInfo getInstallSourceInfo(@NonNull String packageName)
+ throws NameNotFoundException {
+ throw new UnsupportedOperationException("getInstallSourceInfo not implemented");
+ }
+
+ /**
* Attempts to clear the user data directory of an application.
* Since this may take a little while, the result will
* be posted back to the given observer. A deletion will fail if the
diff --git a/core/java/android/os/incremental/IIncrementalServiceProxy.aidl b/core/java/android/os/incremental/IIncrementalServiceProxy.aidl
index 12740eaf3425..ffff52e5aac9 100644
--- a/core/java/android/os/incremental/IIncrementalServiceProxy.aidl
+++ b/core/java/android/os/incremental/IIncrementalServiceProxy.aidl
@@ -18,7 +18,7 @@ package android.os.incremental;
import android.os.incremental.IncrementalFileSystemControlParcel;
import android.os.incremental.IncrementalDataLoaderParamsParcel;
-import android.service.incremental.IIncrementalDataLoaderStatusListener;
+import android.content.pm.IDataLoaderStatusListener;
/**
* Binder service to receive calls from native Incremental Service and handle Java tasks such as
@@ -29,7 +29,7 @@ interface IIncrementalServiceProxy {
boolean prepareDataLoader(int mountId,
in IncrementalFileSystemControlParcel control,
in IncrementalDataLoaderParamsParcel params,
- in IIncrementalDataLoaderStatusListener listener);
+ in IDataLoaderStatusListener listener);
boolean startDataLoader(int mountId);
void showHealthBlockedUI(int mountId);
void destroyDataLoader(int mountId);
diff --git a/core/java/android/os/incremental/IncrementalFileStorages.java b/core/java/android/os/incremental/IncrementalFileStorages.java
new file mode 100644
index 000000000000..5bd0748b8d97
--- /dev/null
+++ b/core/java/android/os/incremental/IncrementalFileStorages.java
@@ -0,0 +1,280 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.os.incremental;
+
+/**
+ * Set up files and directories used in an installation session.
+ * Currently only used by Incremental Installation.
+ * For Incremental installation, the expected outcome of this function is:
+ * 0) All the files are in defaultStorage
+ * 1) All APK files are in the same directory, bound to mApkStorage, and bound to the
+ * InstallerSession's stage dir. The files are linked from mApkStorage to defaultStorage.
+ * 2) All lib files are in the sub directories as their names suggest, and in the same parent
+ * directory as the APK files. The files are linked from mApkStorage to defaultStorage.
+ * 3) OBB files are in another directory that is different from APK files and lib files, bound
+ * to mObbStorage. The files are linked from mObbStorage to defaultStorage.
+ *
+ * @throws IllegalStateException the session is not an Incremental installation session.
+ */
+
+import static dalvik.system.VMRuntime.getInstructionSet;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.pm.InstallationFile;
+import android.os.IVold;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.util.ArraySet;
+import android.util.Slog;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Random;
+
+/**
+ * This class manages storage instances used during a package installation session.
+ * @hide
+ */
+public final class IncrementalFileStorages {
+ private static final String TAG = "IncrementalFileStorages";
+ private @Nullable IncrementalStorage mDefaultStorage;
+ private @Nullable IncrementalStorage mApkStorage;
+ private @Nullable IncrementalStorage mObbStorage;
+ private @Nullable String mDefaultDir;
+ private @Nullable String mObbDir;
+ private @NonNull IncrementalManager mIncrementalManager;
+ private @Nullable ArraySet<String> mLibDirs;
+ private @NonNull String mPackageName;
+ private @NonNull File mStageDir;
+
+ /**
+ * Set up files and directories used in an installation session.
+ * Currently only used by Incremental Installation.
+ * For Incremental installation, the expected outcome of this function is:
+ * 0) All the files are in defaultStorage
+ * 1) All APK files are in the same directory, bound to mApkStorage, and bound to the
+ * InstallerSession's stage dir. The files are linked from mApkStorage to defaultStorage.
+ * 2) All lib files are in the sub directories as their names suggest, and in the same parent
+ * directory as the APK files. The files are linked from mApkStorage to defaultStorage.
+ * 3) OBB files are in another directory that is different from APK files and lib files, bound
+ * to mObbStorage. The files are linked from mObbStorage to defaultStorage.
+ *
+ * @throws IllegalStateException the session is not an Incremental installation session.
+ */
+ public IncrementalFileStorages(@NonNull String packageName,
+ @NonNull File stageDir,
+ @NonNull IncrementalManager incrementalManager,
+ @NonNull IncrementalDataLoaderParams incrementalDataLoaderParams) {
+ mPackageName = packageName;
+ mStageDir = stageDir;
+ mIncrementalManager = incrementalManager;
+ if (incrementalDataLoaderParams.getPackageName().equals("local")) {
+ final String incrementalPath = incrementalDataLoaderParams.getStaticArgs();
+ mDefaultStorage = mIncrementalManager.openStorage(incrementalPath);
+ mDefaultDir = incrementalPath;
+ return;
+ }
+ mDefaultDir = getTempDir();
+ if (mDefaultDir == null) {
+ return;
+ }
+ mDefaultStorage = mIncrementalManager.createStorage(mDefaultDir,
+ incrementalDataLoaderParams,
+ IncrementalManager.CREATE_MODE_CREATE
+ | IncrementalManager.CREATE_MODE_TEMPORARY_BIND, false);
+ }
+
+ /**
+ * Adds a file into the installation session. Makes sure it will be placed inside
+ * a proper storage instance, based on its file type.
+ */
+ public void addFile(@NonNull InstallationFile file) throws IOException {
+ if (mDefaultStorage == null) {
+ throw new IOException("Cannot add file because default storage does not exist");
+ }
+ if (file.getFileType() == InstallationFile.FILE_TYPE_APK) {
+ addApkFile(file);
+ } else if (file.getFileType() == InstallationFile.FILE_TYPE_OBB) {
+ addObbFile(file);
+ } else if (file.getFileType() == InstallationFile.FILE_TYPE_LIB) {
+ addLibFile(file);
+ } else {
+ throw new IOException("Unknown file type: " + file.getFileType());
+ }
+ }
+
+ private void addApkFile(@NonNull InstallationFile apk) throws IOException {
+ // Create a storage for APK files and lib files
+ final String stageDirPath = mStageDir.getAbsolutePath();
+ if (mApkStorage == null) {
+ mApkStorage = mIncrementalManager.createStorage(stageDirPath, mDefaultStorage,
+ IncrementalManager.CREATE_MODE_CREATE
+ | IncrementalManager.CREATE_MODE_TEMPORARY_BIND);
+ mApkStorage.bind(stageDirPath);
+ }
+
+ if (!new File(mDefaultDir, apk.getName()).exists()) {
+ mDefaultStorage.makeFile(apk.getName(), apk.getSize(),
+ apk.getMetadata());
+ }
+ // Assuming APK files are already named properly, e.g., "base.apk"
+ mDefaultStorage.makeLink(apk.getName(), mApkStorage, apk.getName());
+ }
+
+ private void addLibFile(@NonNull InstallationFile lib) throws IOException {
+ // TODO(b/136132412): remove this after we have incfs support for lib file mapping
+ if (mApkStorage == null) {
+ throw new IOException("Cannot add lib file without adding an apk file first");
+ }
+ if (mLibDirs == null) {
+ mLibDirs = new ArraySet<>();
+ }
+ String current = "";
+ final Path libDirPath = Paths.get(lib.getName()).getParent();
+ final int numDirComponents = libDirPath.getNameCount();
+ for (int i = 0; i < numDirComponents; i++) {
+ String dirName = libDirPath.getName(i).toString();
+ try {
+ dirName = getInstructionSet(dirName);
+ } catch (IllegalArgumentException ignored) {
+ }
+ current += dirName;
+ if (!mLibDirs.contains(current)) {
+ mDefaultStorage.makeDirectory(current);
+ mApkStorage.makeDirectory(current);
+ mLibDirs.add(current);
+ }
+ current += '/';
+ }
+ String libFilePath = current + Paths.get(lib.getName()).getFileName();
+ mDefaultStorage.makeFile(libFilePath, lib.getSize(), lib.getMetadata());
+ mDefaultStorage.makeLink(libFilePath, mApkStorage, libFilePath);
+ }
+
+ private void addObbFile(@NonNull InstallationFile obb) throws IOException {
+ if (mObbStorage == null) {
+ // Create a storage for OBB files
+ mObbDir = getTempDir();
+ if (mObbDir == null) {
+ throw new IOException("Failed to create obb storage directory.");
+ }
+ mObbStorage = mIncrementalManager.createStorage(
+ mObbDir, mDefaultStorage,
+ IncrementalManager.CREATE_MODE_CREATE
+ | IncrementalManager.CREATE_MODE_TEMPORARY_BIND);
+ }
+ mDefaultStorage.makeFile(obb.getName(), obb.getSize(), obb.getMetadata());
+ mDefaultStorage.makeLink(obb.getName(), mObbStorage, obb.getName());
+ }
+
+ private boolean hasObb() {
+ return (mObbStorage != null && mObbDir != null);
+ }
+
+ /**
+ * Starts loading data for default storage.
+ * TODO(b/136132412): update the implementation with latest API design.
+ */
+ public boolean startLoading() {
+ if (mDefaultStorage == null) {
+ return false;
+ }
+ return mDefaultStorage.startLoading();
+ }
+
+ /**
+ * Sets up obb storage directory and create bindings.
+ */
+ public void finishSetUp() {
+ if (!hasObb()) {
+ return;
+ }
+ final String mainObbDir = String.format("/storage/emulated/0/Android/obb/%s", mPackageName);
+ final String packageObbDirRoot =
+ String.format("/mnt/runtime/%s/emulated/0/Android/obb/", mPackageName);
+ final String[] obbDirs = {
+ packageObbDirRoot + "read",
+ packageObbDirRoot + "write",
+ packageObbDirRoot + "full",
+ packageObbDirRoot + "default",
+ String.format("/data/media/0/Android/obb/%s", mPackageName),
+ mainObbDir,
+ };
+ try {
+ Slog.i(TAG, "Creating obb directory '" + mainObbDir + "'");
+ final IVold vold = IVold.Stub.asInterface(ServiceManager.getServiceOrThrow("vold"));
+ vold.mkdirs(mainObbDir);
+ for (String d : obbDirs) {
+ mObbStorage.bindPermanent(d);
+ }
+ } catch (ServiceManager.ServiceNotFoundException ex) {
+ Slog.e(TAG, "vold service is not found.");
+ cleanUp();
+ } catch (IOException | RemoteException ex) {
+ Slog.e(TAG, "Failed to create obb dir at: " + mainObbDir, ex);
+ cleanUp();
+ }
+ }
+
+ /**
+ * Resets the states and unbinds storage instances for an installation session.
+ * TODO(b/136132412): make sure unnecessary binds are removed but useful storages are kept
+ */
+ public void cleanUp() {
+ if (mDefaultStorage != null && mDefaultDir != null) {
+ try {
+ mDefaultStorage.unBind(mDefaultDir);
+ } catch (IOException ignored) {
+ }
+ mDefaultDir = null;
+ mDefaultStorage = null;
+ }
+ if (mApkStorage != null && mStageDir != null) {
+ try {
+ mApkStorage.unBind(mStageDir.getAbsolutePath());
+ } catch (IOException ignored) {
+ }
+ mApkStorage = null;
+ }
+ if (mObbStorage != null && mObbDir != null) {
+ try {
+ mObbStorage.unBind(mObbDir);
+ } catch (IOException ignored) {
+ }
+ mObbDir = null;
+ mObbStorage = null;
+ }
+ }
+
+ private String getTempDir() {
+ final String tmpDirRoot = "/data/tmp";
+ final Random random = new Random();
+ final Path tmpDir =
+ Paths.get(tmpDirRoot, String.valueOf(random.nextInt(Integer.MAX_VALUE - 1)));
+ try {
+ Files.createDirectories(tmpDir);
+ } catch (Exception ex) {
+ Slog.e(TAG, "Failed to create dir", ex);
+ return null;
+ }
+ return tmpDir.toAbsolutePath().toString();
+ }
+}
diff --git a/core/java/android/permission/PermissionManager.java b/core/java/android/permission/PermissionManager.java
index 6c4ee016033d..09286feee6b9 100644
--- a/core/java/android/permission/PermissionManager.java
+++ b/core/java/android/permission/PermissionManager.java
@@ -17,6 +17,7 @@
package android.permission;
import android.Manifest;
+import android.annotation.CallbackExecutor;
import android.annotation.IntRange;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -29,6 +30,8 @@ import android.content.Context;
import android.content.pm.IPackageManager;
import android.content.pm.permission.SplitPermissionInfoParcelable;
import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.os.UserHandle;
import android.util.Slog;
import com.android.internal.annotations.Immutable;
@@ -36,6 +39,8 @@ import com.android.internal.annotations.Immutable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
+import java.util.concurrent.Executor;
+import java.util.function.Consumer;
/**
* System level service for accessing the permission capabilities of the platform.
@@ -59,6 +64,8 @@ public final class PermissionManager {
private final IPackageManager mPackageManager;
+ private final IPermissionManager mPermissionManager;
+
private List<SplitPermissionInfo> mSplitPermissionInfos;
/**
@@ -67,9 +74,12 @@ public final class PermissionManager {
* @param context The current context in which to operate.
* @hide
*/
- public PermissionManager(@NonNull Context context, IPackageManager packageManager) {
+ public PermissionManager(@NonNull Context context, IPackageManager packageManager)
+ throws ServiceManager.ServiceNotFoundException {
mContext = context;
mPackageManager = packageManager;
+ mPermissionManager = IPermissionManager.Stub.asInterface(
+ ServiceManager.getServiceOrThrow("permissionmgr"));
}
/**
@@ -145,6 +155,48 @@ public final class PermissionManager {
return mSplitPermissionInfos;
}
+ /**
+ * Grant default permissions to currently active LUI app
+ * @param packageName The package name for the LUI app
+ * @param user The user handle
+ * @param callback The callback provided by caller to be notified when grant completes
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(Manifest.permission.GRANT_RUNTIME_PERMISSIONS_TO_TELEPHONY_DEFAULTS)
+ public void grantDefaultPermissionsToLuiApp(
+ @NonNull String packageName, @NonNull UserHandle user,
+ @NonNull @CallbackExecutor Executor executor, @NonNull Consumer<Boolean> callback) {
+ try {
+ mPermissionManager.grantDefaultPermissionsToActiveLuiApp(
+ packageName, user.getIdentifier());
+ executor.execute(() -> callback.accept(true));
+ } catch (RemoteException e) {
+ e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Revoke default permissions to currently active LUI app
+ * @param packageNames The package names for the LUI apps
+ * @param user The user handle
+ * @param callback The callback provided by caller to be notified when grant completes
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(Manifest.permission.GRANT_RUNTIME_PERMISSIONS_TO_TELEPHONY_DEFAULTS)
+ public void revokeDefaultPermissionsFromLuiApps(
+ @NonNull String[] packageNames, @NonNull UserHandle user,
+ @NonNull @CallbackExecutor Executor executor, @NonNull Consumer<Boolean> callback) {
+ try {
+ mPermissionManager.revokeDefaultPermissionsFromLuiApps(
+ packageNames, user.getIdentifier());
+ executor.execute(() -> callback.accept(true));
+ } catch (RemoteException e) {
+ e.rethrowFromSystemServer();
+ }
+ }
+
private List<SplitPermissionInfo> splitPermissionInfoListToNonParcelableList(
List<SplitPermissionInfoParcelable> parcelableList) {
final int size = parcelableList.size();
diff --git a/core/java/android/provider/MediaStore.java b/core/java/android/provider/MediaStore.java
index 01f9c7300fa1..2c53025da350 100644
--- a/core/java/android/provider/MediaStore.java
+++ b/core/java/android/provider/MediaStore.java
@@ -20,6 +20,7 @@ import android.annotation.BytesLong;
import android.annotation.CurrentTimeMillisLong;
import android.annotation.CurrentTimeSecondsLong;
import android.annotation.DurationMillisLong;
+import android.annotation.IntDef;
import android.annotation.IntRange;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -78,6 +79,8 @@ import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.text.Collator;
import java.util.ArrayList;
import java.util.Collection;
@@ -205,8 +208,10 @@ public final class MediaStore {
public static final String PARAM_DELETE_DATA = "deletedata";
/** {@hide} */
+ @Deprecated
public static final String PARAM_INCLUDE_PENDING = "includePending";
/** {@hide} */
+ @Deprecated
public static final String PARAM_INCLUDE_TRASHED = "includeTrashed";
/** {@hide} */
public static final String PARAM_PROGRESS = "progress";
@@ -559,6 +564,101 @@ public final class MediaStore {
public static final String UNKNOWN_STRING = "<unknown>";
/**
+ * Specify a {@link Uri} that is "related" to the current operation being
+ * performed.
+ * <p>
+ * This is typically used to allow an operation that may normally be
+ * rejected, such as making a copy of a pre-existing image located under a
+ * {@link MediaColumns#RELATIVE_PATH} where new images are not allowed.
+ * <p>
+ * It's strongly recommended that when making a copy of pre-existing content
+ * that you define the "original document ID" GUID as defined by the <em>XMP
+ * Media Management</em> standard.
+ * <p>
+ * This key can be placed in a {@link Bundle} of extras and passed to
+ * {@link ContentResolver#insert}.
+ */
+ public static final String QUERY_ARG_RELATED_URI = "android:query-arg-related-uri";
+
+ /**
+ * Specify how {@link MediaColumns#IS_PENDING} items should be filtered when
+ * performing a {@link MediaStore} operation.
+ * <p>
+ * This key can be placed in a {@link Bundle} of extras and passed to
+ * {@link ContentResolver#query}, {@link ContentResolver#update}, or
+ * {@link ContentResolver#delete}.
+ * <p>
+ * By default, pending items are filtered away from operations.
+ */
+ @Match
+ public static final String QUERY_ARG_MATCH_PENDING = "android:query-arg-match-pending";
+
+ /**
+ * Specify how {@link MediaColumns#IS_TRASHED} items should be filtered when
+ * performing a {@link MediaStore} operation.
+ * <p>
+ * This key can be placed in a {@link Bundle} of extras and passed to
+ * {@link ContentResolver#query}, {@link ContentResolver#update}, or
+ * {@link ContentResolver#delete}.
+ * <p>
+ * By default, trashed items are filtered away from operations.
+ */
+ @Match
+ public static final String QUERY_ARG_MATCH_TRASHED = "android:query-arg-match-trashed";
+
+ /**
+ * Specify how {@link MediaColumns#IS_FAVORITE} items should be filtered
+ * when performing a {@link MediaStore} operation.
+ * <p>
+ * This key can be placed in a {@link Bundle} of extras and passed to
+ * {@link ContentResolver#query}, {@link ContentResolver#update}, or
+ * {@link ContentResolver#delete}.
+ * <p>
+ * By default, favorite items are <em>not</em> filtered away from
+ * operations.
+ */
+ @Match
+ public static final String QUERY_ARG_MATCH_FAVORITE = "android:query-arg-match-favorite";
+
+ /** @hide */
+ @IntDef(flag = true, prefix = { "MATCH_" }, value = {
+ MATCH_DEFAULT,
+ MATCH_INCLUDE,
+ MATCH_EXCLUDE,
+ MATCH_ONLY,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface Match {}
+
+ /**
+ * Value indicating that the default matching behavior should be used, as
+ * defined by the key documentation.
+ */
+ public static final int MATCH_DEFAULT = 0;
+
+ /**
+ * Value indicating that operations should include items matching the
+ * criteria defined by this key.
+ * <p>
+ * Note that items <em>not</em> matching the criteria <em>may</em> also be
+ * included depending on the default behavior documented by the key. If you
+ * want to operate exclusively on matching items, use {@link #MATCH_ONLY}.
+ */
+ public static final int MATCH_INCLUDE = 1;
+
+ /**
+ * Value indicating that operations should exclude items matching the
+ * criteria defined by this key.
+ */
+ public static final int MATCH_EXCLUDE = 2;
+
+ /**
+ * Value indicating that operations should only operate on items explicitly
+ * matching the criteria defined by this key.
+ */
+ public static final int MATCH_ONLY = 3;
+
+ /**
* Update the given {@link Uri} to also include any pending media items from
* calls such as
* {@link ContentResolver#query(Uri, String[], Bundle, CancellationSignal)}.
@@ -566,12 +666,16 @@ public final class MediaStore {
*
* @see MediaColumns#IS_PENDING
* @see MediaStore#getIncludePending(Uri)
+ * @deprecated consider migrating to {@link #QUERY_ARG_MATCH_PENDING} which
+ * is more expressive.
*/
+ @Deprecated
public static @NonNull Uri setIncludePending(@NonNull Uri uri) {
return setIncludePending(uri.buildUpon()).build();
}
/** @hide */
+ @Deprecated
public static @NonNull Uri.Builder setIncludePending(@NonNull Uri.Builder uriBuilder) {
return uriBuilder.appendQueryParameter(PARAM_INCLUDE_PENDING, "1");
}
@@ -582,7 +686,11 @@ public final class MediaStore {
*
* @see MediaColumns#IS_PENDING
* @see MediaStore#setIncludePending(Uri)
+ * @deprecated consider migrating to {@link #QUERY_ARG_MATCH_PENDING} which
+ * is more expressive.
+ * @removed
*/
+ @Deprecated
public static boolean getIncludePending(@NonNull Uri uri) {
return parseBoolean(uri.getQueryParameter(MediaStore.PARAM_INCLUDE_PENDING));
}
@@ -597,7 +705,11 @@ public final class MediaStore {
* @see MediaStore#setIncludeTrashed(Uri)
* @see MediaStore#trash(Context, Uri)
* @see MediaStore#untrash(Context, Uri)
+ * @deprecated consider migrating to {@link #QUERY_ARG_MATCH_TRASHED} which
+ * is more expressive.
+ * @removed
*/
+ @Deprecated
public static @NonNull Uri setIncludeTrashed(@NonNull Uri uri) {
return uri.buildUpon().appendQueryParameter(PARAM_INCLUDE_TRASHED, "1").build();
}
@@ -1000,7 +1112,7 @@ public final class MediaStore {
* the field to {@code 0}, or until they expire as defined by
* {@link #DATE_EXPIRES}.
*
- * @see MediaStore#setIncludePending(Uri)
+ * @see MediaStore#QUERY_ARG_MATCH_PENDING
*/
@Column(Cursor.FIELD_TYPE_INTEGER)
public static final String IS_PENDING = "is_pending";
@@ -1011,8 +1123,7 @@ public final class MediaStore {
* Trashed items are retained until they expire as defined by
* {@link #DATE_EXPIRES}.
*
- * @see MediaColumns#IS_TRASHED
- * @see MediaStore#setIncludeTrashed(Uri)
+ * @see MediaStore#QUERY_ARG_MATCH_TRASHED
* @see MediaStore#trash(Context, Uri)
* @see MediaStore#untrash(Context, Uri)
*/
@@ -1186,6 +1297,8 @@ public final class MediaStore {
/**
* Flag indicating if the media item has been marked as being a
* "favorite" by the user.
+ *
+ * @see MediaStore#QUERY_ARG_MATCH_FAVORITE
*/
@Column(Cursor.FIELD_TYPE_INTEGER)
public static final String IS_FAVORITE = "is_favorite";
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index fa8896ebea80..ad8d55313795 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -8782,6 +8782,22 @@ public final class Settings {
public static final String BUGREPORT_IN_POWER_MENU = "bugreport_in_power_menu";
/**
+ * The package name for the custom bugreport handler app. This app must be whitelisted.
+ * This is currently used only by Power Menu short press.
+ *
+ * @hide
+ */
+ public static final String CUSTOM_BUGREPORT_HANDLER_APP = "custom_bugreport_handler_app";
+
+ /**
+ * The user id for the custom bugreport handler app. This is currently used only by Power
+ * Menu short press.
+ *
+ * @hide
+ */
+ public static final String CUSTOM_BUGREPORT_HANDLER_USER = "custom_bugreport_handler_user";
+
+ /**
* Whether ADB is enabled.
*/
public static final String ADB_ENABLED = "adb_enabled";
@@ -8918,14 +8934,33 @@ public final class Settings {
* List of ISO country codes in which eUICC UI is shown. Country codes should be separated
* by comma.
*
- * <p>Used to hide eUICC UI from users who are currently in countries no carriers support
- * eUICC.
+ * Note: if {@link #EUICC_SUPPORTED_COUNTRIES} is empty, then {@link
+ * #EUICC_UNSUPPORTED_COUNTRIES} is used.
+ *
+ * <p>Used to hide eUICC UI from users who are currently in countries where no carriers
+ * support eUICC.
+ *
* @hide
*/
- //TODO(b/77914569) Changes this to System Api.
+ @SystemApi
public static final String EUICC_SUPPORTED_COUNTRIES = "euicc_supported_countries";
/**
+ * List of ISO country codes in which eUICC UI is not shown. Country codes should be
+ * separated by comma.
+ *
+ * Note: if {@link #EUICC_SUPPORTED_COUNTRIES} is empty, then {@link
+ * #EUICC_UNSUPPORTED_COUNTRIES} is used.
+ *
+ * <p>Used to hide eUICC UI from users who are currently in countries where no carriers
+ * support eUICC.
+ *
+ * @hide
+ */
+ @SystemApi
+ public static final String EUICC_UNSUPPORTED_COUNTRIES = "euicc_unsupported_countries";
+
+ /**
* Whether any activity can be resized. When this is true, any
* activity, regardless of manifest values, can be resized for multi-window.
* (0 = false, 1 = true)
diff --git a/core/java/android/provider/Telephony.java b/core/java/android/provider/Telephony.java
index 0e5200983bc0..22f90f62b114 100644
--- a/core/java/android/provider/Telephony.java
+++ b/core/java/android/provider/Telephony.java
@@ -44,7 +44,6 @@ import android.telephony.TelephonyManager;
import android.text.TextUtils;
import android.util.Patterns;
-import com.android.internal.telephony.PhoneConstants;
import com.android.internal.telephony.SmsApplication;
import java.lang.annotation.Retention;
@@ -1379,7 +1378,7 @@ public final class Telephony {
}
String format = intent.getStringExtra("format");
- int subId = intent.getIntExtra(PhoneConstants.SUBSCRIPTION_KEY,
+ int subId = intent.getIntExtra(SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX,
SubscriptionManager.getDefaultSmsSubscriptionId());
Rlog.v(TAG, " getMessagesFromIntent sub_id : " + subId);
diff --git a/core/java/android/service/controls/BooleanAction.aidl b/core/java/android/service/controls/BooleanAction.aidl
new file mode 100644
index 000000000000..730ad36749f7
--- /dev/null
+++ b/core/java/android/service/controls/BooleanAction.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.service.controls;
+
+parcelable BooleanAction; \ No newline at end of file
diff --git a/core/java/android/service/controls/BooleanAction.java b/core/java/android/service/controls/BooleanAction.java
new file mode 100644
index 000000000000..8508c635142f
--- /dev/null
+++ b/core/java/android/service/controls/BooleanAction.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.service.controls;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.Parcel;
+
+/**
+ * Action sent by a {@link ToggleTemplate}
+ * @hide
+ */
+public final class BooleanAction extends ControlAction {
+
+ private final boolean mNewState;
+
+ /**
+ * @param templateId the identifier of the {@link ToggleTemplate} that produced this action.
+ * @param newState new value for the state displayed by the {@link ToggleTemplate}.
+ */
+ public BooleanAction(@NonNull String templateId, boolean newState) {
+ this(templateId, newState, null);
+ }
+
+ /**
+ * @param templateId the identifier of the {@link ToggleTemplate} that originated this action.
+ * @param newValue new value for the state displayed by the {@link ToggleTemplate}.
+ * @param challengeValue a value sent by the user along with the action to authenticate. {@code}
+ * null is sent when no authentication is needed or has not been
+ * requested.
+ */
+ public BooleanAction(@NonNull String templateId, boolean newValue,
+ @Nullable String challengeValue) {
+ super(templateId, challengeValue);
+ mNewState = newValue;
+ }
+
+ BooleanAction(Parcel in) {
+ super(in);
+ mNewState = in.readByte() == 1;
+ }
+
+ /**
+ * The new state set for the button in the corresponding {@link ToggleTemplate}.
+ *
+ * @return {@code true} if the button was toggled from an {@code off} state to an {@code on}
+ * state.
+ */
+ public boolean getNewState() {
+ return mNewState;
+ }
+
+ /**
+ * @return {@link ControlAction#TYPE_BOOLEAN}
+ */
+ @Override
+ public int getActionType() {
+ return ControlAction.TYPE_BOOLEAN;
+ }
+
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ super.writeToParcel(dest, flags);
+ dest.writeByte(mNewState ? (byte) 1 : (byte) 0);
+ }
+
+ public static final @NonNull Creator<BooleanAction> CREATOR = new Creator<BooleanAction>() {
+ @Override
+ public BooleanAction createFromParcel(Parcel source) {
+ return new BooleanAction(source);
+ }
+
+ @Override
+ public BooleanAction[] newArray(int size) {
+ return new BooleanAction[size];
+ }
+ };
+}
diff --git a/core/java/android/service/controls/Control.aidl b/core/java/android/service/controls/Control.aidl
new file mode 100644
index 000000000000..f4964f2e15d7
--- /dev/null
+++ b/core/java/android/service/controls/Control.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (c) 2019, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.service.controls;
+
+parcelable Control; \ No newline at end of file
diff --git a/core/java/android/service/controls/Control.java b/core/java/android/service/controls/Control.java
new file mode 100644
index 000000000000..a69408c43df3
--- /dev/null
+++ b/core/java/android/service/controls/Control.java
@@ -0,0 +1,284 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.service.controls;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.Intent;
+import android.content.res.ColorStateList;
+import android.graphics.drawable.Icon;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import com.android.internal.util.Preconditions;
+
+/**
+ * Represents a physical object that can be represented by a {@link ControlTemplate} and whose
+ * properties may be modified through a {@link ControlAction}.
+ *
+ * The information is provided by a {@link ControlProviderService} and represents static
+ * information (not current status) about the device.
+ * <p>
+ * Each control needs a unique (per provider) identifier that is persistent across reboots of the
+ * system.
+ * <p>
+ * Each {@link Control} will have a name and an icon. The name is usually set up by the user in the
+ * {@link ControlProvider} while the icon is usually decided by the {@link ControlProvider} based
+ * on the type of device.
+ * <p>
+ * The {@link ControlTemplate.TemplateType} provided will be used as a hint when displaying this in
+ * non-interactive situations (for example when there's no state to display). This template is not
+ * the one that will be shown with the current state and provide interactions. That template is set
+ * using {@link ControlState}.
+ * <p>
+ * An {@link Intent} linking to the provider Activity that expands this {@link Control} should be
+ * provided.
+ * @hide
+ */
+public class Control implements Parcelable {
+
+ private final @NonNull String mControlId;
+ private final @NonNull Icon mIcon;
+ private final @NonNull CharSequence mTitle;
+ private final @Nullable ColorStateList mTintColor;
+ private final @NonNull Intent mAppIntent;
+ private final @ControlTemplate.TemplateType int mPrimaryType;
+
+ /**
+ * @param controlId the unique persistent identifier for this object.
+ * @param icon an icon to display identifying the control.
+ * @param title the user facing name of this control (e.g. "Bedroom thermostat").
+ * @param tintColor the color to tint parts of the element UI. If {@code null} is passed, the
+ * system accent color will be used.
+ * @param appIntent an intent linking to a page to interact with the corresponding device.
+ * @param primaryType the primary template for this type.
+ */
+ public Control(@NonNull String controlId,
+ @NonNull Icon icon,
+ @NonNull CharSequence title,
+ @Nullable ColorStateList tintColor,
+ @NonNull Intent appIntent,
+ int primaryType) {
+ Preconditions.checkNotNull(controlId);
+ Preconditions.checkNotNull(icon);
+ Preconditions.checkNotNull(title);
+ Preconditions.checkNotNull(appIntent);
+ mControlId = controlId;
+ mIcon = icon;
+ mTitle = title;
+ mTintColor = tintColor;
+ mAppIntent = appIntent;
+ mPrimaryType = primaryType;
+ }
+
+ public Control(Parcel in) {
+ mControlId = in.readString();
+ mIcon = Icon.CREATOR.createFromParcel(in);
+ mTitle = in.readCharSequence();
+ if (in.readByte() == 1) {
+ mTintColor = ColorStateList.CREATOR.createFromParcel(in);
+ } else {
+ mTintColor = null;
+ }
+ mAppIntent = Intent.CREATOR.createFromParcel(in);
+ mPrimaryType = in.readInt();
+ }
+
+ @NonNull
+ public String getControlId() {
+ return mControlId;
+ }
+
+ @NonNull
+ public Icon getIcon() {
+ return mIcon;
+ }
+
+ @NonNull
+ public CharSequence getTitle() {
+ return mTitle;
+ }
+
+ @Nullable
+ public ColorStateList getTint() {
+ return mTintColor;
+ }
+
+ @NonNull
+ public Intent getAppIntent() {
+ return mAppIntent;
+ }
+
+ @ControlTemplate.TemplateType
+ public int getPrimaryType() {
+ return mPrimaryType;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeString(mControlId);
+ mIcon.writeToParcel(dest, flags);
+ dest.writeCharSequence(mTitle);
+ if (mTintColor != null) {
+ dest.writeByte((byte) 1);
+ mTintColor.writeToParcel(dest, flags);
+ } else {
+ dest.writeByte((byte) 0);
+ }
+ mAppIntent.writeToParcel(dest, flags);
+ dest.writeInt(mPrimaryType);
+ }
+
+ public static final Creator<Control> CREATOR = new Creator<Control>() {
+ @Override
+ public Control createFromParcel(Parcel source) {
+ return new Control(source);
+ }
+
+ @Override
+ public Control[] newArray(int size) {
+ return new Control[size];
+ }
+ };
+
+ /**
+ * Builder class for {@link Control}.
+ *
+ * This class facilitates the creation of {@link Control}. It provides the following
+ * defaults for non-optional parameters:
+ * <ul>
+ * <li> Title: {@code ""}
+ * <li> Primary template: {@link ControlTemplate#TYPE_NONE}
+ * </ul>
+ */
+ public static class Builder {
+ private String mControlId;
+ private Icon mIcon;
+ private CharSequence mTitle = "";
+ private ColorStateList mTintColor;
+ private @Nullable Intent mAppIntent;
+ private @ControlTemplate.TemplateType int mPrimaryType = ControlTemplate.TYPE_NONE;
+
+ /**
+ * @param controlId the identifier for the {@link Control}.
+ * @param icon the icon for the {@link Control}.
+ * @param appIntent the intent linking to the device Activity.
+ */
+ public Builder(@NonNull String controlId,
+ @NonNull Icon icon,
+ @NonNull Intent appIntent) {
+ Preconditions.checkNotNull(controlId);
+ Preconditions.checkNotNull(icon);
+ Preconditions.checkNotNull(appIntent);
+ mControlId = controlId;
+ mIcon = icon;
+ mAppIntent = appIntent;
+ }
+
+ /**
+ * Creates a {@link Builder} using an existing {@link Control} as a base.
+ * @param control base for the builder.
+ */
+ public Builder(@NonNull Control control) {
+ Preconditions.checkNotNull(control);
+ mControlId = control.mControlId;
+ mIcon = control.mIcon;
+ mTitle = control.mTitle;
+ mTintColor = control.mTintColor;
+ mAppIntent = control.mAppIntent;
+ mPrimaryType = control.mPrimaryType;
+ }
+
+ /**
+ * @param controlId the identifier for the {@link Control}.
+ * @return {@code this}
+ */
+ public Builder setControlId(@NonNull String controlId) {
+ Preconditions.checkNotNull(controlId);
+ mControlId = controlId;
+ return this;
+ }
+
+ /**
+ * @param icon the icon for the {@link Control}
+ * @return {@code this}
+ */
+ @NonNull
+ public Builder setIcon(@NonNull Icon icon) {
+ Preconditions.checkNotNull(icon);
+ mIcon = icon;
+ return this;
+ }
+
+ /**
+ * @param title the user facing name of the {@link Control}
+ * @return {@code this}
+ */
+ @NonNull
+ public Builder setTitle(@NonNull CharSequence title) {
+ Preconditions.checkNotNull(title);
+ mTitle = title;
+ return this;
+ }
+
+ /**
+ * @param tint colors for tinting parts of the {@link Control} UI. Passing {@code null} will
+ * default to using the current color accent.
+ * @return {@code this}
+ */
+ @NonNull
+ public Builder setTint(@Nullable ColorStateList tint) {
+ mTintColor = tint;
+ return this;
+ }
+
+ /**
+ * @param appIntent an {@link Intent} linking to an Activity for the {@link Control}
+ * @return {@code this}
+ */
+ @NonNull
+ public Builder setAppIntent(@NonNull Intent appIntent) {
+ Preconditions.checkNotNull(appIntent);
+ mAppIntent = appIntent;
+ return this;
+ }
+
+ /**
+ * @param type type to use as default in the {@link Control}
+ * @return {@code this}
+ */
+ @NonNull
+ public Builder setPrimaryType(@ControlTemplate.TemplateType int type) {
+ mPrimaryType = type;
+ return this;
+ }
+
+ /**
+ * Build a {@link Control}
+ * @return a valid {@link Control}
+ */
+ @NonNull
+ public Control build() {
+ return new Control(mControlId, mIcon, mTitle, mTintColor, mAppIntent, mPrimaryType);
+ }
+ }
+}
diff --git a/core/java/android/service/controls/ControlAction.aidl b/core/java/android/service/controls/ControlAction.aidl
new file mode 100644
index 000000000000..e1a5276b70d6
--- /dev/null
+++ b/core/java/android/service/controls/ControlAction.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.service.controls;
+
+parcelable ControlAction; \ No newline at end of file
diff --git a/core/java/android/service/controls/ControlAction.java b/core/java/android/service/controls/ControlAction.java
new file mode 100644
index 000000000000..8b759556b597
--- /dev/null
+++ b/core/java/android/service/controls/ControlAction.java
@@ -0,0 +1,189 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.service.controls;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import com.android.internal.util.Preconditions;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * An abstract action that is executed from a {@link ControlTemplate}.
+ *
+ * The action may have a value to authenticate the input, when the provider has requested it to
+ * complete the action.
+ * @hide
+ */
+public abstract class ControlAction implements Parcelable {
+
+ /**
+ * @hide
+ */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef({
+ TYPE_BOOLEAN,
+ TYPE_FLOAT
+ })
+ public @interface ActionType {};
+
+ /**
+ * The identifier of {@link BooleanAction}.
+ */
+ public static final @ActionType int TYPE_BOOLEAN = 0;
+
+ /**
+ * The identifier of {@link FloatAction}.
+ */
+ public static final @ActionType int TYPE_FLOAT = 1;
+
+ /**
+ * @hide
+ */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef({
+ RESPONSE_OK,
+ RESPONSE_FAIL,
+ RESPONSE_CHALLENGE_ACK,
+ RESPONSE_CHALLENGE_PIN,
+ RESPONSE_CHALLENGE_PASSPHRASE
+ })
+ public @interface ResponseResult {};
+
+ /**
+ * Response code for {@link IControlsProviderCallback#onControlActionResponse} indicating that
+ * the action has been performed. The action may still fail later and the state may not change.
+ */
+ public static final @ResponseResult int RESPONSE_OK = 0;
+ /**
+ * Response code for {@link IControlsProviderCallback#onControlActionResponse} indicating that
+ * the action has failed.
+ */
+ public static final @ResponseResult int RESPONSE_FAIL = 1;
+ /**
+ * Response code for {@link IControlsProviderCallback#onControlActionResponse} indicating that
+ * in order for the action to be performed, acknowledgment from the user is required.
+ */
+ public static final @ResponseResult int RESPONSE_CHALLENGE_ACK = 2;
+ /**
+ * Response code for {@link IControlsProviderCallback#onControlActionResponse} indicating that
+ * in order for the action to be performed, a PIN is required.
+ */
+ public static final @ResponseResult int RESPONSE_CHALLENGE_PIN = 3;
+ /**
+ * Response code for {@link IControlsProviderCallback#onControlActionResponse} indicating that
+ * in order for the action to be performed, an alphanumeric passphrase is required.
+ */
+ public static final @ResponseResult int RESPONSE_CHALLENGE_PASSPHRASE = 4;
+
+ /**
+ * The {@link ActionType} associated with this class.
+ */
+ public abstract @ActionType int getActionType();
+
+ private final @NonNull String mTemplateId;
+ private final @Nullable String mChallengeValue;
+
+ private ControlAction() {
+ mTemplateId = "";
+ mChallengeValue = null;
+ }
+
+ /**
+ * @hide
+ */
+ ControlAction(@NonNull String templateId, @Nullable String challengeValue) {
+ Preconditions.checkNotNull(templateId);
+ mTemplateId = templateId;
+ mChallengeValue = challengeValue;
+ }
+
+ /**
+ * @hide
+ */
+ ControlAction(Parcel in) {
+ mTemplateId = in.readString();
+ if (in.readByte() == 1) {
+ mChallengeValue = in.readString();
+ } else {
+ mChallengeValue = null;
+ }
+ }
+
+ /**
+ * The identifier of the {@link ControlTemplate} that originated this action
+ */
+ @NonNull
+ public String getTemplateId() {
+ return mTemplateId;
+ }
+
+ /**
+ * The challenge value used to authenticate certain actions, if available.
+ */
+ @Nullable
+ public String getChallengeValue() {
+ return mChallengeValue;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(getActionType());
+ dest.writeString(mTemplateId);
+ if (mChallengeValue != null) {
+ dest.writeByte((byte) 1);
+ dest.writeString(mChallengeValue);
+ } else {
+ dest.writeByte((byte) 0);
+ }
+ }
+
+ public static final @NonNull Creator<ControlAction> CREATOR = new Creator<ControlAction>() {
+ @Override
+ public ControlAction createFromParcel(Parcel source) {
+ int type = source.readInt();
+ return createActionFromType(type, source);
+ }
+
+ @Override
+ public ControlAction[] newArray(int size) {
+ return new ControlAction[size];
+ }
+ };
+
+ private static ControlAction createActionFromType(@ActionType int type, Parcel source) {
+ switch(type) {
+ case TYPE_BOOLEAN:
+ return BooleanAction.CREATOR.createFromParcel(source);
+ case TYPE_FLOAT:
+ return FloatAction.CREATOR.createFromParcel(source);
+ default:
+ return null;
+ }
+ }
+
+}
diff --git a/core/java/android/service/controls/ControlButton.aidl b/core/java/android/service/controls/ControlButton.aidl
new file mode 100644
index 000000000000..6a7262d9542e
--- /dev/null
+++ b/core/java/android/service/controls/ControlButton.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2019, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.service.controls;
+
+parcelable ControlButton; \ No newline at end of file
diff --git a/core/java/android/service/controls/ControlButton.java b/core/java/android/service/controls/ControlButton.java
new file mode 100644
index 000000000000..fed31158be35
--- /dev/null
+++ b/core/java/android/service/controls/ControlButton.java
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.service.controls;
+
+import android.annotation.NonNull;
+import android.graphics.drawable.Icon;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import com.android.internal.util.Preconditions;
+
+/**
+ * Button element for {@link ControlTemplate}.
+ * @hide
+ */
+public class ControlButton implements Parcelable {
+
+ private final boolean mActive;
+ private final @NonNull Icon mIcon;
+ private final @NonNull CharSequence mContentDescription;
+
+ /**
+ * @param active true if the button should be rendered as active.
+ * @param icon icon to display in the button.
+ * @param contentDescription content description for the button.
+ */
+ public ControlButton(boolean active, @NonNull Icon icon,
+ @NonNull CharSequence contentDescription) {
+ Preconditions.checkNotNull(icon);
+ Preconditions.checkNotNull(contentDescription);
+ mActive = active;
+ mIcon = icon;
+ mContentDescription = contentDescription;
+ }
+
+ /**
+ * Whether the button should be rendered in its active state.
+ */
+ public boolean isActive() {
+ return mActive;
+ }
+
+ /**
+ * The icon for this button.
+ */
+ @NonNull
+ public Icon getIcon() {
+ return mIcon;
+ }
+
+ /**
+ * The content description for this button.
+ */
+ @NonNull
+ public CharSequence getContentDescription() {
+ return mContentDescription;
+ }
+
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeByte(mActive ? (byte) 1 : (byte) 0);
+ mIcon.writeToParcel(dest, flags);
+ dest.writeCharSequence(mContentDescription);
+ }
+
+ ControlButton(Parcel in) {
+ mActive = in.readByte() != 0;
+ mIcon = Icon.CREATOR.createFromParcel(in);
+ mContentDescription = in.readCharSequence();
+ }
+
+ public static final Creator<ControlButton> CREATOR = new Creator<ControlButton>() {
+ @Override
+ public ControlButton createFromParcel(Parcel source) {
+ return new ControlButton(source);
+ }
+
+ @Override
+ public ControlButton[] newArray(int size) {
+ return new ControlButton[size];
+ }
+ };
+}
diff --git a/core/java/android/service/controls/ControlState.aidl b/core/java/android/service/controls/ControlState.aidl
new file mode 100644
index 000000000000..520d85b47d3e
--- /dev/null
+++ b/core/java/android/service/controls/ControlState.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (c) 2019, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.service.controls;
+
+parcelable ControlState; \ No newline at end of file
diff --git a/core/java/android/service/controls/ControlState.java b/core/java/android/service/controls/ControlState.java
new file mode 100644
index 000000000000..804aef798eb5
--- /dev/null
+++ b/core/java/android/service/controls/ControlState.java
@@ -0,0 +1,318 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.service.controls;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.res.ColorStateList;
+import android.graphics.drawable.Icon;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import com.android.internal.util.Preconditions;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Current state for a {@link Control}.
+ *
+ * Collects information to render the current state of a {@link Control} as well as possible action
+ * that can be performed on it. Some of the information may temporarily override the defaults
+ * provided by the corresponding {@link Control}, while this state is being displayed.
+ *
+ * Additionally, this can be used to modify information related to the corresponding
+ * {@link Control}.
+ * @hide
+ */
+public final class ControlState implements Parcelable {
+
+ /**
+ * @hide
+ */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef({
+ STATUS_OK,
+ STATUS_NOT_FOUND,
+ STATUS_ERROR,
+ STATUS_DISABLED,
+ })
+ public @interface Status {};
+
+ /**
+ * The device corresponding to the {@link Control} is responding correctly.
+ */
+ public static final int STATUS_OK = 0;
+
+ /**
+ * The device corresponding to the {@link Control} cannot be found or was removed.
+ */
+ public static final int STATUS_NOT_FOUND = 1;
+
+ /**
+ * The device corresponding to the {@link Control} is in an error state.
+ */
+ public static final int STATUS_ERROR = 2;
+
+ /**
+ * The {@link Control} is currently disabled.
+ */
+ public static final int STATUS_DISABLED = 3;
+
+ private final @NonNull Control mControl;
+ private final @Status int mStatus;
+ private final @NonNull ControlTemplate mControlTemplate;
+ private final @NonNull CharSequence mStatusText;
+ private final @Nullable Icon mOverrideIcon;
+ private final @Nullable ColorStateList mOverrideTint;
+
+ /**
+ * @param control the {@link Control} this state should be applied to. Can be used to
+ * update information about the {@link Control}
+ * @param status the current status of the {@link Control}.
+ * @param controlTemplate the template to be used to render the {@link Control}.
+ * @param statusText the text describing the current status.
+ * @param overrideIcon the icon to temporarily override the one provided in
+ * {@link Control#getIcon()}. Pass {@code null} to use the icon in
+ * {@link Control#getIcon()}.
+ * @param overrideTint the colors to temporarily override those provided in
+ * {@link Control#getTint()}. Pass {@code null} to use the colors in
+ * {@link Control#getTint()}.
+ */
+ public ControlState(@NonNull Control control,
+ int status,
+ @NonNull ControlTemplate controlTemplate,
+ @NonNull CharSequence statusText,
+ @Nullable Icon overrideIcon,
+ @Nullable ColorStateList overrideTint) {
+ Preconditions.checkNotNull(control);
+ Preconditions.checkNotNull(controlTemplate);
+ Preconditions.checkNotNull(statusText);
+
+ mControl = control;
+ mStatus = status;
+ mControlTemplate = controlTemplate;
+ mOverrideIcon = overrideIcon;
+ mStatusText = statusText;
+ mOverrideTint = overrideTint;
+ }
+
+ ControlState(Parcel in) {
+ mControl = Control.CREATOR.createFromParcel(in);
+ mStatus = in.readInt();
+ mControlTemplate = ControlTemplate.CREATOR.createFromParcel(in);
+ mStatusText = in.readCharSequence();
+ if (in.readByte() == 1) {
+ mOverrideIcon = Icon.CREATOR.createFromParcel(in);
+ } else {
+ mOverrideIcon = null;
+ }
+ if (in.readByte() == 1) {
+ mOverrideTint = ColorStateList.CREATOR.createFromParcel(in);
+ } else {
+ mOverrideTint = null;
+ }
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Status
+ public int getStatus() {
+ return mStatus;
+ }
+
+ @NonNull
+ public ControlTemplate getControlTemplate() {
+ return mControlTemplate;
+ }
+
+ @Nullable
+ public Icon getOverrideIcon() {
+ return mOverrideIcon;
+ }
+
+ @NonNull
+ public CharSequence getStatusText() {
+ return mStatusText;
+ }
+
+ @Nullable
+ public ColorStateList getOverrideTint() {
+ return mOverrideTint;
+ }
+
+ @NonNull
+ public Control getControl() {
+ return mControl;
+ }
+
+ @NonNull
+ public String getControlId() {
+ return mControl.getControlId();
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ mControl.writeToParcel(dest, flags);
+ dest.writeInt(mStatus);
+ mControlTemplate.writeToParcel(dest, flags);
+ dest.writeCharSequence(mStatusText);
+ if (mOverrideIcon != null) {
+ dest.writeByte((byte) 1);
+ mOverrideIcon.writeToParcel(dest, flags);
+ } else {
+ dest.writeByte((byte) 0);
+ }
+ if (mOverrideTint != null) {
+ dest.writeByte((byte) 1);
+ mOverrideTint.writeToParcel(dest, flags);
+ } else {
+ dest.writeByte((byte) 0);
+ }
+ }
+
+ public static final Creator<ControlState> CREATOR = new Creator<ControlState>() {
+ @Override
+ public ControlState createFromParcel(Parcel source) {
+ return new ControlState(source);
+ }
+
+ @Override
+ public ControlState[] newArray(int size) {
+ return new ControlState[size];
+ }
+ };
+
+ /**
+ * Builder class for {@link ControlState}.
+ *
+ * This class facilitates the creation of {@link ControlState}. It provides the following
+ * defaults for non-optional parameters:
+ * <ul>
+ * <li> Status: {@link ControlState#STATUS_OK}
+ * <li> Control template: {@link ControlTemplate#NO_TEMPLATE}
+ * <li> Status text: {@code ""}
+ * </ul>
+ */
+ public static class Builder {
+ private @NonNull Control mControl;
+ private @Status int mStatus = STATUS_OK;
+ private @NonNull ControlTemplate mControlTemplate = ControlTemplate.NO_TEMPLATE;
+ private @NonNull CharSequence mStatusText = "";
+ private @Nullable Icon mOverrideIcon;
+ private @Nullable ColorStateList mOverrideTint;
+
+ /**
+ * @param control the {@link Control} that the resulting {@link ControlState} refers to.
+ */
+ public Builder(@NonNull Control control) {
+ Preconditions.checkNotNull(control);
+ mControl = control;
+ }
+
+ /**
+ * Creates a {@link Builder} using an existing {@link ControlState} as a base.
+ * @param controlState base for the builder.
+ */
+ public Builder(@NonNull ControlState controlState) {
+ Preconditions.checkNotNull(controlState);
+ mControl = controlState.mControl;
+ mControlTemplate = controlState.mControlTemplate;
+ mOverrideIcon = controlState.mOverrideIcon;
+ mStatusText = controlState.mStatusText;
+ mOverrideTint = controlState.mOverrideTint;
+ }
+
+
+ /**
+ * @param control the updated {@link Control} information.
+ * @return {@code this}
+ */
+ @NonNull
+ public Builder setControl(@NonNull Control control) {
+ mControl = control;
+ return this;
+ }
+
+ /**
+ * @param status the current status of the {@link Control}
+ * @return {@code this}
+ */
+ @NonNull
+ public Builder setStatus(@Status int status) {
+ mStatus = status;
+ return this;
+ }
+
+ /**
+ * @param controlTemplate the template to use when rendering the {@code Control}.
+ * @return {@code this}
+ */
+ @NonNull
+ public Builder setControlTemplate(@NonNull ControlTemplate controlTemplate) {
+ Preconditions.checkNotNull(controlTemplate);
+ mControlTemplate = controlTemplate;
+ return this;
+ }
+
+ /**
+ * @param statusText the user-visible description of the status.
+ * @return {@code this}
+ */
+ @NonNull
+ public Builder setStatusText(@NonNull CharSequence statusText) {
+ Preconditions.checkNotNull(statusText);
+ mStatusText = statusText;
+ return this;
+ }
+
+ /**
+ * @param overrideIcon the icon to override the one defined in the corresponding
+ * {@code Control}. Pass {@code null} to remove the override.
+ * @return {@code this}
+ */
+ @NonNull
+ public Builder setOverrideIcon(@Nullable Icon overrideIcon) {
+ mOverrideIcon = overrideIcon;
+ return this;
+ }
+
+ /**
+ * @param overrideTint the colors to override the ones defined in the corresponding
+ * {@code Control}. Pass {@code null} to remove the override.
+ * @return {@code this}
+ */
+ @NonNull
+ public Builder setOverrideTint(@Nullable ColorStateList overrideTint) {
+ mOverrideTint = overrideTint;
+ return this;
+ }
+
+ /**
+ * @return a new {@link ControlState}
+ */
+ public ControlState build() {
+ return new ControlState(mControl, mStatus, mControlTemplate, mStatusText,
+ mOverrideIcon, mOverrideTint);
+ }
+ }
+}
+
diff --git a/core/java/android/service/controls/ControlTemplate.aidl b/core/java/android/service/controls/ControlTemplate.aidl
new file mode 100644
index 000000000000..ecb948c8a306
--- /dev/null
+++ b/core/java/android/service/controls/ControlTemplate.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (c) 2019, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.service.controls;
+
+parcelable ControlTemplate; \ No newline at end of file
diff --git a/core/java/android/service/controls/ControlTemplate.java b/core/java/android/service/controls/ControlTemplate.java
new file mode 100644
index 000000000000..e559862e86d6
--- /dev/null
+++ b/core/java/android/service/controls/ControlTemplate.java
@@ -0,0 +1,167 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.service.controls;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import com.android.internal.util.Preconditions;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * An abstract input template for a {@link Control}.
+ *
+ * Specifies what layout is presented to the user when a {@link ControlState} is assigned to a
+ * particular {@link Control}.
+ * <p>
+ * Some instances of {@link Control} can originate actions (via user interaction) to modify its
+ * associated state. The actions available to a given {@link Control} in a particular
+ * {@link ControlState} are determined by its {@link ControlTemplate}.
+ * @see ControlAction
+ * @hide
+ */
+public abstract class ControlTemplate implements Parcelable {
+
+ /**
+ * Singleton representing a {@link Control} with no input.
+ */
+ public static final ControlTemplate NO_TEMPLATE = new ControlTemplate("") {
+ @Override
+ public int getTemplateType() {
+ return TYPE_NONE;
+ }
+ };
+
+ /**
+ * @hide
+ */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef({
+ TYPE_NONE,
+ TYPE_TOGGLE,
+ TYPE_RANGE,
+ TYPE_THUMBNAIL,
+ TYPE_DISCRETE_TOGGLE,
+ TYPE_COORD_RANGE
+ })
+ public @interface TemplateType {}
+
+ /**
+ * Type identifier of {@link ControlTemplate#NO_TEMPLATE}.
+ */
+ public static final int TYPE_NONE = 0;
+
+ /**
+ * Type identifier of {@link ToggleTemplate}.
+ */
+ public static final int TYPE_TOGGLE = 1;
+
+ /**
+ * Type identifier of {@link RangeTemplate}.
+ */
+ public static final int TYPE_RANGE = 2;
+
+ /**
+ * Type identifier of {@link ThumbnailTemplate}.
+ */
+ public static final int TYPE_THUMBNAIL = 3;
+
+ /**
+ * Type identifier of {@link DiscreteToggleTemplate}.
+ */
+ public static final int TYPE_DISCRETE_TOGGLE = 4;
+
+ /**
+ * @hide
+ */
+ public static final int TYPE_COORD_RANGE = 5;
+
+ private @NonNull final String mTemplateId;
+
+ /**
+ * @return the identifier for this object.
+ */
+ public String getTemplateId() {
+ return mTemplateId;
+ }
+
+ /**
+ * The {@link TemplateType} associated with this class.
+ */
+ public abstract @TemplateType int getTemplateType();
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(getTemplateType());
+ dest.writeString(mTemplateId);
+ }
+
+ private ControlTemplate() {
+ mTemplateId = "";
+ }
+
+ ControlTemplate(Parcel in) {
+ mTemplateId = in.readString();
+ }
+
+ /**
+ * @hide
+ */
+ ControlTemplate(@NonNull String templateId) {
+ Preconditions.checkNotNull(templateId);
+ mTemplateId = templateId;
+ }
+
+ public static final Creator<ControlTemplate> CREATOR = new Creator<ControlTemplate>() {
+ @Override
+ public ControlTemplate createFromParcel(Parcel source) {
+ int type = source.readInt();
+ return createTemplateFromType(type, source);
+ }
+
+ @Override
+ public ControlTemplate[] newArray(int size) {
+ return new ControlTemplate[size];
+ }
+ };
+
+ private static ControlTemplate createTemplateFromType(@TemplateType int type, Parcel source) {
+ switch(type) {
+ case TYPE_TOGGLE:
+ return ToggleTemplate.CREATOR.createFromParcel(source);
+ case TYPE_RANGE:
+ return RangeTemplate.CREATOR.createFromParcel(source);
+ case TYPE_THUMBNAIL:
+ return ThumbnailTemplate.CREATOR.createFromParcel(source);
+ case TYPE_DISCRETE_TOGGLE:
+ return DiscreteToggleTemplate.CREATOR.createFromParcel(source);
+ case TYPE_NONE:
+ return NO_TEMPLATE;
+ default:
+ return null;
+ }
+ }
+}
diff --git a/core/java/android/service/controls/DiscreteToggleTemplate.java b/core/java/android/service/controls/DiscreteToggleTemplate.java
new file mode 100644
index 000000000000..5167af41c2f0
--- /dev/null
+++ b/core/java/android/service/controls/DiscreteToggleTemplate.java
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.service.controls;
+
+import android.annotation.NonNull;
+import android.os.Parcel;
+
+import com.android.internal.util.Preconditions;
+
+/**
+ * A template for a {@link Control} with two discrete inputs.
+ *
+ * The two inputs represent a <i>Negative</i> input and a <i>Positive</i> input.
+ * <p>
+ * When one of the buttons is actioned, a {@link BooleanAction} will be sent.
+ * {@link BooleanAction#getNewState} will be {@code false} if the button was
+ * {@link DiscreteToggleTemplate#getNegativeButton} and {@code true} if the button was
+ * {@link DiscreteToggleTemplate#getPositiveButton}.
+ * @hide
+ */
+public class DiscreteToggleTemplate extends ControlTemplate {
+
+ private final @NonNull ControlButton mNegativeButton;
+ private final @NonNull ControlButton mPositiveButton;
+
+ /**
+ * @param templateId the identifier for this template object
+ * @param negativeButton a {@ControlButton} for the <i>Negative</i> input
+ * @param positiveButton a {@ControlButton} for the <i>Positive</i> input
+ */
+ public DiscreteToggleTemplate(@NonNull String templateId,
+ @NonNull ControlButton negativeButton,
+ @NonNull ControlButton positiveButton) {
+ super(templateId);
+ Preconditions.checkNotNull(negativeButton);
+ Preconditions.checkNotNull(positiveButton);
+ mNegativeButton = negativeButton;
+ mPositiveButton = positiveButton;
+ }
+
+ DiscreteToggleTemplate(Parcel in) {
+ super(in);
+ this.mNegativeButton = ControlButton.CREATOR.createFromParcel(in);
+ this.mPositiveButton = ControlButton.CREATOR.createFromParcel(in);
+ }
+
+ /**
+ * The {@link ControlButton} associated with the <i>Negative</i> action.
+ */
+ @NonNull
+ public ControlButton getNegativeButton() {
+ return mNegativeButton;
+ }
+
+ /**
+ * The {@link ControlButton} associated with the <i>Positive</i> action.
+ */
+ @NonNull
+ public ControlButton getPositiveButton() {
+ return mPositiveButton;
+ }
+
+ /**
+ * @return {@link ControlTemplate#TYPE_DISCRETE_TOGGLE}
+ */
+ @Override
+ public int getTemplateType() {
+ return TYPE_DISCRETE_TOGGLE;
+ }
+
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ super.writeToParcel(dest, flags);
+ mNegativeButton.writeToParcel(dest, flags);
+ mPositiveButton.writeToParcel(dest, flags);
+ }
+
+ public static final Creator<DiscreteToggleTemplate> CREATOR =
+ new Creator<DiscreteToggleTemplate>() {
+ @Override
+ public DiscreteToggleTemplate createFromParcel(Parcel source) {
+ return new DiscreteToggleTemplate(source);
+ }
+
+ @Override
+ public DiscreteToggleTemplate[] newArray(int size) {
+ return new DiscreteToggleTemplate[size];
+ }
+ };
+}
diff --git a/core/java/android/service/controls/FloatAction.aidl b/core/java/android/service/controls/FloatAction.aidl
new file mode 100644
index 000000000000..dbc0f726880c
--- /dev/null
+++ b/core/java/android/service/controls/FloatAction.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.service.controls;
+
+parcelable FloatAction; \ No newline at end of file
diff --git a/core/java/android/service/controls/FloatAction.java b/core/java/android/service/controls/FloatAction.java
new file mode 100644
index 000000000000..fe6db10a98cd
--- /dev/null
+++ b/core/java/android/service/controls/FloatAction.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.service.controls;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.Parcel;
+
+/**
+ * Action sent by a {@link RangeTemplate}.
+ * @hide
+ */
+public final class FloatAction extends ControlAction {
+
+ private final float mNewValue;
+
+ /**
+ * @param templateId the identifier of the {@link RangeTemplate} that produced this action.
+ * @param newValue new value for the state displayed by the {@link RangeTemplate}.
+ */
+ public FloatAction(@NonNull String templateId, float newValue) {
+ this(templateId, newValue, null);
+ }
+
+ /**
+ * @param templateId the identifier of the {@link RangeTemplate} that originated this action.
+ * @param newValue new value for the state of the {@link RangeTemplate}.
+ * @param challengeValue a value sent by the user along with the action to authenticate. {@code}
+ * null is sent when no authentication is needed or has not been
+ * requested.
+ */
+
+ public FloatAction(@NonNull String templateId, float newValue,
+ @Nullable String challengeValue) {
+ super(templateId, challengeValue);
+ mNewValue = newValue;
+ }
+
+ public FloatAction(Parcel in) {
+ super(in);
+ mNewValue = in.readFloat();
+ }
+
+ /**
+ * The new value set for the range in the corresponding {@link RangeTemplate}.
+ */
+ public float getNewValue() {
+ return mNewValue;
+ }
+
+ /**
+ * @return {@link ControlAction#TYPE_FLOAT}
+ */
+ @Override
+ public int getActionType() {
+ return TYPE_FLOAT;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ super.writeToParcel(dest, flags);
+ dest.writeFloat(mNewValue);
+ }
+
+ public static final @NonNull Creator<FloatAction> CREATOR = new Creator<FloatAction>() {
+ @Override
+ public FloatAction createFromParcel(Parcel source) {
+ return new FloatAction(source);
+ }
+
+ @Override
+ public FloatAction[] newArray(int size) {
+ return new FloatAction[size];
+ }
+ };
+}
diff --git a/core/java/android/service/controls/IControlsProvider.aidl b/core/java/android/service/controls/IControlsProvider.aidl
new file mode 100644
index 000000000000..f778653eb3d3
--- /dev/null
+++ b/core/java/android/service/controls/IControlsProvider.aidl
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2019, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.service.controls;
+
+import android.service.controls.ControlAction;
+
+/** @hide */
+oneway interface IControlsProvider {
+ void load();
+
+ void subscribe(in List<String> controlIds);
+
+ void unsubscribe();
+
+ void onAction(in String controlId, in ControlAction action);
+} \ No newline at end of file
diff --git a/core/java/android/service/controls/IControlsProviderCallback.aidl b/core/java/android/service/controls/IControlsProviderCallback.aidl
new file mode 100644
index 000000000000..3dbb68c1c7f0
--- /dev/null
+++ b/core/java/android/service/controls/IControlsProviderCallback.aidl
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2019, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.service.controls;
+
+import android.service.controls.Control;
+import android.service.controls.ControlState;
+
+/** @hide */
+oneway interface IControlsProviderCallback {
+ void onLoad(in List<Control> controls);
+
+ void onRefreshState(in List<ControlState> controlStates);
+
+ void onControlActionResponse(in String controlId, int response);
+} \ No newline at end of file
diff --git a/core/java/android/service/controls/RangeTemplate.aidl b/core/java/android/service/controls/RangeTemplate.aidl
new file mode 100644
index 000000000000..a3d1ca074276
--- /dev/null
+++ b/core/java/android/service/controls/RangeTemplate.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (c) 2019, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.service.controls;
+
+parcelable RangeTemplate; \ No newline at end of file
diff --git a/core/java/android/service/controls/RangeTemplate.java b/core/java/android/service/controls/RangeTemplate.java
new file mode 100644
index 000000000000..70bf2dd4aad4
--- /dev/null
+++ b/core/java/android/service/controls/RangeTemplate.java
@@ -0,0 +1,190 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.service.controls;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.Parcel;
+
+import com.android.internal.util.Preconditions;
+
+import java.security.InvalidParameterException;
+
+/**
+ * A template for a {@link Control} with inputs in a "continuous" range of values.
+ *
+ * @see FloatAction
+ * @hide
+ */
+public final class RangeTemplate extends ControlTemplate {
+
+ private final float mMinValue;
+ private final float mMaxValue;
+ private final float mCurrentValue;
+ private final float mStepValue;
+ private final @NonNull CharSequence mFormatString;
+
+ /**
+ * Construct a new {@link RangeTemplate}.
+ *
+ * The range must be valid, meaning:
+ * <ul>
+ * <li> {@code minValue} < {@code maxValue}
+ * <li> {@code minValue} < {@code currentValue}
+ * <li> {@code currentValue} < {@code maxValue}
+ * <li> 0 < {@code stepValue}
+ * </ul>
+ * <p>
+ * The current value of the Control will be formatted accordingly.
+ *
+ * @param templateId the identifier for this template object
+ * @param minValue minimum value for the input
+ * @param maxValue maximum value for the input
+ * @param currentValue the current value of the {@link ControlState} containing this object.
+ * @param stepValue minimum value of increments/decrements when interacting with this control.
+ * @param formatString a formatting string as per {@link String#format} used to display the
+ * {@code currentValue}. If {@code null} is passed, the "%.1f" is used.
+ * @throws InvalidParameterException if the parameters passed do not make a valid range.
+ */
+ public RangeTemplate(@NonNull String templateId,
+ float minValue,
+ float maxValue,
+ float currentValue,
+ float stepValue,
+ @Nullable CharSequence formatString) {
+ super(templateId);
+ Preconditions.checkNotNull(formatString);
+ mMinValue = minValue;
+ mMaxValue = maxValue;
+ mCurrentValue = currentValue;
+ mStepValue = stepValue;
+ if (formatString != null) {
+ mFormatString = formatString;
+ } else {
+ mFormatString = "%.1f";
+ }
+ validate();
+ }
+
+ /**
+ * Construct a new {@link RangeTemplate} from a {@link Parcel}.
+ *
+ * @throws InvalidParameterException if the parameters passed do not make a valid range
+ * @see RangeTemplate#RangeTemplate(String, float, float, float, float, CharSequence)
+ * @hide
+ */
+ RangeTemplate(Parcel in) {
+ super(in);
+ mMinValue = in.readFloat();
+ mMaxValue = in.readFloat();
+ mCurrentValue = in.readFloat();
+ mStepValue = in.readFloat();
+ mFormatString = in.readCharSequence();
+ validate();
+ }
+
+ /**
+ * The minimum value for this range.
+ */
+ public float getMinValue() {
+ return mMinValue;
+ }
+
+ /**
+ * The maximum value for this range.
+ */
+ public float getMaxValue() {
+ return mMaxValue;
+ }
+
+ /**
+ * The current value for this range.
+ */
+ public float getCurrentValue() {
+ return mCurrentValue;
+ }
+
+ /**
+ * The value of the smallest increment or decrement that can be performed on this range.
+ */
+ public float getStepValue() {
+ return mStepValue;
+ }
+
+ /**
+ * Formatter for generating a user visible {@link String} representing the value
+ * returned by {@link RangeTemplate#getCurrentValue}.
+ * @return a formatting string as specified in {@link String#format}
+ */
+ @NonNull
+ public CharSequence getFormatString() {
+ return mFormatString;
+ }
+
+ /**
+ * @return {@link ControlTemplate#TYPE_RANGE}
+ */
+ @Override
+ public int getTemplateType() {
+ return TYPE_RANGE;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ super.writeToParcel(dest, flags);
+ dest.writeFloat(mMinValue);
+ dest.writeFloat(mMaxValue);
+ dest.writeFloat(mCurrentValue);
+ dest.writeFloat(mStepValue);
+ dest.writeCharSequence(mFormatString);
+ }
+
+ /**
+ * Validate constructor parameters
+ *
+ * @throws InvalidParameterException if the parameters passed do not make a valid range
+ */
+ private void validate() {
+ if (Float.compare(mMinValue, mMaxValue) > 0) {
+ throw new InvalidParameterException(
+ String.format("minValue=%f > maxValue=%f", mMinValue, mMaxValue));
+ }
+ if (Float.compare(mMinValue, mCurrentValue) > 0) {
+ throw new InvalidParameterException(
+ String.format("minValue=%f > currentValue=%f", mMinValue, mCurrentValue));
+ }
+ if (Float.compare(mCurrentValue, mMaxValue) > 0) {
+ throw new InvalidParameterException(
+ String.format("currentValue=%f > maxValue=%f", mCurrentValue, mMaxValue));
+ }
+ if (mStepValue <= 0) {
+ throw new InvalidParameterException(String.format("stepValue=%f <= 0", mStepValue));
+ }
+ }
+
+ public static final Creator<RangeTemplate> CREATOR = new Creator<RangeTemplate>() {
+ @Override
+ public RangeTemplate createFromParcel(Parcel source) {
+ return new RangeTemplate(source);
+ }
+
+ @Override
+ public RangeTemplate[] newArray(int size) {
+ return new RangeTemplate[size];
+ }
+ };
+}
diff --git a/core/java/android/service/controls/ThumbnailTemplate.aidl b/core/java/android/service/controls/ThumbnailTemplate.aidl
new file mode 100644
index 000000000000..fe8c7fed7c89
--- /dev/null
+++ b/core/java/android/service/controls/ThumbnailTemplate.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (c) 2019, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.service.controls;
+
+parcelable ThumbnailTemplate; \ No newline at end of file
diff --git a/core/java/android/service/controls/ThumbnailTemplate.java b/core/java/android/service/controls/ThumbnailTemplate.java
new file mode 100644
index 000000000000..796d2de89576
--- /dev/null
+++ b/core/java/android/service/controls/ThumbnailTemplate.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.service.controls;
+
+import android.annotation.NonNull;
+import android.graphics.drawable.Icon;
+import android.os.Parcel;
+
+import com.android.internal.util.Preconditions;
+
+/**
+ * A template for a {@link Control} that displays an image.
+ * @hide
+ */
+public final class ThumbnailTemplate extends ControlTemplate {
+
+ private final @NonNull Icon mThumbnail;
+ private final @NonNull CharSequence mContentDescription;
+
+ /**
+ * @param templateId the identifier for this template object
+ * @param thumbnail an image to display on the {@link Control}
+ * @param contentDescription a description of the image for accessibility.
+ */
+ public ThumbnailTemplate(@NonNull String templateId, @NonNull Icon thumbnail,
+ @NonNull CharSequence contentDescription) {
+ super(templateId);
+ Preconditions.checkNotNull(thumbnail);
+ Preconditions.checkNotNull(contentDescription);
+ mThumbnail = thumbnail;
+ mContentDescription = contentDescription;
+ }
+
+ ThumbnailTemplate(Parcel in) {
+ super(in);
+ mThumbnail = Icon.CREATOR.createFromParcel(in);
+ mContentDescription = in.readCharSequence();
+ }
+
+ /**
+ * The {@link Icon} (image) displayed by this template.
+ */
+ @NonNull
+ public Icon getThumbnail() {
+ return mThumbnail;
+ }
+
+ /**
+ * The description of the image returned by {@link ThumbnailTemplate#getThumbnail()}
+ */
+ @NonNull
+ public CharSequence getContentDescription() {
+ return mContentDescription;
+ }
+
+ /**
+ * @return {@link ControlTemplate#TYPE_THUMBNAIL}
+ */
+ @Override
+ public int getTemplateType() {
+ return TYPE_THUMBNAIL;
+ }
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ super.writeToParcel(dest, flags);
+ mThumbnail.writeToParcel(dest, flags);
+ dest.writeCharSequence(mContentDescription);
+ }
+
+ public static final Creator<ThumbnailTemplate> CREATOR = new Creator<ThumbnailTemplate>() {
+ @Override
+ public ThumbnailTemplate createFromParcel(Parcel source) {
+ return new ThumbnailTemplate(source);
+ }
+
+ @Override
+ public ThumbnailTemplate[] newArray(int size) {
+ return new ThumbnailTemplate[size];
+ }
+ };
+}
diff --git a/core/java/android/service/controls/ToggleTemplate.aidl b/core/java/android/service/controls/ToggleTemplate.aidl
new file mode 100644
index 000000000000..1c823d9aee6d
--- /dev/null
+++ b/core/java/android/service/controls/ToggleTemplate.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (c) 2019, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.service.controls;
+
+parcelable ToggleTemplate; \ No newline at end of file
diff --git a/core/java/android/service/controls/ToggleTemplate.java b/core/java/android/service/controls/ToggleTemplate.java
new file mode 100644
index 000000000000..3766bd168477
--- /dev/null
+++ b/core/java/android/service/controls/ToggleTemplate.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.service.controls;
+
+import android.annotation.NonNull;
+import android.os.Parcel;
+
+import com.android.internal.util.Preconditions;
+
+/**
+ * A template for a {@link Control} with a single button that can be toggled between two states.
+ *
+ * The states for the toggle correspond to the states in {@link ControlButton#isActive()}.
+ * An action on this template will originate a {@link BooleanAction} to change that state.
+ *
+ * @see BooleanAction
+ * @hide
+ */
+public final class ToggleTemplate extends ControlTemplate {
+
+ private final @NonNull ControlButton mButton;
+
+ /**
+ * @param templateId the identifier for this template object
+ * @param button a {@ControlButton} that can show the current state and toggle it
+ */
+ public ToggleTemplate(@NonNull String templateId, @NonNull ControlButton button) {
+ super(templateId);
+ Preconditions.checkNotNull(button);
+ mButton = button;
+ }
+
+ ToggleTemplate(Parcel in) {
+ super(in);
+ mButton = ControlButton.CREATOR.createFromParcel(in);
+ }
+
+ /**
+ * The button provided to this object in {@link ToggleTemplate#ToggleTemplate}
+ */
+ @NonNull
+ public ControlButton getButton() {
+ return mButton;
+ }
+
+ /**
+ * @return {@link ControlTemplate#TYPE_TOGGLE}
+ */
+ @Override
+ public int getTemplateType() {
+ return TYPE_TOGGLE;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ super.writeToParcel(dest, flags);
+ mButton.writeToParcel(dest, flags);
+ }
+
+ public static final Creator<ToggleTemplate> CREATOR = new Creator<ToggleTemplate>() {
+ @Override
+ public ToggleTemplate createFromParcel(Parcel source) {
+ return new ToggleTemplate(source);
+ }
+
+ @Override
+ public ToggleTemplate[] newArray(int size) {
+ return new ToggleTemplate[size];
+ }
+ };
+
+}
diff --git a/core/java/android/service/incremental/IIncrementalDataLoaderService.aidl b/core/java/android/service/incremental/IIncrementalDataLoaderService.aidl
deleted file mode 100644
index 723fc594bd72..000000000000
--- a/core/java/android/service/incremental/IIncrementalDataLoaderService.aidl
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.service.incremental;
-
-import android.os.incremental.IncrementalDataLoaderParamsParcel;
-import android.os.incremental.IncrementalFileSystemControlParcel;
-import android.service.incremental.IIncrementalDataLoaderStatusListener;
-
-/** @hide */
-oneway interface IIncrementalDataLoaderService {
- void createDataLoader(in int storageId,
- in IncrementalFileSystemControlParcel control,
- in IncrementalDataLoaderParamsParcel params,
- in IIncrementalDataLoaderStatusListener listener,
- in boolean start);
- void startDataLoader(in int storageId);
- void stopDataLoader(in int storageId);
- void destroyDataLoader(in int storageId);
- void onFileCreated(in int storageId, in long inode, in byte[] metadata);
-}
diff --git a/core/java/android/service/notification/IConditionProvider.aidl b/core/java/android/service/notification/IConditionProvider.aidl
index 3f3c6b80286d..dd3904fc28ce 100644
--- a/core/java/android/service/notification/IConditionProvider.aidl
+++ b/core/java/android/service/notification/IConditionProvider.aidl
@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2014, The Android Open Source Project
+ * Copyright (c) 2019, The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/telephony/java/android/telephony/DataConnectionRealTimeInfo.aidl b/core/java/android/telephony/DataConnectionRealTimeInfo.aidl
index 70fbb1180e15..70fbb1180e15 100644
--- a/telephony/java/android/telephony/DataConnectionRealTimeInfo.aidl
+++ b/core/java/android/telephony/DataConnectionRealTimeInfo.aidl
diff --git a/telephony/java/android/telephony/DataConnectionRealTimeInfo.java b/core/java/android/telephony/DataConnectionRealTimeInfo.java
index 8106f5f30d26..8106f5f30d26 100644
--- a/telephony/java/android/telephony/DataConnectionRealTimeInfo.java
+++ b/core/java/android/telephony/DataConnectionRealTimeInfo.java
diff --git a/core/java/android/telephony/TelephonyRegistryManager.java b/core/java/android/telephony/TelephonyRegistryManager.java
index f66a679ad87d..9d7b57ba250d 100644
--- a/core/java/android/telephony/TelephonyRegistryManager.java
+++ b/core/java/android/telephony/TelephonyRegistryManager.java
@@ -455,6 +455,19 @@ public class TelephonyRegistryManager {
}
/**
+ * Sim activation type: voice
+ * @see #notifyVoiceActivationStateChanged
+ * @hide
+ */
+ public static final int SIM_ACTIVATION_TYPE_VOICE = 0;
+ /**
+ * Sim activation type: data
+ * @see #notifyDataActivationStateChanged
+ * @hide
+ */
+ public static final int SIM_ACTIVATION_TYPE_DATA = 1;
+
+ /**
* Notify data activation state changed on certain subscription.
* @see TelephonyManager#getDataActivationState()
*
@@ -469,7 +482,7 @@ public class TelephonyRegistryManager {
@SimActivationState int activationState) {
try {
sRegistry.notifySimActivationStateChangedForPhoneId(slotIndex, subId,
- TelephonyManager.SIM_ACTIVATION_TYPE_DATA, activationState);
+ SIM_ACTIVATION_TYPE_DATA, activationState);
} catch (RemoteException ex) {
// system process is dead
}
@@ -490,7 +503,7 @@ public class TelephonyRegistryManager {
@SimActivationState int activationState) {
try {
sRegistry.notifySimActivationStateChangedForPhoneId(slotIndex, subId,
- TelephonyManager.SIM_ACTIVATION_TYPE_VOICE, activationState);
+ SIM_ACTIVATION_TYPE_VOICE, activationState);
} catch (RemoteException ex) {
// system process is dead
}
diff --git a/core/java/android/util/StatsEvent.java b/core/java/android/util/StatsEvent.java
index d7ec30c531eb..0a4069d15706 100644
--- a/core/java/android/util/StatsEvent.java
+++ b/core/java/android/util/StatsEvent.java
@@ -177,7 +177,7 @@ public final class StatsEvent implements Parcelable {
* @hide
**/
@VisibleForTesting
- public static final int ERROR_ATTRIBUTION_UIDS_TAGS_SIZES_NOT_EQUAL = 0x400;
+ public static final int ERROR_ATTRIBUTION_UIDS_TAGS_SIZES_NOT_EQUAL = 0x1000;
// Size limits.
@@ -628,9 +628,9 @@ public final class StatsEvent implements Parcelable {
if (0 == mErrorMask) {
mBuffer.putByte(POS_NUM_ELEMENTS, (byte) mNumElements);
} else {
- mBuffer.putByte(0, TYPE_ERRORS);
- mBuffer.putByte(POS_NUM_ELEMENTS, (byte) 3);
+ mPos += mBuffer.putByte(mPos, TYPE_ERRORS);
mPos += mBuffer.putInt(mPos, mErrorMask);
+ mBuffer.putByte(POS_NUM_ELEMENTS, (byte) 3);
size = mPos;
}
diff --git a/core/java/android/view/InsetsController.java b/core/java/android/view/InsetsController.java
index 3c93bb7a59b2..bc70d634b4ec 100644
--- a/core/java/android/view/InsetsController.java
+++ b/core/java/android/view/InsetsController.java
@@ -467,6 +467,10 @@ public class InsetsController implements WindowInsetsController {
}
}
+ boolean isAnimating() {
+ return mAnimationDirection != DIRECTION_NONE;
+ }
+
private InsetsSourceConsumer createConsumerOfType(int type) {
if (type == ITYPE_IME) {
return new ImeInsetsSourceConsumer(mState, Transaction::new, this);
@@ -514,6 +518,7 @@ public class InsetsController implements WindowInsetsController {
} else {
hideDirectly(types);
}
+ mAnimationDirection = show ? DIRECTION_SHOW : DIRECTION_HIDE;
mAnimator = ObjectAnimator.ofObject(
controller,
new InsetsProperty(),
diff --git a/core/java/android/view/InsetsSourceConsumer.java b/core/java/android/view/InsetsSourceConsumer.java
index b1caf1872de2..c6d9898a425c 100644
--- a/core/java/android/view/InsetsSourceConsumer.java
+++ b/core/java/android/view/InsetsSourceConsumer.java
@@ -167,7 +167,8 @@ public class InsetsSourceConsumer {
}
private void applyHiddenToControl() {
- if (mSourceControl == null || mSourceControl.getLeash() == null) {
+ if (mSourceControl == null || mSourceControl.getLeash() == null
+ || mController.isAnimating()) {
return;
}
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index fc80e00f7381..9e5e20ab046b 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -442,6 +442,12 @@ public final class SurfaceControl implements Parcelable {
public static final int METADATA_TASK_ID = 3;
/**
+ * Accessibility ID to allow association between surfaces and accessibility tree.
+ * @hide
+ */
+ public static final int METADATA_ACCESSIBILITY_ID = 4;
+
+ /**
* A wrapper around GraphicBuffer that contains extra information about how to
* interpret the screenshot GraphicBuffer.
* @hide
@@ -2651,6 +2657,7 @@ public final class SurfaceControl implements Parcelable {
* @hide
*/
public Transaction setMetadata(SurfaceControl sc, int key, Parcel data) {
+ sc.checkNotReleased();
nativeSetMetadata(mNativeObject, sc.mNativeObject, key, data);
return this;
}
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index c62e69cc5ed1..7a817b6d4dc4 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -1181,7 +1181,8 @@ public interface WindowManager extends ViewManager {
* a soft input method, so it will be Z-ordered and positioned
* independently of any active input method (typically this means it
* gets Z-ordered on top of the input method, so it can use the full
- * screen for its content and cover the input method if needed.) */
+ * screen for its content and cover the input method if needed. You
+ * can use {@link #FLAG_ALT_FOCUSABLE_IM} to modify this behavior. */
public static final int FLAG_NOT_FOCUSABLE = 0x00000008;
/** Window flag: this window can never receive touch events. */
@@ -1287,11 +1288,14 @@ public interface WindowManager extends ViewManager {
* set for you by Window as described in {@link Window#setFlags}.*/
public static final int FLAG_LAYOUT_INSET_DECOR = 0x00010000;
- /** Window flag: When set, input method can't interact with the focusable window
- * and can be placed to use more space and cover the input method.
- * Note: When combined with {@link #FLAG_NOT_FOCUSABLE}, this flag has no
- * effect since input method cannot interact with windows having {@link #FLAG_NOT_FOCUSABLE}
- * flag set.
+ /** Window flag: invert the state of {@link #FLAG_NOT_FOCUSABLE} with
+ * respect to how this window interacts with the current method. That
+ * is, if FLAG_NOT_FOCUSABLE is set and this flag is set, then the
+ * window will behave as if it needs to interact with the input method
+ * and thus be placed behind/away from it; if FLAG_NOT_FOCUSABLE is
+ * not set and this flag is set, then the window will behave as if it
+ * doesn't need to interact with the input method and can be placed
+ * to use more space and cover the input method.
*/
public static final int FLAG_ALT_FOCUSABLE_IM = 0x00020000;
@@ -1989,12 +1993,16 @@ public interface WindowManager extends ViewManager {
*
* @param flags The current window manager flags.
*
- * @return Returns {@code true} if such a window should be behind/interact
- * with an input method, (@code false} if not.
+ * @return Returns true if such a window should be behind/interact
+ * with an input method, false if not.
*/
public static boolean mayUseInputMethod(int flags) {
- return (flags & FLAG_NOT_FOCUSABLE) != FLAG_NOT_FOCUSABLE
- && (flags & FLAG_ALT_FOCUSABLE_IM) != FLAG_ALT_FOCUSABLE_IM;
+ switch (flags&(FLAG_NOT_FOCUSABLE|FLAG_ALT_FOCUSABLE_IM)) {
+ case 0:
+ case FLAG_NOT_FOCUSABLE|FLAG_ALT_FOCUSABLE_IM:
+ return true;
+ }
+ return false;
}
/**
diff --git a/core/java/com/android/internal/util/AsyncChannel.java b/core/java/com/android/internal/util/AsyncChannel.java
index b0888f2c8df9..121ae1a17456 100644
--- a/core/java/com/android/internal/util/AsyncChannel.java
+++ b/core/java/com/android/internal/util/AsyncChannel.java
@@ -29,7 +29,7 @@ import android.os.Looper;
import android.os.Message;
import android.os.Messenger;
import android.os.RemoteException;
-import android.util.Slog;
+import android.util.Log;
import java.util.Stack;
@@ -841,7 +841,7 @@ public class AsyncChannel {
msg.replyTo = sm.mMessenger;
synchronized (sm.mHandler.mLockObject) {
if (sm.mHandler.mResultMsg != null) {
- Slog.wtf(TAG, "mResultMsg should be null here");
+ Log.wtf(TAG, "mResultMsg should be null here");
sm.mHandler.mResultMsg = null;
}
dstMessenger.send(msg);
@@ -851,9 +851,9 @@ public class AsyncChannel {
}
}
} catch (InterruptedException e) {
- Slog.e(TAG, "error in sendMessageSynchronously", e);
+ Log.e(TAG, "error in sendMessageSynchronously", e);
} catch (RemoteException e) {
- Slog.e(TAG, "error in sendMessageSynchronously", e);
+ Log.e(TAG, "error in sendMessageSynchronously", e);
}
sm.recycle();
return resultMsg;
@@ -939,7 +939,7 @@ public class AsyncChannel {
* @param s
*/
private static void log(String s) {
- Slog.d(TAG, s);
+ Log.d(TAG, s);
}
private final class DeathMonitor implements IBinder.DeathRecipient {
diff --git a/core/java/com/android/internal/util/AsyncService.java b/core/java/com/android/internal/util/AsyncService.java
index e39a2bfc6abd..58e4a605f88c 100644
--- a/core/java/com/android/internal/util/AsyncService.java
+++ b/core/java/com/android/internal/util/AsyncService.java
@@ -22,7 +22,7 @@ import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.os.Messenger;
-import android.util.Slog;
+import android.util.Log;
/**
* A service that receives Intents and IBinder transactions
@@ -92,7 +92,7 @@ abstract public class AsyncService extends Service {
*/
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
- if (DBG) Slog.d(TAG, "onStartCommand");
+ if (DBG) Log.d(TAG, "onStartCommand");
Message msg = mHandler.obtainMessage();
msg.what = CMD_ASYNC_SERVICE_ON_START_INTENT;
@@ -111,7 +111,7 @@ abstract public class AsyncService extends Service {
*/
@Override
public void onDestroy() {
- if (DBG) Slog.d(TAG, "onDestroy");
+ if (DBG) Log.d(TAG, "onDestroy");
Message msg = mHandler.obtainMessage();
msg.what = CMD_ASYNC_SERVICE_DESTROY;
diff --git a/core/java/com/android/internal/view/BaseIWindow.java b/core/java/com/android/internal/view/BaseIWindow.java
index 57bfcac5bf54..2ac2975d0a44 100644
--- a/core/java/com/android/internal/view/BaseIWindow.java
+++ b/core/java/com/android/internal/view/BaseIWindow.java
@@ -36,6 +36,8 @@ import com.android.internal.os.IResultReceiver;
import dalvik.annotation.compat.UnsupportedAppUsage;
+import java.io.IOException;
+
public class BaseIWindow extends IWindow.Stub {
@UnsupportedAppUsage(maxTargetSdk = android.os.Build.VERSION_CODES.P)
@@ -101,6 +103,13 @@ public class BaseIWindow extends IWindow.Stub {
@Override
public void executeCommand(String command, String parameters, ParcelFileDescriptor out) {
+ if (out != null) {
+ try {
+ out.closeWithError("Unsupported command " + command);
+ } catch (IOException e) {
+ // Ignore
+ }
+ }
}
@Override
diff --git a/core/proto/android/stats/mediaprovider/mediaprovider_enums.proto b/core/proto/android/stats/mediaprovider/mediaprovider_enums.proto
new file mode 100644
index 000000000000..138782bf5d19
--- /dev/null
+++ b/core/proto/android/stats/mediaprovider/mediaprovider_enums.proto
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+syntax = "proto2";
+package android.stats.mediaprovider;
+option java_multiple_files = true;
+
+enum VolumeType {
+ // Volume is unknown
+ UNKNOWN = 0;
+ // Volume is MediaStore.VOLUME_INTERNAL
+ INTERNAL = 1;
+ // Volume is MediaStore.VOLUME_EXTERNAL_PRIMARY
+ EXTERNAL_PRIMARY = 2;
+ // Volume is non-primary external storage
+ EXTERNAL_OTHER = 3;
+}
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index fc9fa8595c5b..10a75842d7c6 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -3695,6 +3695,8 @@
instead of 'Emergency calls only' when SIM is unready. -->
<string-array translatable="false" name="config_display_no_service_when_sim_unready">
<item>"DE"</item>
+ <item>"GB"</item>
+ <item>"JP"</item>
</string-array>
<!-- Class names of device specific services inheriting com.android.server.SystemService. The
@@ -4179,4 +4181,10 @@
<string-array name="config_integrityRuleProviderPackages" translatable="false">
<!-- Add packages here -->
</string-array>
+
+ <!-- When true, enables the whitelisted app to handle bug reports from power menu short press. -->
+ <bool name="config_bugReportHandlerEnabled">false</bool>
+
+ <!-- The package name for the default bug report handler app from power menu short press. This app must be whitelisted. -->
+ <string name="config_defaultBugReportHandlerApp" translatable="false"></string>
</resources>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index dcf73792e041..0f5da39a2c1e 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -1014,23 +1014,29 @@
<string name="permdesc_readContacts" product="tablet">Allows the app to read
data about your contacts stored on your tablet, including the frequency
with which you\'ve called, emailed, or communicated in other ways with
- specific individuals. This permission allows apps to save your contact
+ specific individuals. Apps will also have access to the accounts on your
+ tablet that have created contacts. This may include accounts created by
+ apps you have installed. This permission allows apps to save your contact
data, and malicious apps may share contact data without your
knowledge.</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_readContacts" product="tv">Allows the app to read
data about your contacts stored on your Android TV device, including the frequency
with which you\'ve called, emailed, or communicated in other ways with
- specific individuals. This permission allows apps to save your contact
- data, and malicious apps may share contact data without your
+ specific individuals. Apps will also have access to the accounts on your
+ Android TV device that have created contacts. This may include accounts
+ created by apps you have installed. This permission allows apps to save
+ your contact data, and malicious apps may share contact data without your
knowledge.</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_readContacts" product="default">Allows the app to
read data about your contacts stored on your phone, including the
frequency with which you\'ve called, emailed, or communicated in other ways
- with specific individuals. This permission allows apps to save your
- contact data, and malicious apps may share contact data without your
- knowledge.</string>
+ with specific individuals. Apps will also have access to the accounts
+ on your phone that have created contacts. This may include accounts
+ created by apps you have installed. This permission allows apps to
+ save your contact data, and malicious apps may share contact data
+ without your knowledge.</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_writeContacts">modify your contacts</string>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index c6c9094229b9..083f33cc8035 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -3751,6 +3751,10 @@
<java-symbol type="bool" name="config_showBuiltinWirelessChargingAnim" />
+ <!-- For bug report handler -->
+ <java-symbol type="bool" name="config_bugReportHandlerEnabled" />
+ <java-symbol type="string" name="config_defaultBugReportHandlerApp" />
+
<java-symbol type="string" name="usb_device_resolve_prompt_warn" />
<!-- For Accessibility system actions -->
diff --git a/core/tests/coretests/src/android/service/controls/ControlActionTest.java b/core/tests/coretests/src/android/service/controls/ControlActionTest.java
new file mode 100644
index 000000000000..ef4912fe1f74
--- /dev/null
+++ b/core/tests/coretests/src/android/service/controls/ControlActionTest.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.service.controls;
+
+import static junit.framework.Assert.assertTrue;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+import android.os.Parcel;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class ControlActionTest {
+
+ private static final String TEST_ID = "TEST_ID";
+
+ @Test
+ public void testUnparcelingCorrectClass_boolean() {
+ ControlAction toParcel = new BooleanAction(TEST_ID, true);
+
+ ControlAction fromParcel = parcelAndUnparcel(toParcel);
+
+ assertEquals(ControlAction.TYPE_BOOLEAN, fromParcel.getActionType());
+ assertTrue(fromParcel instanceof BooleanAction);
+ }
+
+ @Test
+ public void testUnparcelingCorrectClass_float() {
+ ControlAction toParcel = new FloatAction(TEST_ID, 1);
+
+ ControlAction fromParcel = parcelAndUnparcel(toParcel);
+
+ assertEquals(ControlAction.TYPE_FLOAT, fromParcel.getActionType());
+ assertTrue(fromParcel instanceof FloatAction);
+ }
+
+ private ControlAction parcelAndUnparcel(ControlAction toParcel) {
+ Parcel parcel = Parcel.obtain();
+
+ assertNotNull(parcel);
+
+ parcel.setDataPosition(0);
+ toParcel.writeToParcel(parcel, 0);
+ parcel.setDataPosition(0);
+
+ return ControlAction.CREATOR.createFromParcel(parcel);
+ }
+}
diff --git a/core/tests/coretests/src/android/service/controls/ControlTemplateTest.java b/core/tests/coretests/src/android/service/controls/ControlTemplateTest.java
new file mode 100644
index 000000000000..4fa4e1d7b733
--- /dev/null
+++ b/core/tests/coretests/src/android/service/controls/ControlTemplateTest.java
@@ -0,0 +1,139 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.service.controls;
+
+import static junit.framework.Assert.assertTrue;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+import android.annotation.DrawableRes;
+import android.graphics.drawable.Icon;
+import android.os.Parcel;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.frameworks.coretests.R;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.MockitoAnnotations;
+
+import java.security.InvalidParameterException;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class ControlTemplateTest {
+
+ private static final String PACKAGE_NAME = "com.android.frameworks.coretests";
+ private static final @DrawableRes int TEST_ICON_ID = R.drawable.box;
+ private static final String TEST_ID = "TEST_ID";
+ private static final CharSequence TEST_CONTENT_DESCRIPTION = "TEST_CONTENT_DESCRIPTION";
+ private Icon mIcon;
+ private ControlButton mControlButton;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ mIcon = Icon.createWithResource(PACKAGE_NAME, TEST_ICON_ID);
+ mControlButton = new ControlButton(true, mIcon, TEST_CONTENT_DESCRIPTION);
+ }
+
+ @Test
+ public void testUnparcelingCorrectClass_none() {
+ ControlTemplate toParcel = ControlTemplate.NO_TEMPLATE;
+
+ ControlTemplate fromParcel = parcelAndUnparcel(toParcel);
+
+ assertEquals(ControlTemplate.NO_TEMPLATE, fromParcel);
+ }
+
+ @Test
+ public void testUnparcelingCorrectClass_toggle() {
+ ControlTemplate toParcel = new ToggleTemplate(TEST_ID, mControlButton);
+
+ ControlTemplate fromParcel = parcelAndUnparcel(toParcel);
+
+ assertEquals(ControlTemplate.TYPE_TOGGLE, fromParcel.getTemplateType());
+ assertTrue(fromParcel instanceof ToggleTemplate);
+ }
+
+ @Test
+ public void testUnparcelingCorrectClass_range() {
+ ControlTemplate toParcel = new RangeTemplate(TEST_ID, 0, 2, 1, 1, "%f");
+
+ ControlTemplate fromParcel = parcelAndUnparcel(toParcel);
+
+ assertEquals(ControlTemplate.TYPE_RANGE, fromParcel.getTemplateType());
+ assertTrue(fromParcel instanceof RangeTemplate);
+ }
+
+ @Test(expected = InvalidParameterException.class)
+ public void testRangeParameters_minMax() {
+ RangeTemplate range = new RangeTemplate(TEST_ID, 2, 0, 1, 1, "%f");
+ }
+
+ @Test(expected = InvalidParameterException.class)
+ public void testRangeParameters_minCurrent() {
+ RangeTemplate range = new RangeTemplate(TEST_ID, 0, 2, -1, 1, "%f");
+ }
+
+ @Test(expected = InvalidParameterException.class)
+ public void testRangeParameters_maxCurrent() {
+ RangeTemplate range = new RangeTemplate(TEST_ID, 0, 2, 3, 1, "%f");
+ }
+
+ @Test(expected = InvalidParameterException.class)
+ public void testRangeParameters_negativeStep() {
+ RangeTemplate range = new RangeTemplate(TEST_ID, 0, 2, 1, -1, "%f");
+ }
+
+ @Test
+ public void testUnparcelingCorrectClass_thumbnail() {
+ ControlTemplate toParcel = new ThumbnailTemplate(TEST_ID, mIcon, TEST_CONTENT_DESCRIPTION);
+
+ ControlTemplate fromParcel = parcelAndUnparcel(toParcel);
+
+ assertEquals(ControlTemplate.TYPE_THUMBNAIL, fromParcel.getTemplateType());
+ assertTrue(fromParcel instanceof ThumbnailTemplate);
+ }
+
+ @Test
+ public void testUnparcelingCorrectClass_discreteToggle() {
+ ControlTemplate toParcel =
+ new DiscreteToggleTemplate(TEST_ID, mControlButton, mControlButton);
+
+ ControlTemplate fromParcel = parcelAndUnparcel(toParcel);
+
+ assertEquals(ControlTemplate.TYPE_DISCRETE_TOGGLE, fromParcel.getTemplateType());
+ assertTrue(fromParcel instanceof DiscreteToggleTemplate);
+ }
+
+ private ControlTemplate parcelAndUnparcel(ControlTemplate toParcel) {
+ Parcel parcel = Parcel.obtain();
+
+ assertNotNull(parcel);
+
+ parcel.setDataPosition(0);
+ toParcel.writeToParcel(parcel, 0);
+ parcel.setDataPosition(0);
+
+ return ControlTemplate.CREATOR.createFromParcel(parcel);
+ }
+}
diff --git a/core/tests/coretests/src/android/util/StatsEventTest.java b/core/tests/coretests/src/android/util/StatsEventTest.java
index 93f11dbccf64..097badadcea9 100644
--- a/core/tests/coretests/src/android/util/StatsEventTest.java
+++ b/core/tests/coretests/src/android/util/StatsEventTest.java
@@ -53,8 +53,8 @@ public class StatsEventTest {
final ByteBuffer buffer =
ByteBuffer.wrap(statsEvent.getBytes()).order(ByteOrder.LITTLE_ENDIAN);
- assertWithMessage("Root element in buffer is not TYPE_ERRORS")
- .that(buffer.get()).isEqualTo(StatsEvent.TYPE_ERRORS);
+ assertWithMessage("Root element in buffer is not TYPE_OBJECT")
+ .that(buffer.get()).isEqualTo(StatsEvent.TYPE_OBJECT);
assertWithMessage("Incorrect number of elements in root object")
.that(buffer.get()).isEqualTo(3);
@@ -71,6 +71,9 @@ public class StatsEventTest {
assertWithMessage("Incorrect atom id")
.that(buffer.getInt()).isEqualTo(expectedAtomId);
+ assertWithMessage("Third element is not errors type")
+ .that(buffer.get()).isEqualTo(StatsEvent.TYPE_ERRORS);
+
final int errorMask = buffer.getInt();
assertWithMessage("ERROR_NO_ATOM_ID should be the only error in the error mask")
diff --git a/media/Android.bp b/media/Android.bp
index 022fa9b7bb9e..1912930f2081 100644
--- a/media/Android.bp
+++ b/media/Android.bp
@@ -45,8 +45,8 @@ java_library {
filegroup {
name: "updatable-media-srcs",
srcs: [
- ":mediasession2-srcs",
":mediaparser-srcs",
+ ":mediasession2-srcs",
],
}
@@ -73,7 +73,8 @@ filegroup {
name: "mediaparser-srcs",
srcs: [
"apex/java/android/media/MediaParser.java"
- ]
+ ],
+ path: "apex/java"
}
metalava_updatable_media_args = " --error UnhiddenSystemApi " +
diff --git a/media/apex/java/android/media/MediaParser.java b/media/apex/java/android/media/MediaParser.java
index c06e2837bcdc..8824269ea0c0 100644
--- a/media/apex/java/android/media/MediaParser.java
+++ b/media/apex/java/android/media/MediaParser.java
@@ -15,10 +15,47 @@
*/
package android.media;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.net.Uri;
+import android.text.TextUtils;
import android.util.Pair;
-
+import android.util.SparseArray;
+
+import com.google.android.exoplayer2.C;
+import com.google.android.exoplayer2.Format;
+import com.google.android.exoplayer2.extractor.DefaultExtractorInput;
+import com.google.android.exoplayer2.extractor.Extractor;
+import com.google.android.exoplayer2.extractor.ExtractorInput;
+import com.google.android.exoplayer2.extractor.ExtractorOutput;
+import com.google.android.exoplayer2.extractor.PositionHolder;
+import com.google.android.exoplayer2.extractor.SeekMap.SeekPoints;
+import com.google.android.exoplayer2.extractor.TrackOutput;
+import com.google.android.exoplayer2.extractor.amr.AmrExtractor;
+import com.google.android.exoplayer2.extractor.flv.FlvExtractor;
+import com.google.android.exoplayer2.extractor.mkv.MatroskaExtractor;
+import com.google.android.exoplayer2.extractor.mp3.Mp3Extractor;
+import com.google.android.exoplayer2.extractor.mp4.FragmentedMp4Extractor;
+import com.google.android.exoplayer2.extractor.mp4.Mp4Extractor;
+import com.google.android.exoplayer2.extractor.ogg.OggExtractor;
+import com.google.android.exoplayer2.extractor.ts.Ac3Extractor;
+import com.google.android.exoplayer2.extractor.ts.Ac4Extractor;
+import com.google.android.exoplayer2.extractor.ts.AdtsExtractor;
+import com.google.android.exoplayer2.extractor.ts.PsExtractor;
+import com.google.android.exoplayer2.extractor.ts.TsExtractor;
+import com.google.android.exoplayer2.extractor.wav.WavExtractor;
+import com.google.android.exoplayer2.upstream.DataSource;
+import com.google.android.exoplayer2.upstream.DataSpec;
+import com.google.android.exoplayer2.upstream.TransferListener;
+import com.google.android.exoplayer2.util.ParsableByteArray;
+
+import java.io.EOFException;
import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.util.Collections;
+import java.util.LinkedHashMap;
import java.util.List;
+import java.util.Map;
/**
* Parses media container formats and extracts contained media samples and metadata.
@@ -32,16 +69,93 @@ import java.util.List;
* <p>Users must implement the following to use this class.
*
* <ul>
- * <li>{@link Input}: Provides the media containers bytes to parse.
- * <li>{@link OutputCallback}: Provides a sink for all extracted data and metadata.
+ * <li>{@link InputReader}: Provides the media container's bytes to parse.
+ * <li>{@link OutputConsumer}: Provides a sink for all extracted data and metadata.
* </ul>
*
- * TODO: Add usage example here.
+ * <p>The following code snippet includes a usage example:
+ *
+ * <pre>
+ * MyOutputConsumer myOutputConsumer = new MyOutputConsumer();
+ * MyInputReader myInputReader = new MyInputReader("www.example.com");
+ * MediaParser mediaParser = MediaParser.create(myOutputConsumer);
+ *
+ * while (mediaParser.advance(myInputReader)) {}
+ *
+ * mediaParser.release();
+ * mediaParser = null;
+ * </pre>
+ *
+ * <p>The following code snippet provides a rudimentary {@link OutputConsumer} sample implementation
+ * which extracts and publishes all video samples:
+ *
+ * <pre>
+ *
+ * class VideoOutputConsumer implements MediaParser.OutputConsumer {
+ *
+ * private static final int MAXIMUM_SAMPLE_SIZE = ...;
+ * private byte[] sampleDataBuffer = new byte[MAXIMUM_SAMPLE_SIZE];
+ * private int videoTrackIndex = -1;
+ * private int bytesWrittenCount = 0;
+ *
+ * \@Override
+ * public void onSeekMap(int i, @NonNull MediaFormat mediaFormat) { \/* Do nothing. *\/ }
+ *
+ * \@Override
+ * public void onFormat(int i, @NonNull MediaFormat mediaFormat) {
+ * if (videoTrackIndex == -1 && mediaFormat
+ * .getString(MediaFormat.KEY_MIME, \/* defaultValue= *\/ "").startsWith("video/")) {
+ * videoTrackIndex = i;
+ * }
+ * }
+ *
+ * \@Override
+ * public void onSampleData(int trackIndex, @NonNull InputReader inputReader)
+ * throws IOException, InterruptedException {
+ * int numberOfBytesToRead = (int) inputReader.getLength();
+ * if (videoTrackIndex != trackIndex) {
+ * // Discard contents.
+ * inputReader.read(\/* bytes= *\/ null, \/* offset= *\/ 0, numberOfBytesToRead);
+ * }
+ * int bytesRead = inputReader.read(sampleDataBuffer, bytesWrittenCount, numberOfBytesToRead);
+ * bytesWrittenCount += bytesRead;
+ * }
+ *
+ * \@Override
+ * public void onSampleCompleted(
+ * int trackIndex,
+ * long timeUs,
+ * int flags,
+ * int size,
+ * int offset,
+ * \@Nullable CryptoInfo cryptoData) {
+ * if (videoTrackIndex != trackIndex) {
+ * return; // It's not the video track. Ignore.
+ * }
+ * byte[] sampleData = new byte[size];
+ * System.arraycopy(sampleDataBuffer, bytesWrittenCount - size - offset, sampleData, \/*
+ * destPos= *\/ 0, size);
+ * // Place trailing bytes at the start of the buffer.
+ * System.arraycopy(
+ * sampleDataBuffer,
+ * bytesWrittenCount - offset,
+ * sampleDataBuffer,
+ * \/* destPos= *\/ 0,
+ * \/* size= *\/ offset);
+ * publishSample(sampleData, timeUs, flags);
+ * }
+ * }
+ *
+ * </pre>
*/
-// @HiddenApi
public final class MediaParser {
- /** Maps seek positions to corresponding positions in the stream. */
+ /**
+ * Maps seek positions to {@link SeekPoint SeekPoints} in the stream.
+ *
+ * <p>A {@link SeekPoint} is a position in the stream from which a player may successfully start
+ * playing media samples.
+ */
public interface SeekMap {
/** Returned by {@link #getDurationUs()} when the duration is unknown. */
@@ -62,13 +176,14 @@ public final class MediaParser {
* <p>{@code getSeekPoints(timeUs).first} contains the latest seek point for samples with
* timestamp equal to or smaller than {@code timeUs}.
*
- * <p>{@code getSeekPoints(timeUs).second} contains the earlies seek point for samples with
+ * <p>{@code getSeekPoints(timeUs).second} contains the earliest seek point for samples with
* timestamp equal to or greater than {@code timeUs}. If a seek point exists for {@code
* timeUs}, the returned pair will contain the same {@link SeekPoint} twice.
*
* @param timeUs A seek time in microseconds.
* @return The corresponding {@link SeekPoint SeekPoints}.
*/
+ @NonNull
Pair<SeekPoint, SeekPoint> getSeekPoints(long timeUs);
}
@@ -76,30 +191,30 @@ public final class MediaParser {
public static final class SeekPoint {
/** A {@link SeekPoint} whose time and byte offset are both set to 0. */
- public static final SeekPoint START = new SeekPoint(0, 0);
+ public static final @NonNull SeekPoint START = new SeekPoint(0, 0);
/** The time of the seek point, in microseconds. */
- public final long mTimeUs;
+ public final long timeUs;
/** The byte offset of the seek point. */
- public final long mPosition;
+ public final long position;
/**
* @param timeUs The time of the seek point, in microseconds.
* @param position The byte offset of the seek point.
*/
- public SeekPoint(long timeUs, long position) {
- this.mTimeUs = timeUs;
- this.mPosition = position;
+ private SeekPoint(long timeUs, long position) {
+ this.timeUs = timeUs;
+ this.position = position;
}
@Override
- public String toString() {
- return "[timeUs=" + mTimeUs + ", position=" + mPosition + "]";
+ public @NonNull String toString() {
+ return "[timeUs=" + timeUs + ", position=" + position + "]";
}
@Override
- public boolean equals(Object obj) {
+ public boolean equals(@Nullable Object obj) {
if (this == obj) {
return true;
}
@@ -107,25 +222,26 @@ public final class MediaParser {
return false;
}
SeekPoint other = (SeekPoint) obj;
- return mTimeUs == other.mTimeUs && mPosition == other.mPosition;
+ return timeUs == other.timeUs && position == other.position;
}
@Override
public int hashCode() {
- int result = (int) mTimeUs;
- result = 31 * result + (int) mPosition;
+ int result = (int) timeUs;
+ result = 31 * result + (int) position;
return result;
}
}
/** Provides input data to {@link MediaParser}. */
- public interface Input {
+ public interface InputReader {
/**
* Reads up to {@code readLength} bytes of data and stores them into {@code buffer},
* starting at index {@code offset}.
*
- * <p>The call will block until at least one byte of data has been read.
+ * <p>This method blocks until at least one byte is read, the end of input is detected, or
+ * an exception is thrown. The read position advances to the first unread byte.
*
* @param buffer The buffer into which the read data should be stored.
* @param offset The start offset into {@code buffer} at which data should be written.
@@ -134,7 +250,7 @@ public final class MediaParser {
* of the input has been reached.
* @throws java.io.IOException If an error occurs reading from the source.
*/
- int read(byte[] buffer, int offset, int readLength)
+ int read(@NonNull byte[] buffer, int offset, int readLength)
throws IOException, InterruptedException;
/** Returns the current read position (byte offset) in the stream. */
@@ -144,22 +260,39 @@ public final class MediaParser {
long getLength();
}
- /** Receives extracted media sample data and metadata from {@link MediaParser}. */
- public interface OutputCallback {
+ /** {@link InputReader} that allows setting the read position. */
+ public interface SeekableInputReader extends InputReader {
/**
- * Called when the number of tracks is defined.
+ * Sets the read position at the given {@code position}.
*
- * @param numberOfTracks The number of tracks in the stream.
+ * <p>{@link #advance} will immediately return after calling this method.
+ *
+ * @param position The position to seek to, in bytes.
*/
- void onTracksFound(int numberOfTracks);
+ void seekToPosition(long position);
+ }
+
+ /** Receives extracted media sample data and metadata from {@link MediaParser}. */
+ public interface OutputConsumer {
/**
* Called when a {@link SeekMap} has been extracted from the stream.
*
+ * <p>This method is called at least once before any samples are {@link #onSampleCompleted
+ * complete}. May be called multiple times after that in order to add {@link SeekPoint
+ * SeekPoints}.
+ *
* @param seekMap The extracted {@link SeekMap}.
*/
- void onSeekMap(SeekMap seekMap);
+ void onSeekMap(@NonNull SeekMap seekMap);
+
+ /**
+ * Called when the number of tracks is found.
+ *
+ * @param numberOfTracks The number of tracks in the stream.
+ */
+ void onTracksFound(int numberOfTracks);
/**
* Called when the {@link MediaFormat} of the track is extracted from the stream.
@@ -167,7 +300,7 @@ public final class MediaParser {
* @param trackIndex The index of the track for which the {@link MediaFormat} was found.
* @param format The extracted {@link MediaFormat}.
*/
- void onFormat(int trackIndex, MediaFormat format);
+ void onFormat(int trackIndex, @NonNull MediaFormat format);
/**
* Called to write sample data to the output.
@@ -176,16 +309,15 @@ public final class MediaParser {
* thrown {@link IOException} caused by reading from {@code input}.
*
* @param trackIndex The index of the track to which the sample data corresponds.
- * @param input The {@link Input} from which to read the data.
- * @return
+ * @param inputReader The {@link InputReader} from which to read the data.
*/
- int onSampleData(int trackIndex, Input input) throws IOException, InterruptedException;
+ void onSampleData(int trackIndex, @NonNull InputReader inputReader)
+ throws IOException, InterruptedException;
/**
- * Defines the boundaries and metadata of an extracted sample.
+ * Called once all the data of a sample has been passed to {@link #onSampleData}.
*
- * <p>The corresponding sample data will have already been passed to the output via calls to
- * {@link #onSampleData}.
+ * <p>Also includes sample metadata, like presentation timestamp and flags.
*
* @param trackIndex The index of the track to which the sample corresponds.
* @param timeUs The media timestamp associated with the sample, in microseconds.
@@ -203,57 +335,22 @@ public final class MediaParser {
int flags,
int size,
int offset,
- MediaCodec.CryptoInfo cryptoData);
- }
-
- /**
- * Controls the behavior of extractors' implementations.
- *
- * <p>DESIGN NOTE: For setting flags like workarounds and special behaviors for adaptive
- * streaming.
- */
- public static final class Parameters {
-
- // TODO: Implement.
-
- }
-
- /** Holds the result of an {@link #advance} invocation. */
- public static final class ResultHolder {
-
- /** Creates a new instance with {@link #result} holding {@link #ADVANCE_RESULT_CONTINUE}. */
- public ResultHolder() {
- result = ADVANCE_RESULT_CONTINUE;
- }
-
- /**
- * May hold {@link #ADVANCE_RESULT_END_OF_INPUT}, {@link #ADVANCE_RESULT_CONTINUE}, {@link
- * #ADVANCE_RESULT_SEEK}.
- */
- public int result;
-
- /**
- * If {@link #result} holds {@link #ADVANCE_RESULT_SEEK}, holds the stream position required
- * from the passed {@link Input} to the next {@link #advance} call. If {@link #result} does
- * not hold {@link #ADVANCE_RESULT_SEEK}, the value of this variable is undefined and should
- * be ignored.
- */
- public long seekPosition;
+ @Nullable MediaCodec.CryptoInfo cryptoData);
}
/**
* Thrown if all extractors implementations provided to {@link #create} failed to sniff the
* input content.
*/
- // @HiddenApi
public static final class UnrecognizedInputFormatException extends IOException {
/**
* Creates a new instance which signals that the extractors with the given names failed to
* parse the input.
*/
- public static UnrecognizedInputFormatException createForExtractors(
- String... extractorNames) {
+ @NonNull
+ private static UnrecognizedInputFormatException createForExtractors(
+ @NonNull String... extractorNames) {
StringBuilder builder = new StringBuilder();
builder.append("None of the available extractors ( ");
builder.append(extractorNames[0]);
@@ -270,21 +367,9 @@ public final class MediaParser {
}
}
- // Public constants.
+ // Private constants.
- /**
- * Returned by {@link #advance} if the {@link Input} passed to the next {@link #advance} is
- * required to provide data continuing from the position in the stream reached by the returning
- * call.
- */
- public static final int ADVANCE_RESULT_CONTINUE = -1;
- /** Returned by {@link #advance} if the end of the {@link Input} was reached. */
- public static final int ADVANCE_RESULT_END_OF_INPUT = -2;
- /**
- * Returned by {@link #advance} when its next call expects a specific stream position, which
- * will be held by {@link ResultHolder#seekPosition}.
- */
- public static final int ADVANCE_RESULT_SEEK = -3;
+ private static final Map<String, ExtractorFactory> EXTRACTOR_FACTORIES_BY_NAME;
// Instance creation methods.
@@ -293,13 +378,15 @@ public final class MediaParser {
* instance will attempt extraction without sniffing the content.
*
* @param name The name of the extractor that will be associated with the created instance.
- * @param outputCallback The {@link OutputCallback} to which track data and samples are pushed.
- * @param parameters Parameters that control specific aspects of the behavior of the extractors.
+ * @param outputConsumer The {@link OutputConsumer} to which track data and samples are pushed.
* @return A new instance.
+ * @throws IllegalArgumentException If an invalid name is provided.
*/
- public static MediaParser createByName(
- String name, OutputCallback outputCallback, Parameters parameters) {
- throw new UnsupportedOperationException();
+ public static @NonNull MediaParser createByName(
+ @NonNull String name, @NonNull OutputConsumer outputConsumer) {
+ String[] nameAsArray = new String[] {name};
+ assertValidNames(nameAsArray);
+ return new MediaParser(outputConsumer, /* sniff= */ false, name);
}
/**
@@ -307,30 +394,46 @@ public final class MediaParser {
* the first {@link #advance} call. Extractor implementations will sniff the content in order of
* appearance in {@code extractorNames}.
*
- * @param outputCallback The {@link OutputCallback} to track data and samples are obtained.
- * @param parameters Parameters that control specific aspects of the behavior of the extractors.
+ * @param outputConsumer The {@link OutputConsumer} to which extracted data is output.
* @param extractorNames The names of the extractors to sniff the content with. If empty, a
* default array of names is used.
* @return A new instance.
*/
- public static MediaParser create(
- OutputCallback outputCallback, Parameters parameters, String... extractorNames) {
- throw new UnsupportedOperationException();
+ public static @NonNull MediaParser create(
+ @NonNull OutputConsumer outputConsumer, @NonNull String... extractorNames) {
+ assertValidNames(extractorNames);
+ if (extractorNames.length == 0) {
+ extractorNames = EXTRACTOR_FACTORIES_BY_NAME.keySet().toArray(new String[0]);
+ }
+ return new MediaParser(outputConsumer, /* sniff= */ true, extractorNames);
}
// Misc static methods.
/**
* Returns an immutable list with the names of the extractors that are suitable for container
- * formats with the given {@code mimeTypes}. If an empty string is passed, all available
- * extractors' names are returned.
+ * formats with the given {@link MediaFormat}.
*
- * <p>TODO: Replace string with media type object.
+ * <p>TODO: List which properties are taken into account. E.g. MimeType.
*/
- public static List<String> getExtractorNames(String mimeTypes) {
+ public static @NonNull List<String> getExtractorNames(@NonNull MediaFormat mediaFormat) {
throw new UnsupportedOperationException();
}
+ // Private fields.
+
+ private final OutputConsumer mOutputConsumer;
+ private final String[] mExtractorNamesPool;
+ private final PositionHolder mPositionHolder;
+ private final InputReadingDataSource mDataSource;
+ private final ExtractorInputAdapter mScratchExtractorInputAdapter;
+ private final ParsableByteArrayAdapter mScratchParsableByteArrayAdapter;
+ private String mExtractorName;
+ private Extractor mExtractor;
+ private ExtractorInput mExtractorInput;
+ private long mPendingSeekPosition;
+ private long mPendingSeekTimeUs;
+
// Public methods.
/**
@@ -344,8 +447,8 @@ public final class MediaParser {
* @return The name of the backing extractor implementation, or null if the backing extractor
* implementation has not yet been selected.
*/
- public String getExtractorName() {
- throw new UnsupportedOperationException();
+ public @Nullable String getExtractorName() {
+ return mExtractorName;
}
/**
@@ -357,26 +460,85 @@ public final class MediaParser {
* <p>If this instance was created using {@link #create}. the first call to this method will
* sniff the content with the extractors with the provided names.
*
- * @param input The {@link Input} from which to obtain the media container data.
- * @param resultHolder The {@link ResultHolder} into which the result of the operation will be
- * written.
+ * @param seekableInputReader The {@link SeekableInputReader} from which to obtain the media
+ * container data.
+ * @return Whether there is any data left to extract. Returns false if the end of input has been
+ * reached.
* @throws UnrecognizedInputFormatException
*/
- public void advance(Input input, ResultHolder resultHolder)
+ public boolean advance(@NonNull SeekableInputReader seekableInputReader)
throws IOException, InterruptedException {
- throw new UnsupportedOperationException();
+ if (mExtractorInput == null) {
+ // TODO: For efficiency, the same implementation should be used, by providing a
+ // clearBuffers() method, or similar.
+ mExtractorInput =
+ new DefaultExtractorInput(
+ mDataSource,
+ seekableInputReader.getPosition(),
+ seekableInputReader.getLength());
+ }
+ mDataSource.mInputReader = seekableInputReader;
+
+ if (mExtractor == null) {
+ for (String extractorName : mExtractorNamesPool) {
+ Extractor extractor =
+ EXTRACTOR_FACTORIES_BY_NAME.get(extractorName).createInstance();
+ try {
+ if (extractor.sniff(mExtractorInput)) {
+ mExtractorName = extractorName;
+ mExtractor = extractor;
+ mExtractor.init(new ExtractorOutputAdapter());
+ break;
+ }
+ } catch (EOFException e) {
+ // Do nothing.
+ } catch (IOException | InterruptedException e) {
+ throw new IllegalStateException(e);
+ } finally {
+ mExtractorInput.resetPeekPosition();
+ }
+ }
+ if (mExtractor == null) {
+ UnrecognizedInputFormatException.createForExtractors(mExtractorNamesPool);
+ }
+ return true;
+ }
+
+ if (isPendingSeek()) {
+ mExtractor.seek(mPendingSeekPosition, mPendingSeekTimeUs);
+ removePendingSeek();
+ }
+
+ mPositionHolder.position = seekableInputReader.getPosition();
+ int result = mExtractor.read(mExtractorInput, mPositionHolder);
+ if (result == Extractor.RESULT_END_OF_INPUT) {
+ return false;
+ }
+ if (result == Extractor.RESULT_SEEK) {
+ mExtractorInput = null;
+ seekableInputReader.seekToPosition(mPositionHolder.position);
+ }
+ return true;
}
/**
* Seeks within the media container being extracted.
*
- * <p>Following a call to this method, the {@link Input} passed to the next invocation of {@link
- * #advance} must provide data starting from {@link SeekPoint#mPosition} in the stream.
+ * <p>{@link SeekPoint SeekPoints} can be obtained from the {@link SeekMap} passed to {@link
+ * OutputConsumer#onSeekMap(SeekMap)}.
+ *
+ * <p>Following a call to this method, the {@link InputReader} passed to the next invocation of
+ * {@link #advance} must provide data starting from {@link SeekPoint#position} in the stream.
*
* @param seekPoint The {@link SeekPoint} to seek to.
*/
- public void seek(SeekPoint seekPoint) {
- throw new UnsupportedOperationException();
+ public void seek(@NonNull SeekPoint seekPoint) {
+ if (mExtractor == null) {
+ mPendingSeekPosition = seekPoint.position;
+ mPendingSeekTimeUs = seekPoint.timeUs;
+ } else {
+ mExtractor.seek(seekPoint.position, seekPoint.timeUs);
+ }
}
/**
@@ -386,6 +548,359 @@ public final class MediaParser {
* invoked. DESIGN NOTE: Should be removed. There shouldn't be any resource for releasing.
*/
public void release() {
- throw new UnsupportedOperationException();
+ mExtractorInput = null;
+ mExtractor = null;
+ }
+
+ // Private methods.
+
+ private MediaParser(
+ OutputConsumer outputConsumer, boolean sniff, String... extractorNamesPool) {
+ mOutputConsumer = outputConsumer;
+ mExtractorNamesPool = extractorNamesPool;
+ if (!sniff) {
+ mExtractorName = extractorNamesPool[0];
+ mExtractor = EXTRACTOR_FACTORIES_BY_NAME.get(mExtractorName).createInstance();
+ }
+ mPositionHolder = new PositionHolder();
+ mDataSource = new InputReadingDataSource();
+ removePendingSeek();
+ mScratchExtractorInputAdapter = new ExtractorInputAdapter();
+ mScratchParsableByteArrayAdapter = new ParsableByteArrayAdapter();
+ }
+
+ private boolean isPendingSeek() {
+ return mPendingSeekPosition >= 0;
+ }
+
+ private void removePendingSeek() {
+ mPendingSeekPosition = -1;
+ mPendingSeekTimeUs = -1;
+ }
+
+ // Private classes.
+
+ private static final class InputReadingDataSource implements DataSource {
+
+ public InputReader mInputReader;
+
+ @Override
+ public void addTransferListener(TransferListener transferListener) {
+ // Do nothing.
+ }
+
+ @Override
+ public long open(DataSpec dataSpec) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public int read(byte[] buffer, int offset, int readLength) throws IOException {
+ // TODO: Reevaluate interruption in Input.
+ try {
+ return mInputReader.read(buffer, offset, readLength);
+ } catch (InterruptedException e) {
+ // TODO: Remove.
+ throw new RuntimeException();
+ }
+ }
+
+ @Override
+ public Uri getUri() {
+ return null;
+ }
+
+ @Override
+ public Map<String, List<String>> getResponseHeaders() {
+ return null;
+ }
+
+ @Override
+ public void close() {
+ throw new UnsupportedOperationException();
+ }
+ }
+
+ private final class ExtractorOutputAdapter implements ExtractorOutput {
+
+ private final SparseArray<TrackOutput> mTrackOutputAdapters;
+ private boolean mTracksEnded;
+
+ private ExtractorOutputAdapter() {
+ mTrackOutputAdapters = new SparseArray<>();
+ }
+
+ @Override
+ public TrackOutput track(int id, int type) {
+ TrackOutput trackOutput = mTrackOutputAdapters.get(id);
+ if (trackOutput == null) {
+ trackOutput = new TrackOutputAdapter(mTrackOutputAdapters.size());
+ mTrackOutputAdapters.put(id, trackOutput);
+ }
+ return trackOutput;
+ }
+
+ @Override
+ public void endTracks() {
+ mOutputConsumer.onTracksFound(mTrackOutputAdapters.size());
+ }
+
+ @Override
+ public void seekMap(com.google.android.exoplayer2.extractor.SeekMap exoplayerSeekMap) {
+ mOutputConsumer.onSeekMap(new ExoToMediaParserSeekMapAdapter(exoplayerSeekMap));
+ }
+ }
+
+ private class TrackOutputAdapter implements TrackOutput {
+
+ private final int mTrackIndex;
+
+ private TrackOutputAdapter(int trackIndex) {
+ mTrackIndex = trackIndex;
+ }
+
+ @Override
+ public void format(Format format) {
+ mOutputConsumer.onFormat(mTrackIndex, toMediaFormat(format));
+ }
+
+ @Override
+ public int sampleData(ExtractorInput input, int length, boolean allowEndOfInput)
+ throws IOException, InterruptedException {
+ mScratchExtractorInputAdapter.setExtractorInput(input, length);
+ long positionBeforeReading = mScratchExtractorInputAdapter.getPosition();
+ mOutputConsumer.onSampleData(mTrackIndex, mScratchExtractorInputAdapter);
+ return (int) (mScratchExtractorInputAdapter.getPosition() - positionBeforeReading);
+ }
+
+ @Override
+ public void sampleData(ParsableByteArray data, int length) {
+ mScratchParsableByteArrayAdapter.resetWithByteArray(data, length);
+ try {
+ mOutputConsumer.onSampleData(mTrackIndex, mScratchParsableByteArrayAdapter);
+ } catch (IOException | InterruptedException e) {
+ // Unexpected.
+ throw new RuntimeException(e);
+ }
+ }
+
+ @Override
+ public void sampleMetadata(
+ long timeUs, int flags, int size, int offset, CryptoData encryptionData) {
+ mOutputConsumer.onSampleCompleted(
+ mTrackIndex, timeUs, flags, size, offset, toCryptoInfo(encryptionData));
+ }
+ }
+
+ private static final class ExtractorInputAdapter implements InputReader {
+
+ private ExtractorInput mExtractorInput;
+ private int mCurrentPosition;
+ private long mLength;
+
+ public void setExtractorInput(ExtractorInput extractorInput, long length) {
+ mExtractorInput = extractorInput;
+ mCurrentPosition = 0;
+ mLength = length;
+ }
+
+ // Input implementation.
+
+ @Override
+ public int read(byte[] buffer, int offset, int readLength)
+ throws IOException, InterruptedException {
+ int readBytes = mExtractorInput.read(buffer, offset, readLength);
+ mCurrentPosition += readBytes;
+ return readBytes;
+ }
+
+ @Override
+ public long getPosition() {
+ return mCurrentPosition;
+ }
+
+ @Override
+ public long getLength() {
+ return mLength - mCurrentPosition;
+ }
+ }
+
+ private static final class ParsableByteArrayAdapter implements InputReader {
+
+ private ParsableByteArray mByteArray;
+ private long mLength;
+ private int mCurrentPosition;
+
+ public void resetWithByteArray(ParsableByteArray byteArray, long length) {
+ mByteArray = byteArray;
+ mCurrentPosition = 0;
+ mLength = length;
+ }
+
+ // Input implementation.
+
+ @Override
+ public int read(byte[] buffer, int offset, int readLength) {
+ mByteArray.readBytes(buffer, offset, readLength);
+ mCurrentPosition += readLength;
+ return readLength;
+ }
+
+ @Override
+ public long getPosition() {
+ return mCurrentPosition;
+ }
+
+ @Override
+ public long getLength() {
+ return mLength - mCurrentPosition;
+ }
+ }
+
+ /** Creates extractor instances. */
+ private interface ExtractorFactory {
+
+ /** Returns a new extractor instance. */
+ Extractor createInstance();
+ }
+
+ private static class ExoToMediaParserSeekMapAdapter implements SeekMap {
+
+ private final com.google.android.exoplayer2.extractor.SeekMap mExoPlayerSeekMap;
+
+ private ExoToMediaParserSeekMapAdapter(
+ com.google.android.exoplayer2.extractor.SeekMap exoplayerSeekMap) {
+ mExoPlayerSeekMap = exoplayerSeekMap;
+ }
+
+ @Override
+ public boolean isSeekable() {
+ return mExoPlayerSeekMap.isSeekable();
+ }
+
+ @Override
+ public long getDurationUs() {
+ return mExoPlayerSeekMap.getDurationUs();
+ }
+
+ @Override
+ public Pair<SeekPoint, SeekPoint> getSeekPoints(long timeUs) {
+ SeekPoints seekPoints = mExoPlayerSeekMap.getSeekPoints(timeUs);
+ return new Pair<>(toSeekPoint(seekPoints.first), toSeekPoint(seekPoints.second));
+ }
+ }
+
+ // Private static methods.
+
+ private static MediaFormat toMediaFormat(Format format) {
+
+ // TODO: Add if (value != Format.NO_VALUE);
+
+ MediaFormat result = new MediaFormat();
+ result.setInteger(MediaFormat.KEY_BIT_RATE, format.bitrate);
+ result.setInteger(MediaFormat.KEY_CHANNEL_COUNT, format.channelCount);
+ if (format.colorInfo != null) {
+ result.setInteger(MediaFormat.KEY_COLOR_TRANSFER, format.colorInfo.colorTransfer);
+ result.setInteger(MediaFormat.KEY_COLOR_RANGE, format.colorInfo.colorRange);
+ result.setInteger(MediaFormat.KEY_COLOR_STANDARD, format.colorInfo.colorSpace);
+ if (format.colorInfo.hdrStaticInfo != null) {
+ result.setByteBuffer(
+ MediaFormat.KEY_HDR_STATIC_INFO,
+ ByteBuffer.wrap(format.colorInfo.hdrStaticInfo));
+ }
+ }
+ result.setString(MediaFormat.KEY_MIME, format.sampleMimeType);
+ result.setFloat(MediaFormat.KEY_FRAME_RATE, format.frameRate);
+ result.setInteger(MediaFormat.KEY_WIDTH, format.width);
+ result.setInteger(MediaFormat.KEY_HEIGHT, format.height);
+ List<byte[]> initData = format.initializationData;
+ if (initData != null) {
+ for (int i = 0; i < initData.size(); i++) {
+ result.setByteBuffer("csd-" + i, ByteBuffer.wrap(initData.get(i)));
+ }
+ }
+ result.setString(MediaFormat.KEY_LANGUAGE, format.language);
+ result.setInteger(MediaFormat.KEY_MAX_INPUT_SIZE, format.maxInputSize);
+ result.setInteger(MediaFormat.KEY_PCM_ENCODING, format.pcmEncoding);
+ result.setInteger(MediaFormat.KEY_ROTATION, format.rotationDegrees);
+ result.setInteger(MediaFormat.KEY_SAMPLE_RATE, format.sampleRate);
+
+ int selectionFlags = format.selectionFlags;
+ // We avoid setting selection flags in the MediaFormat, unless explicitly signaled by the
+ // extractor.
+ if ((selectionFlags & C.SELECTION_FLAG_AUTOSELECT) != 0) {
+ result.setInteger(MediaFormat.KEY_IS_AUTOSELECT, 1);
+ }
+ if ((selectionFlags & C.SELECTION_FLAG_DEFAULT) != 0) {
+ result.setInteger(MediaFormat.KEY_IS_DEFAULT, 1);
+ }
+ if ((selectionFlags & C.SELECTION_FLAG_FORCED) != 0) {
+ result.setInteger(MediaFormat.KEY_IS_FORCED_SUBTITLE, 1);
+ }
+
+ // LACK OF SUPPORT FOR:
+ // format.accessibilityChannel;
+ // format.codecs;
+ // format.containerMimeType;
+ // format.drmInitData;
+ // format.encoderDelay;
+ // format.encoderPadding;
+ // format.id;
+ // format.metadata;
+ // format.pixelWidthHeightRatio;
+ // format.roleFlags;
+ // format.stereoMode;
+ // format.subsampleOffsetUs;
+ return result;
+ }
+
+ private static int toFrameworkFlags(int flags) {
+ // TODO: Implement.
+ return 0;
+ }
+
+ private static MediaCodec.CryptoInfo toCryptoInfo(TrackOutput.CryptoData encryptionData) {
+ // TODO: Implement.
+ return null;
+ }
+
+ /** Returns a new {@link SeekPoint} equivalent to the given {@code exoPlayerSeekPoint}. */
+ private static SeekPoint toSeekPoint(
+ com.google.android.exoplayer2.extractor.SeekPoint exoPlayerSeekPoint) {
+ return new SeekPoint(exoPlayerSeekPoint.timeUs, exoPlayerSeekPoint.position);
+ }
+
+ private static void assertValidNames(@NonNull String[] names) {
+ for (String name : names) {
+ if (!EXTRACTOR_FACTORIES_BY_NAME.containsKey(name)) {
+ throw new IllegalArgumentException(
+ "Invalid extractor name: "
+ + name
+ + ". Supported extractors are: "
+ + TextUtils.join(", ", EXTRACTOR_FACTORIES_BY_NAME.keySet())
+ + ".");
+ }
+ }
+ }
+
+ // Static initialization.
+
+ static {
+ // Using a LinkedHashMap to keep the insertion order when iterating over the keys.
+ LinkedHashMap<String, ExtractorFactory> extractorFactoriesByName = new LinkedHashMap<>();
+ extractorFactoriesByName.put("exo.Ac3Extractor", Ac3Extractor::new);
+ extractorFactoriesByName.put("exo.Ac4Extractor", Ac4Extractor::new);
+ extractorFactoriesByName.put("exo.AdtsExtractor", AdtsExtractor::new);
+ extractorFactoriesByName.put("exo.AmrExtractor", AmrExtractor::new);
+ extractorFactoriesByName.put("exo.FlvExtractor", FlvExtractor::new);
+ extractorFactoriesByName.put("exo.FragmentedMp4Extractor", FragmentedMp4Extractor::new);
+ extractorFactoriesByName.put("exo.MatroskaExtractor", MatroskaExtractor::new);
+ extractorFactoriesByName.put("exo.Mp3Extractor", Mp3Extractor::new);
+ extractorFactoriesByName.put("exo.Mp4Extractor", Mp4Extractor::new);
+ extractorFactoriesByName.put("exo.OggExtractor", OggExtractor::new);
+ extractorFactoriesByName.put("exo.PsExtractor", PsExtractor::new);
+ extractorFactoriesByName.put("exo.TsExtractor", TsExtractor::new);
+ extractorFactoriesByName.put("exo.WavExtractor", WavExtractor::new);
+ EXTRACTOR_FACTORIES_BY_NAME = Collections.unmodifiableMap(extractorFactoriesByName);
}
}
diff --git a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
index 2496d44f1488..c8532e006489 100644
--- a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
+++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
@@ -119,11 +119,11 @@ import com.android.systemui.statusbar.phone.NotificationGroupAlertTransferHelper
import com.android.systemui.statusbar.phone.NotificationGroupManager;
import com.android.systemui.statusbar.phone.ScrimController;
import com.android.systemui.statusbar.phone.StatusBar;
+import com.android.systemui.statusbar.phone.StatusBarComponent;
import com.android.systemui.statusbar.phone.StatusBarIconController;
import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
import com.android.systemui.statusbar.phone.StatusBarNotificationActivityStarter;
import com.android.systemui.statusbar.phone.StatusBarWindowController;
-import com.android.systemui.statusbar.phone.StatusBarWindowViewController;
import com.android.systemui.statusbar.policy.BatteryController;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.DeviceProvisionedController;
@@ -140,6 +140,7 @@ import java.util.Map;
import java.util.Optional;
import javax.inject.Named;
+import javax.inject.Provider;
import dagger.Lazy;
@@ -156,7 +157,6 @@ public class CarStatusBar extends StatusBar implements CarBatteryController.Batt
private static final float FLING_SPEED_UP_FACTOR = 0.6f;
private final ScrimController mScrimController;
- private final StatusBarWindowViewController mStatusBarWindowViewController;
private final LockscreenLockIconController mLockscreenLockIconController;
private float mOpeningVelocity = DEFAULT_FLING_VELOCITY;
@@ -288,7 +288,6 @@ public class CarStatusBar extends StatusBar implements CarBatteryController.Batt
NotificationListener notificationListener,
ConfigurationController configurationController,
StatusBarWindowController statusBarWindowController,
- StatusBarWindowViewController statusBarWindowViewController,
LockscreenLockIconController lockscreenLockIconController,
DozeParameters dozeParameters,
ScrimController scrimController,
@@ -301,6 +300,7 @@ public class CarStatusBar extends StatusBar implements CarBatteryController.Batt
VolumeComponent volumeComponent,
CommandQueue commandQueue,
Optional<Recents> recents,
+ Provider<StatusBarComponent.Builder> statusBarComponentBuilder,
PluginManager pluginManager,
RemoteInputUriController remoteInputUriController,
Optional<Divider> dividerOptional,
@@ -366,7 +366,6 @@ public class CarStatusBar extends StatusBar implements CarBatteryController.Batt
notificationListener,
configurationController,
statusBarWindowController,
- statusBarWindowViewController,
lockscreenLockIconController,
dozeParameters,
scrimController,
@@ -380,6 +379,7 @@ public class CarStatusBar extends StatusBar implements CarBatteryController.Batt
volumeComponent,
commandQueue,
recents,
+ statusBarComponentBuilder,
pluginManager,
remoteInputUriController,
dividerOptional,
@@ -390,7 +390,6 @@ public class CarStatusBar extends StatusBar implements CarBatteryController.Batt
viewMediatorCallback,
dismissCallbackRegistry);
mScrimController = scrimController;
- mStatusBarWindowViewController = statusBarWindowViewController;
mLockscreenLockIconController = lockscreenLockIconController;
mDeviceProvisionedController = deviceProvisionedController;
mCarServiceProvider = carServiceProvider;
diff --git a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBarModule.java b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBarModule.java
index 324c6e41e339..eff60fa246a4 100644
--- a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBarModule.java
+++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBarModule.java
@@ -78,11 +78,11 @@ import com.android.systemui.statusbar.phone.LockscreenWallpaper;
import com.android.systemui.statusbar.phone.NotificationGroupAlertTransferHelper;
import com.android.systemui.statusbar.phone.NotificationGroupManager;
import com.android.systemui.statusbar.phone.ScrimController;
+import com.android.systemui.statusbar.phone.StatusBarComponent;
import com.android.systemui.statusbar.phone.StatusBarIconController;
import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
import com.android.systemui.statusbar.phone.StatusBarNotificationActivityStarter;
import com.android.systemui.statusbar.phone.StatusBarWindowController;
-import com.android.systemui.statusbar.phone.StatusBarWindowViewController;
import com.android.systemui.statusbar.policy.BatteryController;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.DeviceProvisionedController;
@@ -96,6 +96,7 @@ import com.android.systemui.volume.VolumeComponent;
import java.util.Optional;
import javax.inject.Named;
+import javax.inject.Provider;
import javax.inject.Singleton;
import dagger.Lazy;
@@ -162,7 +163,6 @@ public class CarStatusBarModule {
NotificationListener notificationListener,
ConfigurationController configurationController,
StatusBarWindowController statusBarWindowController,
- StatusBarWindowViewController statusBarWindowViewController,
LockscreenLockIconController lockscreenLockIconController,
DozeParameters dozeParameters,
ScrimController scrimController,
@@ -175,6 +175,7 @@ public class CarStatusBarModule {
VolumeComponent volumeComponent,
CommandQueue commandQueue,
Optional<Recents> recentsOptional,
+ Provider<StatusBarComponent.Builder> statusBarComponentBuilder,
PluginManager pluginManager,
RemoteInputUriController remoteInputUriController,
Optional<Divider> dividerOptional,
@@ -239,7 +240,6 @@ public class CarStatusBarModule {
notificationListener,
configurationController,
statusBarWindowController,
- statusBarWindowViewController,
lockscreenLockIconController,
dozeParameters,
scrimController,
@@ -252,6 +252,7 @@ public class CarStatusBarModule {
volumeComponent,
commandQueue,
recentsOptional,
+ statusBarComponentBuilder,
pluginManager,
remoteInputUriController,
dividerOptional,
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java
index 785dd561d1b7..96aee512c090 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java
@@ -44,8 +44,8 @@ public class A2dpProfile implements LocalBluetoothProfile {
private final CachedBluetoothDeviceManager mDeviceManager;
static final ParcelUuid[] SINK_UUIDS = {
- BluetoothUuid.AudioSink,
- BluetoothUuid.AdvAudioDist,
+ BluetoothUuid.A2DP_SINK,
+ BluetoothUuid.ADV_AUDIO_DIST,
};
static final String NAME = "A2DP";
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpSinkProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpSinkProfile.java
index 4ce9d3e2dff2..55765dd40d36 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpSinkProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpSinkProfile.java
@@ -40,8 +40,8 @@ final class A2dpSinkProfile implements LocalBluetoothProfile {
private final CachedBluetoothDeviceManager mDeviceManager;
static final ParcelUuid[] SRC_UUIDS = {
- BluetoothUuid.AudioSource,
- BluetoothUuid.AdvAudioDist,
+ BluetoothUuid.A2DP_SOURCE,
+ BluetoothUuid.ADV_AUDIO_DIST,
};
static final String NAME = "A2DPSink";
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothDeviceFilter.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothDeviceFilter.java
index 8dec86ac3614..b8ad321d6dd3 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothDeviceFilter.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothDeviceFilter.java
@@ -22,6 +22,8 @@ import android.bluetooth.BluetoothUuid;
import android.os.ParcelUuid;
import android.util.Log;
+import com.android.internal.util.ArrayUtils;
+
/**
* BluetoothDeviceFilter contains a static method that returns a
* Filter object that returns whether or not the BluetoothDevice
@@ -130,7 +132,7 @@ public final class BluetoothDeviceFilter {
@Override
boolean matches(ParcelUuid[] uuids, BluetoothClass btClass) {
if (uuids != null) {
- if (BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.ObexObjectPush)) {
+ if (ArrayUtils.contains(uuids, BluetoothUuid.OBEX_OBJECT_PUSH)) {
return true;
}
}
@@ -144,7 +146,7 @@ public final class BluetoothDeviceFilter {
@Override
boolean matches(ParcelUuid[] uuids, BluetoothClass btClass) {
if (uuids != null) {
- if (BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.PANU)) {
+ if (ArrayUtils.contains(uuids, BluetoothUuid.PANU)) {
return true;
}
}
@@ -158,7 +160,7 @@ public final class BluetoothDeviceFilter {
@Override
boolean matches(ParcelUuid[] uuids, BluetoothClass btClass) {
if (uuids != null) {
- if (BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.NAP)) {
+ if (ArrayUtils.contains(uuids, BluetoothUuid.NAP)) {
return true;
}
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
index 833c4ac07633..066659677add 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
@@ -35,6 +35,7 @@ import android.util.Log;
import androidx.annotation.VisibleForTesting;
+import com.android.internal.util.ArrayUtils;
import com.android.settingslib.R;
import com.android.settingslib.Utils;
@@ -685,9 +686,9 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice>
ParcelUuid[] uuids = mDevice.getUuids();
long timeout = MAX_UUID_DELAY_FOR_AUTO_CONNECT;
- if (BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.Hogp)) {
+ if (ArrayUtils.contains(uuids, BluetoothUuid.HOGP)) {
timeout = MAX_HOGP_DELAY_FOR_AUTO_CONNECT;
- } else if (BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.HearingAid)) {
+ } else if (ArrayUtils.contains(uuids, BluetoothUuid.HEARING_AID)) {
timeout = MAX_HEARING_AIDS_DELAY_FOR_AUTO_CONNECT;
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HeadsetProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HeadsetProfile.java
index c1933fd87633..9f7b7181b19f 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HeadsetProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HeadsetProfile.java
@@ -45,7 +45,7 @@ public class HeadsetProfile implements LocalBluetoothProfile {
static final ParcelUuid[] UUIDS = {
BluetoothUuid.HSP,
- BluetoothUuid.Handsfree,
+ BluetoothUuid.HFP,
};
static final String NAME = "HEADSET";
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HfpClientProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HfpClientProfile.java
index 4bdbc3196556..860b77d1ebcd 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HfpClientProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HfpClientProfile.java
@@ -44,7 +44,7 @@ final class HfpClientProfile implements LocalBluetoothProfile {
static final ParcelUuid[] SRC_UUIDS = {
BluetoothUuid.HSP_AG,
- BluetoothUuid.Handsfree_AG,
+ BluetoothUuid.HFP_AG,
};
static final String NAME = "HEADSET_CLIENT";
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java
index 29c6d719641a..ae2acbea8e4d 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java
@@ -30,8 +30,8 @@ import android.bluetooth.BluetoothMapClient;
import android.bluetooth.BluetoothPan;
import android.bluetooth.BluetoothPbap;
import android.bluetooth.BluetoothPbapClient;
-import android.bluetooth.BluetoothSap;
import android.bluetooth.BluetoothProfile;
+import android.bluetooth.BluetoothSap;
import android.bluetooth.BluetoothUuid;
import android.content.Context;
import android.content.Intent;
@@ -40,6 +40,7 @@ import android.util.Log;
import androidx.annotation.VisibleForTesting;
+import com.android.internal.util.ArrayUtils;
import com.android.internal.util.CollectionUtils;
import java.util.ArrayList;
@@ -471,43 +472,40 @@ public class LocalBluetoothProfileManager {
}
if (mHeadsetProfile != null) {
- if ((BluetoothUuid.isUuidPresent(localUuids, BluetoothUuid.HSP_AG) &&
- BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.HSP)) ||
- (BluetoothUuid.isUuidPresent(localUuids, BluetoothUuid.Handsfree_AG) &&
- BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.Handsfree))) {
+ if ((ArrayUtils.contains(localUuids, BluetoothUuid.HSP_AG)
+ && ArrayUtils.contains(uuids, BluetoothUuid.HSP))
+ || (ArrayUtils.contains(localUuids, BluetoothUuid.HFP_AG)
+ && ArrayUtils.contains(uuids, BluetoothUuid.HFP))) {
profiles.add(mHeadsetProfile);
removedProfiles.remove(mHeadsetProfile);
}
}
if ((mHfpClientProfile != null) &&
- BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.Handsfree_AG) &&
- BluetoothUuid.isUuidPresent(localUuids, BluetoothUuid.Handsfree)) {
+ ArrayUtils.contains(uuids, BluetoothUuid.HFP_AG)
+ && ArrayUtils.contains(localUuids, BluetoothUuid.HFP)) {
profiles.add(mHfpClientProfile);
removedProfiles.remove(mHfpClientProfile);
}
- if (BluetoothUuid.containsAnyUuid(uuids, A2dpProfile.SINK_UUIDS) &&
- mA2dpProfile != null) {
+ if (BluetoothUuid.containsAnyUuid(uuids, A2dpProfile.SINK_UUIDS) && mA2dpProfile != null) {
profiles.add(mA2dpProfile);
removedProfiles.remove(mA2dpProfile);
}
- if (BluetoothUuid.containsAnyUuid(uuids, A2dpSinkProfile.SRC_UUIDS) &&
- mA2dpSinkProfile != null) {
+ if (BluetoothUuid.containsAnyUuid(uuids, A2dpSinkProfile.SRC_UUIDS)
+ && mA2dpSinkProfile != null) {
profiles.add(mA2dpSinkProfile);
removedProfiles.remove(mA2dpSinkProfile);
}
- if (BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.ObexObjectPush) &&
- mOppProfile != null) {
+ if (ArrayUtils.contains(uuids, BluetoothUuid.OBEX_OBJECT_PUSH) && mOppProfile != null) {
profiles.add(mOppProfile);
removedProfiles.remove(mOppProfile);
}
- if ((BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.Hid) ||
- BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.Hogp)) &&
- mHidProfile != null) {
+ if ((ArrayUtils.contains(uuids, BluetoothUuid.HID)
+ || ArrayUtils.contains(uuids, BluetoothUuid.HOGP)) && mHidProfile != null) {
profiles.add(mHidProfile);
removedProfiles.remove(mHidProfile);
}
@@ -520,8 +518,8 @@ public class LocalBluetoothProfileManager {
if(isPanNapConnected)
if(DEBUG) Log.d(TAG, "Valid PAN-NAP connection exists.");
- if ((BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.NAP) &&
- mPanProfile != null) || isPanNapConnected) {
+ if ((ArrayUtils.contains(uuids, BluetoothUuid.NAP) && mPanProfile != null)
+ || isPanNapConnected) {
profiles.add(mPanProfile);
removedProfiles.remove(mPanProfile);
}
@@ -545,20 +543,18 @@ public class LocalBluetoothProfileManager {
removedProfiles.remove(mMapClientProfile);
}
- if ((mPbapClientProfile != null) &&
- BluetoothUuid.isUuidPresent(localUuids, BluetoothUuid.PBAP_PCE) &&
- BluetoothUuid.containsAnyUuid(uuids, PbapClientProfile.SRC_UUIDS)) {
+ if ((mPbapClientProfile != null) && ArrayUtils.contains(localUuids, BluetoothUuid.PBAP_PCE)
+ && BluetoothUuid.containsAnyUuid(uuids, PbapClientProfile.SRC_UUIDS)) {
profiles.add(mPbapClientProfile);
removedProfiles.remove(mPbapClientProfile);
}
- if (BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.HearingAid) &&
- mHearingAidProfile != null) {
+ if (ArrayUtils.contains(uuids, BluetoothUuid.HEARING_AID) && mHearingAidProfile != null) {
profiles.add(mHearingAidProfile);
removedProfiles.remove(mHearingAidProfile);
}
- if (mSapProfile != null && BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.SAP)) {
+ if (mSapProfile != null && ArrayUtils.contains(uuids, BluetoothUuid.SAP)) {
profiles.add(mSapProfile);
removedProfiles.remove(mSapProfile);
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/PbapServerProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/PbapServerProfile.java
index 17104e4e96cd..d91226e02878 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/PbapServerProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/PbapServerProfile.java
@@ -46,7 +46,7 @@ public class PbapServerProfile implements LocalBluetoothProfile {
// The UUIDs indicate that remote device might access pbap server
static final ParcelUuid[] PBAB_CLIENT_UUIDS = {
BluetoothUuid.HSP,
- BluetoothUuid.Handsfree,
+ BluetoothUuid.HFP,
BluetoothUuid.PBAP_PCE
};
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManagerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManagerTest.java
index 5d5872ea2354..fd5b05311247 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManagerTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManagerTest.java
@@ -132,7 +132,7 @@ public class LocalBluetoothProfileManagerTest {
mShadowBluetoothAdapter.setSupportedProfiles(generateList(
new int[] {BluetoothProfile.HID_HOST}));
mProfileManager.updateLocalProfiles();
- ParcelUuid[] uuids = new ParcelUuid[]{BluetoothUuid.Hid};
+ ParcelUuid[] uuids = new ParcelUuid[]{BluetoothUuid.HID};
ParcelUuid[] localUuids = new ParcelUuid[]{};
List<LocalBluetoothProfile> profiles = new ArrayList<>();
List<LocalBluetoothProfile> removedProfiles = new ArrayList<>();
diff --git a/packages/SettingsProvider/src/android/provider/settings/backup/GlobalSettings.java b/packages/SettingsProvider/src/android/provider/settings/backup/GlobalSettings.java
index 1527de1a1d17..1f687420a377 100644
--- a/packages/SettingsProvider/src/android/provider/settings/backup/GlobalSettings.java
+++ b/packages/SettingsProvider/src/android/provider/settings/backup/GlobalSettings.java
@@ -70,5 +70,7 @@ public class GlobalSettings {
Settings.Global.CHARGING_VIBRATION_ENABLED,
Settings.Global.AWARE_ALLOWED,
Settings.Global.NOTIFICATION_BUBBLES,
+ Settings.Global.CUSTOM_BUGREPORT_HANDLER_APP,
+ Settings.Global.CUSTOM_BUGREPORT_HANDLER_USER,
};
}
diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/GlobalSettingsValidators.java b/packages/SettingsProvider/src/android/provider/settings/validators/GlobalSettingsValidators.java
index 4a0ed6f91ed3..3d278db800a6 100644
--- a/packages/SettingsProvider/src/android/provider/settings/validators/GlobalSettingsValidators.java
+++ b/packages/SettingsProvider/src/android/provider/settings/validators/GlobalSettingsValidators.java
@@ -149,5 +149,7 @@ public class GlobalSettingsValidators {
VALIDATORS.put(
Global.POWER_BUTTON_VERY_LONG_PRESS, new InclusiveIntegerRangeValidator(0, 1));
VALIDATORS.put(Global.NOTIFICATION_BUBBLES, BOOLEAN_VALIDATOR);
+ VALIDATORS.put(Global.CUSTOM_BUGREPORT_HANDLER_APP, ANY_STRING_VALIDATOR);
+ VALIDATORS.put(Global.CUSTOM_BUGREPORT_HANDLER_USER, ANY_INTEGER_VALIDATOR);
}
}
diff --git a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
index 540726bddf5e..c23a494d3312 100644
--- a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
+++ b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
@@ -268,6 +268,7 @@ public class SettingsBackupTest {
Settings.Global.ERROR_LOGCAT_PREFIX,
Settings.Global.EUICC_PROVISIONED,
Settings.Global.EUICC_SUPPORTED_COUNTRIES,
+ Settings.Global.EUICC_UNSUPPORTED_COUNTRIES,
Settings.Global.EUICC_FACTORY_RESET_TIMEOUT_MILLIS,
Settings.Global.EUICC_REMOVING_INVISIBLE_PROFILES_TIMEOUT_MILLIS,
Settings.Global.FANCY_IME_ANIMATIONS,
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index 0a671d9185f0..6f6803817138 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -288,6 +288,11 @@
android:exported="false"
android:permission="com.android.systemui.permission.SELF" />
+ <service android:name=".assist.AssistHandleService"
+ android:exported="true"
+ android:enabled="false"
+ />
+
<!-- started from PhoneWindowManager
TODO: Should have an android:permission attribute -->
<service android:name=".screenshot.TakeScreenshotService"
diff --git a/packages/SystemUI/src/com/android/systemui/ForegroundServiceController.java b/packages/SystemUI/src/com/android/systemui/ForegroundServiceController.java
index 493186b2bd85..41dd5bbf272b 100644
--- a/packages/SystemUI/src/com/android/systemui/ForegroundServiceController.java
+++ b/packages/SystemUI/src/com/android/systemui/ForegroundServiceController.java
@@ -139,6 +139,8 @@ public class ForegroundServiceController {
}
}
+ // TODO: (b/145659174) remove when moving to NewNotifPipeline. Replaced by
+ // ForegroundCoordinator
// Update appOp if there's an associated pending or visible notification:
final String foregroundKey = getStandardLayoutKey(userId, packageName);
if (foregroundKey != null) {
diff --git a/packages/SystemUI/src/com/android/systemui/ForegroundServiceNotificationListener.java b/packages/SystemUI/src/com/android/systemui/ForegroundServiceNotificationListener.java
index c4e276277df5..8105faa23e89 100644
--- a/packages/SystemUI/src/com/android/systemui/ForegroundServiceNotificationListener.java
+++ b/packages/SystemUI/src/com/android/systemui/ForegroundServiceNotificationListener.java
@@ -52,6 +52,9 @@ public class ForegroundServiceNotificationListener {
NotifCollection notifCollection) {
mContext = context;
mForegroundServiceController = foregroundServiceController;
+
+ // TODO: (b/145659174) remove mEntryManager when moving to NewNotifPipeline. Replaced by
+ // ForegroundCoordinator
mEntryManager = notificationEntryManager;
mEntryManager.addNotificationEntryListener(new NotificationEntryListener() {
@Override
@@ -171,8 +174,8 @@ public class ForegroundServiceNotificationListener {
true /* create if not found */);
}
- // TODO: remove this when fully migrated to the NewNotifPipeline (work done in
- // ForegroundCoordinator)
+ // TODO: (b/145659174) remove when moving to NewNotifPipeline. Replaced by
+ // ForegroundCoordinator
private void tagForeground(NotificationEntry entry) {
final StatusBarNotification sbn = entry.getSbn();
ArraySet<Integer> activeOps = mForegroundServiceController.getAppOps(
diff --git a/packages/SystemUI/src/com/android/systemui/assist/AssistHandleService.kt b/packages/SystemUI/src/com/android/systemui/assist/AssistHandleService.kt
new file mode 100644
index 000000000000..9ceafc674d34
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/assist/AssistHandleService.kt
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.assist
+
+import android.app.Service
+import android.content.Intent
+import android.os.IBinder
+import dagger.Lazy
+import javax.inject.Inject
+
+class AssistHandleService @Inject constructor(private val assistManager: Lazy<AssistManager>)
+ : Service() {
+
+ private val binder = object : IAssistHandleService.Stub() {
+ override fun requestAssistHandles() {
+ assistManager.get().requestAssistHandles()
+ }
+ }
+
+ override fun onBind(intent: Intent?): IBinder? {
+ return binder
+ }
+} \ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/assist/AssistModule.java b/packages/SystemUI/src/com/android/systemui/assist/AssistModule.java
index 6f5a17dca432..96939b010555 100644
--- a/packages/SystemUI/src/com/android/systemui/assist/AssistModule.java
+++ b/packages/SystemUI/src/com/android/systemui/assist/AssistModule.java
@@ -16,6 +16,7 @@
package com.android.systemui.assist;
+import android.app.Service;
import android.content.Context;
import android.os.Handler;
import android.os.HandlerThread;
@@ -33,8 +34,11 @@ import java.util.Map;
import javax.inject.Named;
import javax.inject.Singleton;
+import dagger.Binds;
import dagger.Module;
import dagger.Provides;
+import dagger.multibindings.ClassKey;
+import dagger.multibindings.IntoMap;
/** Module for dagger injections related to the Assistant. */
@Module
@@ -87,4 +91,9 @@ public abstract class AssistModule {
static Clock provideSystemClock() {
return SystemClock::uptimeMillis;
}
+
+ @Binds
+ @IntoMap
+ @ClassKey(AssistHandleService.class)
+ abstract Service bindAssistHandleService(AssistHandleService assistHandleService);
}
diff --git a/packages/SystemUI/src/com/android/systemui/assist/IAssistHandleService.aidl b/packages/SystemUI/src/com/android/systemui/assist/IAssistHandleService.aidl
new file mode 100644
index 000000000000..ef07d9d3f182
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/assist/IAssistHandleService.aidl
@@ -0,0 +1,24 @@
+/**
+ * Copyright (c) 2009, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.assist;
+
+/** Interface implemented by AssisthandleService and called by on-device intelligence. */
+interface IAssistHandleService {
+
+ /** Request that the Assistant Handles be shown. */
+ oneway void requestAssistHandles();
+} \ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/Bubble.java b/packages/SystemUI/src/com/android/systemui/bubbles/Bubble.java
index 24ee969526cc..46d060e5ebda 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/Bubble.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/Bubble.java
@@ -199,7 +199,7 @@ class Bubble {
mExpandedView = (BubbleExpandedView) inflater.inflate(
R.layout.bubble_expanded_view, stackView, false /* attachToRoot */);
- mExpandedView.setBubble(this, stackView, mAppName);
+ mExpandedView.setBubble(this, stackView);
mInflated = true;
}
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
index ed21e141c12d..15bb3305ea52 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
@@ -700,10 +700,11 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
@Override
public void onPendingEntryAdded(NotificationEntry entry) {
boolean previouslyUserCreated = mUserCreatedBubbles.contains(entry.getKey());
- BubbleExperimentConfig.adjustForExperiments(mContext, entry, previouslyUserCreated);
+ boolean wasAdjusted = BubbleExperimentConfig.adjustForExperiments(
+ mContext, entry, previouslyUserCreated);
if (mNotificationInterruptionStateProvider.shouldBubbleUp(entry)
- && canLaunchInActivityView(mContext, entry)) {
+ && (canLaunchInActivityView(mContext, entry) || wasAdjusted)) {
updateBubble(entry);
}
}
@@ -711,10 +712,11 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
@Override
public void onPreEntryUpdated(NotificationEntry entry) {
boolean previouslyUserCreated = mUserCreatedBubbles.contains(entry.getKey());
- BubbleExperimentConfig.adjustForExperiments(mContext, entry, previouslyUserCreated);
+ boolean wasAdjusted = BubbleExperimentConfig.adjustForExperiments(
+ mContext, entry, previouslyUserCreated);
boolean shouldBubble = mNotificationInterruptionStateProvider.shouldBubbleUp(entry)
- && canLaunchInActivityView(mContext, entry);
+ && (canLaunchInActivityView(mContext, entry) || wasAdjusted);
if (!shouldBubble && mBubbleData.hasBubbleWithKey(entry.getKey())) {
// It was previously a bubble but no longer a bubble -- lets remove it
removeBubble(entry.getKey(), DISMISS_NO_LONGER_BUBBLE);
@@ -1022,11 +1024,6 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
PendingIntent intent = entry.getBubbleMetadata() != null
? entry.getBubbleMetadata().getIntent()
: null;
- return canLaunchIntentInActivityView(context, entry, intent);
- }
-
- static boolean canLaunchIntentInActivityView(Context context, NotificationEntry entry,
- PendingIntent intent) {
if (intent == null) {
Log.w(TAG, "Unable to create bubble -- no intent: " + entry.getKey());
return false;
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java
index 512b38e895bb..856b15e7135d 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java
@@ -31,15 +31,12 @@ import android.app.PendingIntent;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageManager;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.Color;
import android.graphics.Insets;
import android.graphics.Point;
import android.graphics.Rect;
-import android.graphics.drawable.Drawable;
import android.graphics.drawable.ShapeDrawable;
import android.os.RemoteException;
import android.service.notification.StatusBarNotification;
@@ -102,9 +99,7 @@ public class BubbleExpandedView extends LinearLayout implements View.OnClickList
private int mExpandedViewTouchSlop;
private Bubble mBubble;
- private PackageManager mPm;
private String mAppName;
- private Drawable mAppIcon;
private BubbleController mBubbleController = Dependency.get(BubbleController.class);
private WindowManager mWindowManager;
@@ -212,7 +207,6 @@ public class BubbleExpandedView extends LinearLayout implements View.OnClickList
public BubbleExpandedView(Context context, AttributeSet attrs, int defStyleAttr,
int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
- mPm = context.getPackageManager();
mDisplaySize = new Point();
mWindowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
// Get the real size -- this includes screen decorations (notches, statusbar, navbar).
@@ -350,29 +344,14 @@ public class BubbleExpandedView extends LinearLayout implements View.OnClickList
/**
* Sets the bubble used to populate this view.
*/
- public void setBubble(Bubble bubble, BubbleStackView stackView, String appName) {
+ public void setBubble(Bubble bubble, BubbleStackView stackView) {
if (DEBUG_BUBBLE_EXPANDED_VIEW) {
Log.d(TAG, "setBubble: bubble=" + (bubble != null ? bubble.getKey() : "null"));
}
-
mStackView = stackView;
mBubble = bubble;
- mAppName = appName;
-
- try {
- ApplicationInfo info = mPm.getApplicationInfo(
- bubble.getPackageName(),
- PackageManager.MATCH_UNINSTALLED_PACKAGES
- | PackageManager.MATCH_DISABLED_COMPONENTS
- | PackageManager.MATCH_DIRECT_BOOT_UNAWARE
- | PackageManager.MATCH_DIRECT_BOOT_AWARE);
- mAppIcon = mPm.getApplicationIcon(info);
- } catch (PackageManager.NameNotFoundException e) {
- // Do nothing.
- }
- if (mAppIcon == null) {
- mAppIcon = mPm.getDefaultActivityIcon();
- }
+ mAppName = bubble.getAppName();
+
applyThemeAttrs();
showSettingsIcon();
updateExpandedView();
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExperimentConfig.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExperimentConfig.java
index 17d6737b04d6..fd7fff4112c8 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExperimentConfig.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExperimentConfig.java
@@ -21,7 +21,6 @@ import static android.content.pm.LauncherApps.ShortcutQuery.FLAG_MATCH_DYNAMIC;
import static android.content.pm.LauncherApps.ShortcutQuery.FLAG_MATCH_MANIFEST;
import static android.content.pm.LauncherApps.ShortcutQuery.FLAG_MATCH_PINNED;
-import static com.android.systemui.bubbles.BubbleController.canLaunchIntentInActivityView;
import static com.android.systemui.bubbles.BubbleDebugConfig.DEBUG_EXPERIMENTS;
import static com.android.systemui.bubbles.BubbleDebugConfig.TAG_BUBBLES;
import static com.android.systemui.bubbles.BubbleDebugConfig.TAG_WITH_CLASS_NAME;
@@ -62,7 +61,7 @@ public class BubbleExperimentConfig {
private static final boolean ALLOW_ANY_NOTIF_TO_BUBBLE_DEFAULT = false;
private static final String ALLOW_MESSAGE_NOTIFS_TO_BUBBLE = "allow_message_notifs_to_bubble";
- private static final boolean ALLOW_MESSAGE_NOTIFS_TO_BUBBLE_DEFAULT = false;
+ private static final boolean ALLOW_MESSAGE_NOTIFS_TO_BUBBLE_DEFAULT = true;
private static final String ALLOW_SHORTCUTS_TO_BUBBLE = "allow_shortcuts_to_bubble";
private static final boolean ALLOW_SHORTCUT_TO_BUBBLE_DEFAULT = false;
@@ -107,8 +106,10 @@ public class BubbleExperimentConfig {
* If {@link #allowAnyNotifToBubble(Context)} is true, this method creates and adds
* {@link android.app.Notification.BubbleMetadata} to the notification entry as long as
* the notification has necessary info for BubbleMetadata.
+ *
+ * @return whether an adjustment was made.
*/
- static void adjustForExperiments(Context context, NotificationEntry entry,
+ static boolean adjustForExperiments(Context context, NotificationEntry entry,
boolean previouslyUserCreated) {
Notification.BubbleMetadata metadata = null;
boolean addedMetadata = false;
@@ -176,7 +177,9 @@ public class BubbleExperimentConfig {
Log.d(TAG, "Setting FLAG_BUBBLE for: " + entry.getKey());
}
entry.setFlagBubble(true);
+ return true;
}
+ return addedMetadata;
}
static Notification.BubbleMetadata createFromNotif(Context context, NotificationEntry entry) {
@@ -193,7 +196,7 @@ public class BubbleExperimentConfig {
? notification.getLargeIcon()
: notification.getSmallIcon();
}
- if (canLaunchIntentInActivityView(context, entry, intent)) {
+ if (intent != null) {
return new Notification.BubbleMetadata.Builder()
.setDesiredHeight(BUBBLE_HEIGHT)
.setIcon(icon)
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
index 9bd729edd210..442313d763ec 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
@@ -35,7 +35,9 @@ import com.android.systemui.statusbar.notification.collection.listbuilder.NotifL
import com.android.systemui.statusbar.notification.people.PeopleHubModule;
import com.android.systemui.statusbar.phone.KeyguardLiftController;
import com.android.systemui.statusbar.phone.StatusBar;
+import com.android.systemui.statusbar.phone.StatusBarComponent;
import com.android.systemui.statusbar.policy.HeadsUpManager;
+import com.android.systemui.util.concurrency.ConcurrencyModule;
import com.android.systemui.util.sensors.AsyncSensorManager;
import com.android.systemui.util.time.SystemClock;
import com.android.systemui.util.time.SystemClockImpl;
@@ -52,7 +54,9 @@ import dagger.Provides;
* implementation.
*/
@Module(includes = {AssistModule.class,
- PeopleHubModule.class})
+ ConcurrencyModule.class,
+ PeopleHubModule.class},
+ subcomponents = {StatusBarComponent.class})
public abstract class SystemUIModule {
@Binds
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIRootComponent.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIRootComponent.java
index e926574977d0..e50e0fe0d224 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIRootComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIRootComponent.java
@@ -25,7 +25,6 @@ import com.android.systemui.Dependency;
import com.android.systemui.SystemUIAppComponentFactory;
import com.android.systemui.SystemUIFactory;
import com.android.systemui.fragments.FragmentService;
-import com.android.systemui.statusbar.phone.StatusBar;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.util.InjectionInflationController;
@@ -73,12 +72,6 @@ public interface SystemUIRootComponent {
Dependency.DependencyInjector createDependency();
/**
- * Injects the StatusBar.
- */
- @Singleton
- StatusBar.StatusBarInjector getStatusBarInjector();
-
- /**
* FragmentCreator generates all Fragments that need injection.
*/
@Singleton
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/qualifiers/Background.java b/packages/SystemUI/src/com/android/systemui/dagger/qualifiers/Background.java
new file mode 100644
index 000000000000..141c9019b3e4
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/dagger/qualifiers/Background.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.dagger.qualifiers;
+
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+
+import javax.inject.Qualifier;
+
+@Qualifier
+@Documented
+@Retention(RUNTIME)
+public @interface Background {
+}
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/qualifiers/Main.java b/packages/SystemUI/src/com/android/systemui/dagger/qualifiers/Main.java
new file mode 100644
index 000000000000..7b097740ff11
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/dagger/qualifiers/Main.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.dagger.qualifiers;
+
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+
+import javax.inject.Qualifier;
+
+@Qualifier
+@Documented
+@Retention(RUNTIME)
+public @interface Main {
+}
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
index b58459470f3f..63a777154254 100644
--- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
@@ -669,7 +669,10 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener,
// Take an "interactive" bugreport.
MetricsLogger.action(mContext,
MetricsEvent.ACTION_BUGREPORT_FROM_POWER_MENU_INTERACTIVE);
- ActivityManager.getService().requestInteractiveBugReport();
+ if (!ActivityManager.getService().launchBugReportHandlerApp()) {
+ Log.w(TAG, "Bugreport handler could not be launched");
+ ActivityManager.getService().requestInteractiveBugReport();
+ }
} catch (RemoteException e) {
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/glwallpaper/ImageRevealHelper.java b/packages/SystemUI/src/com/android/systemui/glwallpaper/ImageRevealHelper.java
index 99c55f13a8a3..f815b5d476ec 100644
--- a/packages/SystemUI/src/com/android/systemui/glwallpaper/ImageRevealHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/glwallpaper/ImageRevealHelper.java
@@ -79,12 +79,6 @@ class ImageRevealHelper {
});
}
- private void animate() {
- mAnimator.cancel();
- mAnimator.setFloatValues(mReveal, mAwake ? MAX_REVEAL : MIN_REVEAL);
- mAnimator.start();
- }
-
public float getReveal() {
return mReveal;
}
@@ -93,8 +87,8 @@ class ImageRevealHelper {
if (DEBUG) {
Log.d(TAG, "updateAwake: awake=" + awake + ", duration=" + duration);
}
+ mAnimator.cancel();
mAwake = awake;
- mAnimator.setDuration(duration);
if (duration == 0) {
// We are transiting from home to aod or aod to home directly,
// we don't need to do transition in these cases.
@@ -103,7 +97,9 @@ class ImageRevealHelper {
mRevealListener.onRevealStateChanged();
mRevealListener.onRevealEnd();
} else {
- animate();
+ mAnimator.setDuration(duration);
+ mAnimator.setFloatValues(mReveal, mAwake ? MAX_REVEAL : MIN_REVEAL);
+ mAnimator.start();
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java b/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java
index 0a9100f6c7d5..f30c181b3c99 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java
@@ -25,7 +25,6 @@ import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.graphics.drawable.Drawable;
import android.os.Build;
-import android.os.Handler;
import android.provider.Settings;
import android.service.quicksettings.Tile;
import android.service.quicksettings.TileService;
@@ -34,8 +33,8 @@ import android.util.ArraySet;
import android.widget.Button;
import com.android.systemui.R;
-import com.android.systemui.dagger.qualifiers.BgHandler;
-import com.android.systemui.dagger.qualifiers.MainHandler;
+import com.android.systemui.dagger.qualifiers.Background;
+import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.plugins.qs.QSTile;
import com.android.systemui.plugins.qs.QSTile.State;
import com.android.systemui.qs.QSTileHost;
@@ -47,6 +46,7 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
+import java.util.concurrent.Executor;
import javax.inject.Inject;
@@ -55,8 +55,8 @@ public class TileQueryHelper {
private final ArrayList<TileInfo> mTiles = new ArrayList<>();
private final ArraySet<String> mSpecs = new ArraySet<>();
- private final Handler mBgHandler;
- private final Handler mMainHandler;
+ private final Executor mMainExecutor;
+ private final Executor mBgExecutor;
private final Context mContext;
private TileStateListener mListener;
@@ -64,10 +64,10 @@ public class TileQueryHelper {
@Inject
public TileQueryHelper(Context context,
- @MainHandler Handler mainHandler, @BgHandler Handler bgHandler) {
+ @Main Executor mainExecutor, @Background Executor bgExecutor) {
mContext = context;
- mMainHandler = mainHandler;
- mBgHandler = bgHandler;
+ mMainExecutor = mainExecutor;
+ mBgExecutor = bgExecutor;
}
public void setListener(TileStateListener listener) {
@@ -126,7 +126,7 @@ public class TileQueryHelper {
tilesToAdd.add(tile);
}
- mBgHandler.post(() -> {
+ mBgExecutor.execute(() -> {
for (QSTile tile : tilesToAdd) {
final QSTile.State state = tile.getState().copy();
// Ignore the current state and get the generic label instead.
@@ -139,7 +139,7 @@ public class TileQueryHelper {
}
private void addPackageTiles(final QSTileHost host) {
- mBgHandler.post(() -> {
+ mBgExecutor.execute(() -> {
Collection<QSTile> params = host.getTiles();
PackageManager pm = mContext.getPackageManager();
List<ResolveInfo> services = pm.queryIntentServicesAsUser(
@@ -185,7 +185,7 @@ public class TileQueryHelper {
private void notifyTilesChanged(final boolean finished) {
final ArrayList<TileInfo> tilesToReturn = new ArrayList<>(mTiles);
- mMainHandler.post(() -> {
+ mMainExecutor.execute(() -> {
if (mListener != null) {
mListener.onTilesChanged(tilesToReturn);
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyRecentsImpl.java b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyRecentsImpl.java
index fcdd23463c5b..f3e2f104621e 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyRecentsImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyRecentsImpl.java
@@ -162,6 +162,8 @@ public class OverviewProxyRecentsImpl implements RecentsImplementation {
if (runningTask.supportsSplitScreenMultiWindow) {
if (ActivityManagerWrapper.getInstance().setTaskWindowingModeSplitScreenPrimary(
runningTask.id, stackCreateMode, initialBounds)) {
+ mDividerOptional.ifPresent(Divider::onDockedTopTask);
+
// The overview service is handling split screen, so just skip the wait for the
// first draw and notify the divider to start animating now
mDividerOptional.ifPresent(Divider::onRecentsDrawn);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/FeatureFlags.java b/packages/SystemUI/src/com/android/systemui/statusbar/FeatureFlags.java
index 341c49a87156..2005d794c9d3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/FeatureFlags.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/FeatureFlags.java
@@ -17,14 +17,13 @@
package com.android.systemui.statusbar;
import android.annotation.NonNull;
-import android.os.Handler;
-import android.os.HandlerExecutor;
import android.provider.DeviceConfig;
import android.util.ArrayMap;
-import com.android.systemui.dagger.qualifiers.BgHandler;
+import com.android.systemui.dagger.qualifiers.Background;
import java.util.Map;
+import java.util.concurrent.Executor;
import javax.inject.Inject;
import javax.inject.Singleton;
@@ -49,10 +48,10 @@ public class FeatureFlags {
private final Map<String, Boolean> mCachedDeviceConfigFlags = new ArrayMap<>();
@Inject
- public FeatureFlags(@BgHandler Handler bgHandler) {
+ public FeatureFlags(@Background Executor executor) {
DeviceConfig.addOnPropertiesChangedListener(
"systemui",
- new HandlerExecutor(bgHandler),
+ executor,
this::onPropertiesChanged);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java
index a98f826c0284..d3a9c2c3c87d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java
@@ -62,6 +62,7 @@ import com.android.systemui.statusbar.phone.LockscreenWallpaper;
import com.android.systemui.statusbar.phone.ScrimController;
import com.android.systemui.statusbar.phone.ScrimState;
import com.android.systemui.statusbar.phone.ShadeController;
+import com.android.systemui.statusbar.phone.StatusBar;
import com.android.systemui.statusbar.phone.StatusBarWindowController;
import com.android.systemui.statusbar.policy.KeyguardStateController;
@@ -122,6 +123,7 @@ public class NotificationMediaManager implements Dumpable {
private final Context mContext;
private final MediaSessionManager mMediaSessionManager;
private final ArrayList<MediaListener> mMediaListeners;
+ private final Lazy<StatusBar> mStatusBarLazy;
private final MediaArtworkProcessor mMediaArtworkProcessor;
private final Set<AsyncTask<?, ?, ?>> mProcessArtworkTasks = new ArraySet<>();
@@ -182,6 +184,7 @@ public class NotificationMediaManager implements Dumpable {
public NotificationMediaManager(
Context context,
Lazy<ShadeController> shadeController,
+ Lazy<StatusBar> statusBarLazy,
Lazy<StatusBarWindowController> statusBarWindowController,
NotificationEntryManager notificationEntryManager,
MediaArtworkProcessor mediaArtworkProcessor,
@@ -195,6 +198,8 @@ public class NotificationMediaManager implements Dumpable {
// TODO: use MediaSessionManager.SessionListener to hook us up to future updates
// in session state
mShadeController = shadeController;
+ // TODO: use KeyguardStateController#isOccluded to remove this dependency
+ mStatusBarLazy = statusBarLazy;
mStatusBarWindowController = statusBarWindowController;
mEntryManager = notificationEntryManager;
notificationEntryManager.addNotificationEntryListener(new NotificationEntryListener() {
@@ -526,9 +531,8 @@ public class NotificationMediaManager implements Dumpable {
}
}
- ShadeController shadeController = mShadeController.get();
StatusBarWindowController windowController = mStatusBarWindowController.get();
- boolean hideBecauseOccluded = shadeController != null && shadeController.isOccluded();
+ boolean hideBecauseOccluded = mStatusBarLazy.get().isOccluded();
final boolean hasArtwork = artworkDrawable != null;
mColorExtractor.setHasMediaArtwork(hasMediaArtwork);
@@ -599,6 +603,7 @@ public class NotificationMediaManager implements Dumpable {
if (DEBUG_MEDIA) {
Log.v(TAG, "DEBUG_MEDIA: Fading out album artwork");
}
+ ShadeController shadeController = mShadeController.get();
boolean cannotAnimateDoze = shadeController != null
&& shadeController.isDozing()
&& !ScrimState.AOD.getAnimateChange();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationListController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationListController.java
index 3f7fd1a4868c..7b1dc074fcbc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationListController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationListController.java
@@ -64,6 +64,8 @@ public class NotificationListController {
}
};
+ // TODO: (b/145659174) remove after moving to NewNotifPipeline. Replaced by
+ // DeviceProvisionedCoordinator
private final DeviceProvisionedListener mDeviceProvisionedListener =
new DeviceProvisionedListener() {
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationRankingManager.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationRankingManager.kt
index 8bce528bab8c..48a4882bcf82 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationRankingManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationRankingManager.kt
@@ -16,37 +16,29 @@
package com.android.systemui.statusbar.notification.collection
-import android.app.Notification
import android.app.NotificationManager.IMPORTANCE_DEFAULT
import android.app.NotificationManager.IMPORTANCE_HIGH
import android.app.NotificationManager.IMPORTANCE_LOW
import android.app.NotificationManager.IMPORTANCE_MIN
-import android.app.Person
import android.service.notification.NotificationListenerService.Ranking
import android.service.notification.NotificationListenerService.RankingMap
import android.service.notification.StatusBarNotification
import com.android.internal.annotations.VisibleForTesting
-
import com.android.systemui.statusbar.NotificationMediaManager
import com.android.systemui.statusbar.notification.NotificationFilter
import com.android.systemui.statusbar.notification.NotificationSectionsFeatureManager
import com.android.systemui.statusbar.notification.logging.NotifEvent
import com.android.systemui.statusbar.notification.logging.NotifLog
+import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier
import com.android.systemui.statusbar.notification.stack.NotificationSectionsManager.BUCKET_ALERTING
import com.android.systemui.statusbar.notification.stack.NotificationSectionsManager.BUCKET_PEOPLE
import com.android.systemui.statusbar.notification.stack.NotificationSectionsManager.BUCKET_SILENT
import com.android.systemui.statusbar.phone.NotificationGroupManager
import com.android.systemui.statusbar.policy.HeadsUpManager
-
+import dagger.Lazy
import java.util.Objects
-import java.util.ArrayList
-
import javax.inject.Inject
-import kotlin.Comparator
-
-import dagger.Lazy
-
private const val TAG = "NotifRankingManager"
/**
@@ -64,7 +56,8 @@ open class NotificationRankingManager @Inject constructor(
private val headsUpManager: HeadsUpManager,
private val notifFilter: NotificationFilter,
private val notifLog: NotifLog,
- sectionsFeatureManager: NotificationSectionsFeatureManager
+ sectionsFeatureManager: NotificationSectionsFeatureManager,
+ private val peopleNotificationIdentifier: PeopleNotificationIdentifier
) {
var rankingMap: RankingMap? = null
@@ -79,6 +72,9 @@ open class NotificationRankingManager @Inject constructor(
val aRank = a.ranking.rank
val bRank = b.ranking.rank
+ val aIsPeople = a.isPeopleNotification()
+ val bIsPeople = b.isPeopleNotification()
+
val aMedia = isImportantMedia(a)
val bMedia = isImportantMedia(b)
@@ -88,25 +84,19 @@ open class NotificationRankingManager @Inject constructor(
val aHeadsUp = a.isRowHeadsUp
val bHeadsUp = b.isRowHeadsUp
- if (usePeopleFiltering && a.isPeopleNotification() != b.isPeopleNotification()) {
- if (a.isPeopleNotification()) -1 else 1
- } else if (aHeadsUp != bHeadsUp) {
- if (aHeadsUp) -1 else 1
- } else if (aHeadsUp) {
+ when {
+ usePeopleFiltering && aIsPeople != bIsPeople -> if (aIsPeople) -1 else 1
+ aHeadsUp != bHeadsUp -> if (aHeadsUp) -1 else 1
// Provide consistent ranking with headsUpManager
- headsUpManager.compare(a, b)
- } else if (aMedia != bMedia) {
+ aHeadsUp -> headsUpManager.compare(a, b)
// Upsort current media notification.
- if (aMedia) -1 else 1
- } else if (aSystemMax != bSystemMax) {
+ aMedia != bMedia -> if (aMedia) -1 else 1
// Upsort PRIORITY_MAX system notifications
- if (aSystemMax) -1 else 1
- } else if (a.isHighPriority != b.isHighPriority) {
- -1 * java.lang.Boolean.compare(a.isHighPriority, b.isHighPriority)
- } else if (aRank != bRank) {
- aRank - bRank
- } else {
- nb.notification.`when`.compareTo(na.notification.`when`)
+ aSystemMax != bSystemMax -> if (aSystemMax) -1 else 1
+ a.isHighPriority != b.isHighPriority ->
+ -1 * a.isHighPriority.compareTo(b.isHighPriority)
+ aRank != bRank -> aRank - bRank
+ else -> nb.notification.`when`.compareTo(na.notification.`when`)
}
}
@@ -138,10 +128,9 @@ open class NotificationRankingManager @Inject constructor(
val c = entry.channel
val n = entry.sbn.notification
- if (((n.isForegroundService && entry.ranking.importance >= IMPORTANCE_LOW) ||
- n.hasMediaSession() ||
- n.hasPerson() ||
- n.hasStyle(Notification.MessagingStyle::class.java))) {
+ if ((n.isForegroundService && entry.ranking.importance >= IMPORTANCE_LOW) ||
+ n.hasMediaSession() ||
+ entry.isPeopleNotification()) {
// Users who have long pressed and demoted to silent should not see the notification
// in the top section
if (c != null && c.hasUserSetImportance()) {
@@ -204,7 +193,7 @@ open class NotificationRankingManager @Inject constructor(
isMedia: Boolean,
isSystemMax: Boolean
) {
- if (usePeopleFiltering && entry.hasAssociatedPeople()) {
+ if (usePeopleFiltering && entry.isPeopleNotification()) {
entry.bucket = BUCKET_PEOPLE
} else if (isHeadsUp || isMedia || isSystemMax || entry.isHighPriority) {
entry.bucket = BUCKET_ALERTING
@@ -235,6 +224,11 @@ open class NotificationRankingManager @Inject constructor(
}
}
}
+
+ private fun NotificationEntry.isPeopleNotification() =
+ sbn.isPeopleNotification()
+ private fun StatusBarNotification.isPeopleNotification() =
+ peopleNotificationIdentifier.isPeopleNotification(this)
}
// Convenience functions
@@ -245,16 +239,3 @@ private fun NotificationEntry.isSystemMax(): Boolean {
private fun StatusBarNotification.isSystemNotification(): Boolean {
return "android" == packageName || "com.android.systemui" == packageName
}
-
-private fun Notification.hasPerson(): Boolean {
- val people: ArrayList<Person> =
- (extras?.getParcelableArrayList(Notification.EXTRA_PEOPLE_LIST)) ?: ArrayList()
- return people.isNotEmpty()
-}
-
-private fun Notification.hasStyle(targetStyleClass: Class<*>): Boolean {
- return targetStyleClass == notificationStyle
-}
-
-private fun NotificationEntry.isPeopleNotification(): Boolean =
- sbn.notification.hasStyle(Notification.MessagingStyle::class.java)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.java
index f5ed089b63bd..6daf3fc50b30 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.java
@@ -32,6 +32,7 @@ import android.service.notification.StatusBarNotification;
import androidx.annotation.MainThread;
import com.android.keyguard.KeyguardUpdateMonitor;
+import com.android.keyguard.KeyguardUpdateMonitorCallback;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
@@ -165,6 +166,7 @@ public class KeyguardCoordinator implements Coordinator {
private void setupInvalidateNotifListCallbacks() {
// register onKeyguardShowing callback
mKeyguardStateController.addCallback(mKeyguardCallback);
+ mKeyguardUpdateMonitor.registerCallback(mKeyguardUpdateCallback);
// register lockscreen settings changed callbacks:
final ContentObserver settingsObserver = new ContentObserver(mMainHandler) {
@@ -230,4 +232,13 @@ public class KeyguardCoordinator implements Coordinator {
invalidateListFromFilter("onStatusBarStateChanged");
}
};
+
+ private final KeyguardUpdateMonitorCallback mKeyguardUpdateCallback =
+ new KeyguardUpdateMonitorCallback() {
+ @Override
+ public void onStrongAuthStateChanged(int userId) {
+ // maybe lockdown mode changed
+ invalidateListFromFilter("onStrongAuthStateChanged");
+ }
+ };
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.java
index fdd51e9e7790..8e9a051e7d43 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.java
@@ -318,7 +318,7 @@ public class NotificationSectionsManager implements StackScrollAlgorithm.Section
}
mParent.addView(mPeopleHubView, targetIndex);
return true;
- } else if (currentHubIndex != targetIndex - 1) {
+ } else if (currentHubIndex != targetIndex) {
if (currentHubIndex < targetIndex) {
targetIndex--;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeServiceHost.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeServiceHost.java
index 063ad855343f..09ebb6468a11 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeServiceHost.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeServiceHost.java
@@ -88,10 +88,9 @@ public final class DozeServiceHost implements DozeHost {
private final PulseExpansionHandler mPulseExpansionHandler;
private final StatusBarWindowController mStatusBarWindowController;
private final NotificationWakeUpCoordinator mNotificationWakeUpCoordinator;
- private final StatusBarWindowViewController mStatusBarWindowViewController;
+ private StatusBarWindowViewController mStatusBarWindowViewController;
private final LockscreenLockIconController mLockscreenLockIconController;
private NotificationIconAreaController mNotificationIconAreaController;
- private StatusBarWindowView mStatusBarWindow;
private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
private NotificationPanelView mNotificationPanel;
private View mAmbientIndicationContainer;
@@ -112,7 +111,6 @@ public final class DozeServiceHost implements DozeHost {
PulseExpansionHandler pulseExpansionHandler,
StatusBarWindowController statusBarWindowController,
NotificationWakeUpCoordinator notificationWakeUpCoordinator,
- StatusBarWindowViewController statusBarWindowViewController,
LockscreenLockIconController lockscreenLockIconController) {
super();
mDozeLog = dozeLog;
@@ -132,7 +130,6 @@ public final class DozeServiceHost implements DozeHost {
mPulseExpansionHandler = pulseExpansionHandler;
mStatusBarWindowController = statusBarWindowController;
mNotificationWakeUpCoordinator = notificationWakeUpCoordinator;
- mStatusBarWindowViewController = statusBarWindowViewController;
mLockscreenLockIconController = lockscreenLockIconController;
}
@@ -143,14 +140,14 @@ public final class DozeServiceHost implements DozeHost {
*/
public void initialize(StatusBar statusBar,
NotificationIconAreaController notificationIconAreaController,
- StatusBarWindowView statusBarWindow,
StatusBarKeyguardViewManager statusBarKeyguardViewManager,
+ StatusBarWindowViewController statusBarWindowViewController,
NotificationPanelView notificationPanel, View ambientIndicationContainer) {
mStatusBar = statusBar;
mNotificationIconAreaController = notificationIconAreaController;
- mStatusBarWindow = statusBarWindow;
mStatusBarKeyguardViewManager = statusBarKeyguardViewManager;
mNotificationPanel = notificationPanel;
+ mStatusBarWindowViewController = statusBarWindowViewController;
mAmbientIndicationContainer = ambientIndicationContainer;
mBiometricUnlockController = mBiometricUnlockControllerLazy.get();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenWallpaper.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenWallpaper.java
index 4d6b54ccfaff..f3e9b6b3d155 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenWallpaper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenWallpaper.java
@@ -134,6 +134,7 @@ public class LockscreenWallpaper extends IWallpaperManagerCallback.Stub implemen
if (fd != null) {
try {
BitmapFactory.Options options = new BitmapFactory.Options();
+ options.inPreferredConfig = Bitmap.Config.HARDWARE;
return LoaderResult.success(BitmapFactory.decodeFileDescriptor(
fd.getFileDescriptor(), null, options));
} catch (OutOfMemoryError e) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ShadeController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ShadeController.java
index f359fe7cfec4..b31ce6afc281 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ShadeController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ShadeController.java
@@ -77,14 +77,6 @@ public interface ShadeController {
void goToKeyguard();
/**
- * When the keyguard is showing and covered by something (bouncer, keyguard activity, etc.) it
- * is occluded. This is controlled by {@link com.android.server.policy.PhoneWindowManager}
- *
- * @return whether the keyguard is currently occluded
- */
- boolean isOccluded();
-
- /**
* Notify the shade controller that the current user changed
*
* @param newUserId userId of the new user
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
index 170261e989a0..5c71a57cba77 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -237,9 +237,9 @@ import java.util.Map;
import java.util.Optional;
import javax.inject.Named;
+import javax.inject.Provider;
import dagger.Lazy;
-import dagger.Subcomponent;
public class StatusBar extends SystemUI implements DemoMode,
ActivityStarter, KeyguardStateController.Callback,
@@ -377,9 +377,10 @@ public class StatusBar extends SystemUI implements DemoMode,
private final FalsingManager mFalsingManager;
private final BroadcastDispatcher mBroadcastDispatcher;
private final ConfigurationController mConfigurationController;
- private final StatusBarWindowViewController mStatusBarWindowViewController;
+ protected StatusBarWindowViewController mStatusBarWindowViewController;
private final DozeParameters mDozeParameters;
private final Lazy<BiometricUnlockController> mBiometricUnlockControllerLazy;
+ private final Provider<StatusBarComponent.Builder> mStatusBarComponentBuilder;
private final PluginManager mPluginManager;
private final RemoteInputUriController mRemoteInputUriController;
private final Optional<Divider> mDividerOptional;
@@ -583,6 +584,8 @@ public class StatusBar extends SystemUI implements DemoMode,
}
}
+ // TODO: (b/145659174) remove when moving to NewNotifPipeline. Replaced by
+ // KeyguardCoordinator
@Override
public void onStrongAuthStateChanged(int userId) {
super.onStrongAuthStateChanged(userId);
@@ -659,7 +662,6 @@ public class StatusBar extends SystemUI implements DemoMode,
NotificationListener notificationListener,
ConfigurationController configurationController,
StatusBarWindowController statusBarWindowController,
- StatusBarWindowViewController statusBarWindowViewController,
LockscreenLockIconController lockscreenLockIconController,
DozeParameters dozeParameters,
ScrimController scrimController,
@@ -673,6 +675,7 @@ public class StatusBar extends SystemUI implements DemoMode,
VolumeComponent volumeComponent,
CommandQueue commandQueue,
Optional<Recents> recentsOptional,
+ Provider<StatusBarComponent.Builder> statusBarComponentBuilder,
PluginManager pluginManager,
RemoteInputUriController remoteInputUriController,
Optional<Divider> dividerOptional,
@@ -732,7 +735,6 @@ public class StatusBar extends SystemUI implements DemoMode,
mNotificationListener = notificationListener;
mConfigurationController = configurationController;
mStatusBarWindowController = statusBarWindowController;
- mStatusBarWindowViewController = statusBarWindowViewController;
mLockscreenLockIconController = lockscreenLockIconController;
mDozeServiceHost = dozeServiceHost;
mPowerManager = powerManager;
@@ -746,6 +748,7 @@ public class StatusBar extends SystemUI implements DemoMode,
mVolumeComponent = volumeComponent;
mCommandQueue = commandQueue;
mRecentsOptional = recentsOptional;
+ mStatusBarComponentBuilder = statusBarComponentBuilder;
mPluginManager = pluginManager;
mRemoteInputUriController = remoteInputUriController;
mDividerOptional = dividerOptional;
@@ -895,7 +898,8 @@ public class StatusBar extends SystemUI implements DemoMode,
mKeyguardUpdateMonitor.registerCallback(mUpdateCallback);
mDozeServiceHost.initialize(this, mNotificationIconAreaController,
- mStatusBarWindow, mStatusBarKeyguardViewManager,
+ mStatusBarKeyguardViewManager,
+ mStatusBarWindowViewController,
mNotificationPanel, mAmbientIndicationContainer);
Dependency.get(ActivityStarterDelegate.class).setActivityStarterImpl(this);
@@ -962,7 +966,7 @@ public class StatusBar extends SystemUI implements DemoMode,
updateResources();
updateTheme();
- inflateStatusBarWindow(context);
+ inflateStatusBarWindow();
mStatusBarWindowViewController.setService(this);
mStatusBarWindow.setOnTouchListener(getStatusBarWindowTouchListener());
@@ -1233,7 +1237,8 @@ public class StatusBar extends SystemUI implements DemoMode,
mPresenter = new StatusBarNotificationPresenter(mContext, mNotificationPanel,
mHeadsUpManager, mStatusBarWindow, mStackScroller, mDozeScrimController,
mScrimController, mActivityLaunchAnimator, mDynamicPrivacyController,
- mNotificationAlertingManager, rowBinder, mKeyguardStateController, mCommandQueue);
+ mNotificationAlertingManager, rowBinder, mKeyguardStateController,
+ this /* statusBar */, mCommandQueue);
mNotificationListController =
new NotificationListController(
@@ -1246,7 +1251,7 @@ public class StatusBar extends SystemUI implements DemoMode,
mNotificationActivityStarter =
mStatusBarNotificationActivityStarterBuilder
- .setShadeController(this)
+ .setStatusBar(this)
.setActivityLaunchAnimator(mActivityLaunchAnimator)
.setNotificationPresenter(mPresenter)
.build();
@@ -1380,8 +1385,11 @@ public class StatusBar extends SystemUI implements DemoMode,
mNotificationPanel);
}
- protected void inflateStatusBarWindow(Context context) {
+ private void inflateStatusBarWindow() {
mStatusBarWindow = mSuperStatusBarViewFactory.getStatusBarWindowView();
+ StatusBarComponent statusBarComponent = mStatusBarComponentBuilder.get()
+ .statusBarWindowView(mStatusBarWindow).build();
+ mStatusBarWindowViewController = statusBarComponent.getStatusBarWindowViewController();
mStatusBarWindowViewController.setupExpandedStatusBar();
}
@@ -1751,7 +1759,12 @@ public class StatusBar extends SystemUI implements DemoMode,
return mAmbientIndicationContainer;
}
- @Override
+ /**
+ * When the keyguard is showing and covered by a "showWhenLocked" activity it
+ * is occluded. This is controlled by {@link com.android.server.policy.PhoneWindowManager}
+ *
+ * @return whether the keyguard is currently occluded
+ */
public boolean isOccluded() {
return mIsOccluded;
}
@@ -4391,11 +4404,6 @@ public class StatusBar extends SystemUI implements DemoMode,
return mGutsManager;
}
- @Subcomponent
- public interface StatusBarInjector {
- void createStatusBar(StatusBar statusbar);
- }
-
boolean isTransientShown() {
return mTransientShown;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarComponent.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarComponent.java
new file mode 100644
index 000000000000..f3c843c6d62d
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarComponent.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.phone;
+
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+
+import javax.inject.Scope;
+
+import dagger.BindsInstance;
+import dagger.Subcomponent;
+
+/**
+ * Dagger subcomponent tied to the lifecycle of StatusBar views.
+ */
+@Subcomponent
+public interface StatusBarComponent {
+ /**
+ * Builder for {@link StatusBarComponent}.
+ */
+ @Subcomponent.Builder
+ interface Builder {
+ @BindsInstance Builder statusBarWindowView(StatusBarWindowView statusBarWindowView);
+ StatusBarComponent build();
+ }
+
+ /**
+ * Scope annotation for singleton items within the StatusBarComponent.
+ */
+ @Documented
+ @Retention(RUNTIME)
+ @Scope
+ @interface StatusBarScope {}
+
+ /**
+ * Creates a StatusBarWindowViewController.
+ */
+ @StatusBarScope
+ StatusBarWindowViewController getStatusBarWindowViewController();
+
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarModule.java
index 5d69409d1d4c..312c85f01275 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarModule.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarModule.java
@@ -77,6 +77,7 @@ import com.android.systemui.volume.VolumeComponent;
import java.util.Optional;
import javax.inject.Named;
+import javax.inject.Provider;
import javax.inject.Singleton;
import dagger.Lazy;
@@ -143,7 +144,6 @@ public class StatusBarModule {
NotificationListener notificationListener,
ConfigurationController configurationController,
StatusBarWindowController statusBarWindowController,
- StatusBarWindowViewController statusBarWindowViewController,
LockscreenLockIconController lockscreenLockIconController,
DozeParameters dozeParameters,
ScrimController scrimController,
@@ -157,6 +157,7 @@ public class StatusBarModule {
VolumeComponent volumeComponent,
CommandQueue commandQueue,
Optional<Recents> recentsOptional,
+ Provider<StatusBarComponent.Builder> statusBarComponentBuilder,
PluginManager pluginManager,
RemoteInputUriController remoteInputUriController,
Optional<Divider> dividerOptional,
@@ -217,7 +218,6 @@ public class StatusBarModule {
notificationListener,
configurationController,
statusBarWindowController,
- statusBarWindowViewController,
lockscreenLockIconController,
dozeParameters,
scrimController,
@@ -231,6 +231,7 @@ public class StatusBarModule {
volumeComponent,
commandQueue,
recentsOptional,
+ statusBarComponentBuilder,
pluginManager,
remoteInputUriController,
dividerOptional,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java
index 863874e788c6..e2832587e2ea 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java
@@ -93,6 +93,7 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit
private final NotificationRemoteInputManager mRemoteInputManager;
private final NotificationLockscreenUserManager mLockscreenUserManager;
private final ShadeController mShadeController;
+ private final StatusBar mStatusBar;
private final KeyguardStateController mKeyguardStateController;
private final ActivityStarter mActivityStarter;
private final NotificationEntryManager mEntryManager;
@@ -125,7 +126,8 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit
IDreamManager dreamManager, NotificationRemoteInputManager remoteInputManager,
StatusBarRemoteInputCallback remoteInputCallback, NotificationGroupManager groupManager,
NotificationLockscreenUserManager lockscreenUserManager,
- ShadeController shadeController, KeyguardStateController keyguardStateController,
+ ShadeController shadeController, StatusBar statusBar,
+ KeyguardStateController keyguardStateController,
NotificationInterruptionStateProvider notificationInterruptionStateProvider,
MetricsLogger metricsLogger, LockPatternUtils lockPatternUtils,
Handler mainThreadHandler, Handler backgroundHandler,
@@ -142,6 +144,8 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit
mRemoteInputManager = remoteInputManager;
mLockscreenUserManager = lockscreenUserManager;
mShadeController = shadeController;
+ // TODO: use KeyguardStateController#isOccluded to remove this dependency
+ mStatusBar = statusBar;
mKeyguardStateController = keyguardStateController;
mActivityStarter = activityStarter;
mEntryManager = entryManager;
@@ -198,7 +202,7 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit
final boolean afterKeyguardGone = isActivityIntent
&& mActivityIntentHelper.wouldLaunchResolverActivity(intent.getIntent(),
mLockscreenUserManager.getCurrentUserId());
- final boolean wasOccluded = mShadeController.isOccluded();
+ final boolean wasOccluded = mStatusBar.isOccluded();
boolean showOverLockscreen = mKeyguardStateController.isShowing() && intent != null
&& mActivityIntentHelper.wouldShowOverLockscreen(intent.getIntent(),
mLockscreenUserManager.getCurrentUserId());
@@ -253,7 +257,7 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit
mShadeController.addPostCollapseAction(runnable);
mShadeController.collapsePanel(true /* animate */);
} else if (mKeyguardStateController.isShowing()
- && mShadeController.isOccluded()) {
+ && mStatusBar.isOccluded()) {
mShadeController.addAfterKeyguardGoneRunnable(runnable);
mShadeController.collapsePanel();
} else {
@@ -384,7 +388,7 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit
.addNextIntentWithParentStack(intent)
.startActivities(getActivityOptions(
mActivityLaunchAnimator.getLaunchAnimation(
- row, mShadeController.isOccluded())),
+ row, mStatusBar.isOccluded())),
new UserHandle(UserHandle.getUserId(appUid)));
mActivityLaunchAnimator.setLaunchResult(launchResult, true /* isActivityIntent */);
if (shouldCollapse()) {
@@ -518,6 +522,7 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit
private ShadeController mShadeController;
private NotificationPresenter mNotificationPresenter;
private ActivityLaunchAnimator mActivityLaunchAnimator;
+ private StatusBar mStatusBar;
@Inject
public Builder(Context context,
@@ -567,8 +572,11 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit
mBubbleController = bubbleController;
mSuperStatusBarViewFactory = superStatusBarViewFactory;
}
- public Builder setShadeController(ShadeController shadeController) {
- mShadeController = shadeController;
+
+ /** Sets the status bar to use as {@link StatusBar} and {@link ShadeController}. */
+ public Builder setStatusBar(StatusBar statusBar) {
+ mStatusBar = statusBar;
+ mShadeController = statusBar;
return this;
}
@@ -600,6 +608,7 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit
mGroupManager,
mLockscreenUserManager,
mShadeController,
+ mStatusBar,
mKeyguardStateController,
mNotificationInterruptionStateProvider,
mMetricsLogger,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java
index 30e26e57e435..6650cf6a5af6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java
@@ -113,6 +113,7 @@ public class StatusBarNotificationPresenter implements NotificationPresenter,
private final DozeScrimController mDozeScrimController;
private final ScrimController mScrimController;
private final Context mContext;
+ private final StatusBar mStatusBar;
private final CommandQueue mCommandQueue;
private final AccessibilityManager mAccessibilityManager;
@@ -140,12 +141,15 @@ public class StatusBarNotificationPresenter implements NotificationPresenter,
NotificationAlertingManager notificationAlertingManager,
NotificationRowBinderImpl notificationRowBinder,
KeyguardStateController keyguardStateController,
+ StatusBar statusBar,
CommandQueue commandQueue) {
mContext = context;
mKeyguardStateController = keyguardStateController;
mNotificationPanel = panel;
mHeadsUpManager = headsUp;
mDynamicPrivacyController = dynamicPrivacyController;
+ // TODO: use KeyguardStateController#isOccluded to remove this dependency
+ mStatusBar = statusBar;
mCommandQueue = commandQueue;
mAboveShelfObserver = new AboveShelfObserver(stackScroller);
mActivityLaunchAnimator = activityLaunchAnimator;
@@ -330,7 +334,7 @@ public class StatusBarNotificationPresenter implements NotificationPresenter,
}
public boolean canHeadsUp(NotificationEntry entry, StatusBarNotification sbn) {
- if (mShadeController.isOccluded()) {
+ if (mStatusBar.isOccluded()) {
boolean devicePublic = mLockscreenUserManager.
isLockscreenPublicMode(mLockscreenUserManager.getCurrentUserId());
boolean userPublic = devicePublic
@@ -356,7 +360,7 @@ public class StatusBarNotificationPresenter implements NotificationPresenter,
} else {
// we only allow head-up on the lockscreen if it doesn't have a fullscreen intent
return !mKeyguardStateController.isShowing()
- || mShadeController.isOccluded();
+ || mStatusBar.isOccluded();
}
}
return true;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowViewController.java
index feac5da38138..3935df02fd91 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowViewController.java
@@ -43,7 +43,6 @@ import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.DragDownHelper;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
import com.android.systemui.statusbar.PulseExpansionHandler;
-import com.android.systemui.statusbar.SuperStatusBarViewFactory;
import com.android.systemui.statusbar.SysuiStatusBarStateController;
import com.android.systemui.statusbar.notification.DynamicPrivacyController;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
@@ -57,14 +56,13 @@ import java.io.FileDescriptor;
import java.io.PrintWriter;
import javax.inject.Inject;
-import javax.inject.Singleton;
import dagger.Lazy;
/**
* Controller for {@link StatusBarWindowView}.
*/
-@Singleton
+//@Singleton
public class StatusBarWindowViewController {
private final InjectionInflationController mInjectionInflationController;
private final NotificationWakeUpCoordinator mCoordinator;
@@ -116,9 +114,9 @@ public class StatusBarWindowViewController {
DozeLog dozeLog,
DozeParameters dozeParameters,
CommandQueue commandQueue,
- SuperStatusBarViewFactory superStatusBarViewFactory,
Lazy<ShadeController> shadeControllerLazy,
- DockManager dockManager) {
+ DockManager dockManager,
+ StatusBarWindowView statusBarWindowView) {
mInjectionInflationController = injectionInflationController;
mCoordinator = coordinator;
mPulseExpansionHandler = pulseExpansionHandler;
@@ -134,7 +132,7 @@ public class StatusBarWindowViewController {
mDozeLog = dozeLog;
mDozeParameters = dozeParameters;
mCommandQueue = commandQueue;
- mView = superStatusBarViewFactory.getStatusBarWindowView();
+ mView = statusBarWindowView;
mShadeControllerLazy = shadeControllerLazy;
mDockManager = dockManager;
diff --git a/packages/SystemUI/src/com/android/systemui/util/concurrency/ConcurrencyModule.java b/packages/SystemUI/src/com/android/systemui/util/concurrency/ConcurrencyModule.java
new file mode 100644
index 000000000000..24f49ff99879
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/util/concurrency/ConcurrencyModule.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.util.concurrency;
+
+import android.content.Context;
+import android.os.Handler;
+
+import com.android.systemui.dagger.qualifiers.Background;
+import com.android.systemui.dagger.qualifiers.BgHandler;
+import com.android.systemui.dagger.qualifiers.Main;
+import com.android.systemui.dagger.qualifiers.MainHandler;
+
+import java.util.concurrent.Executor;
+
+import dagger.Module;
+import dagger.Provides;
+
+/**
+ * Dagger Module for classes found within the concurrent package.
+ */
+@Module
+public abstract class ConcurrencyModule {
+ /**
+ * Provide a Background-Thread Executor by default.
+ */
+ @Provides
+ public static Executor provideExecutor(@BgHandler Handler handler) {
+ return new ExecutorImpl(handler);
+ }
+
+ /**
+ * Provide a Background-Thread Executor.
+ */
+ @Provides
+ @Background
+ public static Executor provideBackgroundExecutor(@BgHandler Handler handler) {
+ return new ExecutorImpl(handler);
+ }
+
+ /**
+ * Provide a Main-Thread Executor.
+ */
+ @Provides
+ @Main
+ public static Executor provideMainExecutor(Context context) {
+ return context.getMainExecutor();
+ }
+
+ /**
+ * Provide a Background-Thread Executor by default.
+ */
+ @Provides
+ public static DelayableExecutor provideDelayableExecutor(@BgHandler Handler handler) {
+ return new ExecutorImpl(handler);
+ }
+
+ /**
+ * Provide a Background-Thread Executor.
+ */
+ @Provides
+ @Background
+ public static DelayableExecutor provideBackgroundDelayableExecutor(@BgHandler Handler handler) {
+ return new ExecutorImpl(handler);
+ }
+
+ /**
+ * Provide a Main-Thread Executor.
+ */
+ @Provides
+ @Main
+ public static DelayableExecutor provideMainDelayableExecutor(@MainHandler Handler handler) {
+ return new ExecutorImpl(handler);
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/util/concurrency/DelayableExecutor.java b/packages/SystemUI/src/com/android/systemui/util/concurrency/DelayableExecutor.java
new file mode 100644
index 000000000000..2d6c4a62047d
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/util/concurrency/DelayableExecutor.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.util.concurrency;
+
+import java.util.concurrent.Executor;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * A sub-class of {@link Executor} that allows Runnables to be delayed and/or cancelled.
+ */
+public interface DelayableExecutor extends Executor {
+ /**
+ * Execute supplied Runnable on the Executors thread after a specified delay.
+ *
+ * See {@link android.os.Handler#postDelayed(Runnable, long)}.
+ *
+ * @return A Runnable that, when run, removes the supplied argument from the Executor queue.
+ */
+ default Runnable executeDelayed(Runnable r, long delayMillis) {
+ return executeDelayed(r, delayMillis, TimeUnit.MILLISECONDS);
+ }
+
+ /**
+ * Execute supplied Runnable on the Executors thread after a specified delay.
+ *
+ * See {@link android.os.Handler#postDelayed(Runnable, long)}.
+ *
+ * @return A Runnable that, when run, removes the supplied argument from the Executor queue..
+ */
+ Runnable executeDelayed(Runnable r, long delay, TimeUnit unit);
+
+ /**
+ * Execute supplied Runnable on the Executors thread at a specified uptime.
+ *
+ * See {@link android.os.Handler#postAtTime(Runnable, long)}.
+ *
+ * @return A Runnable that, when run, removes the supplied argument from the Executor queue.
+ */
+ default Runnable executeAtTime(Runnable r, long uptime) {
+ return executeAtTime(r, uptime, TimeUnit.MILLISECONDS);
+ }
+
+ /**
+ * Execute supplied Runnable on the Executors thread at a specified uptime.
+ *
+ * See {@link android.os.Handler#postAtTime(Runnable, long)}.
+ *
+ * @return A Runnable that, when run, removes the supplied argument from the Executor queue.
+ */
+ Runnable executeAtTime(Runnable r, long uptimeMillis, TimeUnit unit);
+
+ /**
+ * Remove all pending Runnables.
+ *
+ */
+ void removeAll();
+
+}
diff --git a/packages/SystemUI/src/com/android/systemui/util/concurrency/ExecutorImpl.java b/packages/SystemUI/src/com/android/systemui/util/concurrency/ExecutorImpl.java
new file mode 100644
index 000000000000..2a99de3ac5ad
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/util/concurrency/ExecutorImpl.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.util.concurrency;
+
+import android.os.Handler;
+import android.os.HandlerExecutor;
+import android.os.Message;
+
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Implementations of {@link DelayableExecutor} for SystemUI.
+ */
+public class ExecutorImpl extends HandlerExecutor implements DelayableExecutor {
+ private final Handler mHandler;
+
+ public ExecutorImpl(Handler handler) {
+ super(handler);
+ mHandler = handler;
+ }
+
+ @Override
+ public Runnable executeDelayed(Runnable r, long delay, TimeUnit unit) {
+ Object token = new Object();
+ Message m = mHandler.obtainMessage(0, token);
+ mHandler.sendMessageDelayed(m, unit.toMillis(delay));
+
+ return () -> mHandler.removeCallbacksAndMessages(token);
+ }
+
+ @Override
+ public Runnable executeAtTime(Runnable r, long uptimeMillis, TimeUnit unit) {
+ Object token = new Object();
+ Message m = mHandler.obtainMessage(0, token);
+ mHandler.sendMessageAtTime(m, unit.toMillis(uptimeMillis));
+
+ return () -> mHandler.removeCallbacksAndMessages(token);
+ }
+
+ @Override
+ public void removeAll() {
+ mHandler.removeCallbacksAndMessages(null);
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/customize/TileQueryHelperTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/customize/TileQueryHelperTest.java
index b41512c9a935..39ce8c1209ac 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/customize/TileQueryHelperTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/customize/TileQueryHelperTest.java
@@ -36,13 +36,9 @@ import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
-import android.os.Handler;
-import android.os.Looper;
import android.provider.Settings;
import android.service.quicksettings.Tile;
import android.testing.AndroidTestingRunner;
-import android.testing.TestableLooper;
-import android.testing.TestableLooper.RunWithLooper;
import android.text.TextUtils;
import android.util.ArraySet;
@@ -52,6 +48,8 @@ import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.plugins.qs.QSTile;
import com.android.systemui.qs.QSTileHost;
+import com.android.systemui.util.concurrency.FakeExecutor;
+import com.android.systemui.util.time.FakeSystemClock;
import org.junit.Before;
import org.junit.Test;
@@ -69,7 +67,6 @@ import java.util.Set;
@SmallTest
@RunWith(AndroidTestingRunner.class)
-@RunWithLooper
public class TileQueryHelperTest extends SysuiTestCase {
private static final String CURRENT_TILES = "wifi,dnd,nfc";
private static final String ONLY_STOCK_TILES = "wifi,dnd";
@@ -98,14 +95,13 @@ public class TileQueryHelperTest extends SysuiTestCase {
private ArgumentCaptor<List<TileQueryHelper.TileInfo>> mCaptor;
private QSTile.State mState;
- private TestableLooper mBGLooper;
private TileQueryHelper mTileQueryHelper;
- private Handler mMainHandler;
+ private FakeExecutor mMainExecutor;
+ private FakeExecutor mBgExecutor;
@Before
public void setup() {
MockitoAnnotations.initMocks(this);
- mBGLooper = TestableLooper.get(this);
mContext.setMockPackageManager(mPackageManager);
mState = new QSTile.State();
@@ -123,9 +119,11 @@ public class TileQueryHelperTest extends SysuiTestCase {
}
).when(mQSTileHost).createTile(anyString());
- mMainHandler = new Handler(Looper.getMainLooper());
- mTileQueryHelper = new TileQueryHelper(mContext, mMainHandler,
- new Handler(mBGLooper.getLooper()));
+ FakeSystemClock clock = new FakeSystemClock();
+ clock.setAutoIncrement(false);
+ mMainExecutor = new FakeExecutor(clock);
+ mBgExecutor = new FakeExecutor(clock);
+ mTileQueryHelper = new TileQueryHelper(mContext, mMainExecutor, mBgExecutor);
mTileQueryHelper.setListener(mListener);
}
@@ -138,8 +136,7 @@ public class TileQueryHelperTest extends SysuiTestCase {
public void testIsFinished_trueAfterQuerying() {
mTileQueryHelper.queryTiles(mQSTileHost);
- mBGLooper.processAllMessages();
- waitForIdleSync(mMainHandler);
+ FakeExecutor.exhaustExecutors(mMainExecutor, mBgExecutor);
assertTrue(mTileQueryHelper.isFinished());
}
@@ -148,8 +145,7 @@ public class TileQueryHelperTest extends SysuiTestCase {
public void testQueryTiles_callsListenerTwice() {
mTileQueryHelper.queryTiles(mQSTileHost);
- mBGLooper.processAllMessages();
- waitForIdleSync(mMainHandler);
+ FakeExecutor.exhaustExecutors(mMainExecutor, mBgExecutor);
verify(mListener, times(2)).onTilesChanged(any());
}
@@ -163,8 +159,7 @@ public class TileQueryHelperTest extends SysuiTestCase {
mTileQueryHelper.queryTiles(mQSTileHost);
- mBGLooper.processAllMessages();
- waitForIdleSync(mMainHandler);
+ FakeExecutor.exhaustExecutors(mMainExecutor, mBgExecutor);
assertTrue(mTileQueryHelper.isFinished());
}
@@ -178,8 +173,7 @@ public class TileQueryHelperTest extends SysuiTestCase {
mTileQueryHelper.queryTiles(mQSTileHost);
- mBGLooper.processAllMessages();
- waitForIdleSync(mMainHandler);
+ FakeExecutor.exhaustExecutors(mMainExecutor, mBgExecutor);
verify(mListener, atLeastOnce()).onTilesChanged(mCaptor.capture());
List<String> specs = new ArrayList<>();
@@ -199,8 +193,7 @@ public class TileQueryHelperTest extends SysuiTestCase {
mTileQueryHelper.queryTiles(mQSTileHost);
- mBGLooper.processAllMessages();
- waitForIdleSync(mMainHandler);
+ FakeExecutor.exhaustExecutors(mMainExecutor, mBgExecutor);
verify(mListener, atLeastOnce()).onTilesChanged(mCaptor.capture());
List<String> specs = new ArrayList<>();
@@ -220,8 +213,7 @@ public class TileQueryHelperTest extends SysuiTestCase {
mTileQueryHelper.queryTiles(mQSTileHost);
- mBGLooper.processAllMessages();
- waitForIdleSync(mMainHandler);
+ FakeExecutor.exhaustExecutors(mMainExecutor, mBgExecutor);
verify(mListener, atLeastOnce()).onTilesChanged(mCaptor.capture());
List<String> specs = new ArrayList<>();
@@ -251,8 +243,7 @@ public class TileQueryHelperTest extends SysuiTestCase {
"");
mTileQueryHelper.queryTiles(mQSTileHost);
- mBGLooper.processAllMessages();
- waitForIdleSync(mMainHandler);
+ FakeExecutor.exhaustExecutors(mMainExecutor, mBgExecutor);
verify(mListener, atLeastOnce()).onTilesChanged(mCaptor.capture());
List<TileQueryHelper.TileInfo> tileInfos = mCaptor.getValue();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java
index a98945f49b99..e0dfe7e66ad5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java
@@ -85,6 +85,7 @@ import com.android.systemui.statusbar.notification.collection.NotificationRowBin
import com.android.systemui.statusbar.notification.collection.NotificationRowBinderImpl;
import com.android.systemui.statusbar.notification.logging.NotifLog;
import com.android.systemui.statusbar.notification.logging.NotificationLogger;
+import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
import com.android.systemui.statusbar.notification.row.RowInflaterTask;
@@ -228,7 +229,8 @@ public class NotificationEntryManagerTest extends SysuiTestCase {
mHeadsUpManager,
mock(NotificationFilter.class),
mNotifLog,
- mock(NotificationSectionsFeatureManager.class)),
+ mock(NotificationSectionsFeatureManager.class),
+ mock(PeopleNotificationIdentifier.class)),
mEnvironment
);
Dependency.get(InitController.class).executePostInitTasks();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationRankingManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationRankingManagerTest.kt
index 01b2f8932d9b..cda1538e899d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationRankingManagerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationRankingManagerTest.kt
@@ -20,7 +20,6 @@ import android.app.Notification
import android.app.NotificationChannel
import android.app.NotificationManager.IMPORTANCE_DEFAULT
import android.app.NotificationManager.IMPORTANCE_LOW
-import android.app.Person
import android.service.notification.NotificationListenerService.RankingMap
import android.service.notification.StatusBarNotification
import android.testing.AndroidTestingRunner
@@ -36,6 +35,7 @@ import com.android.systemui.statusbar.NotificationMediaManager
import com.android.systemui.statusbar.notification.NotificationFilter
import com.android.systemui.statusbar.notification.NotificationSectionsFeatureManager
import com.android.systemui.statusbar.notification.logging.NotifLog
+import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier
import com.android.systemui.statusbar.notification.stack.NotificationSectionsManager.BUCKET_ALERTING
import com.android.systemui.statusbar.notification.stack.NotificationSectionsManager.BUCKET_SILENT
import com.android.systemui.statusbar.phone.NotificationGroupManager
@@ -52,62 +52,41 @@ import org.mockito.Mockito.mock
@SmallTest
@RunWith(AndroidTestingRunner::class)
-class NotificationRankingManagerTest
- : SysuiTestCase() {
+class NotificationRankingManagerTest : SysuiTestCase() {
- private var lazyMedia: Lazy<NotificationMediaManager> = Lazy {
- mock<NotificationMediaManager>(NotificationMediaManager::class.java)
+ private val lazyMedia: Lazy<NotificationMediaManager> = Lazy {
+ mock(NotificationMediaManager::class.java)
}
-
- private val rankingManager = TestableNotificationRankingManager(
- lazyMedia,
- mock<NotificationGroupManager>(NotificationGroupManager::class.java),
- mock<HeadsUpManager>(HeadsUpManager::class.java),
- mock<NotificationFilter>(NotificationFilter::class.java),
- mock<NotifLog>(NotifLog::class.java),
- mock<NotificationSectionsFeatureManager>(NotificationSectionsFeatureManager::class.java)
- )
+ private lateinit var personNotificationIdentifier: PeopleNotificationIdentifier
+ private lateinit var rankingManager: TestableNotificationRankingManager
@Before
fun setup() {
+ personNotificationIdentifier =
+ mock(PeopleNotificationIdentifier::class.java)
+ rankingManager = TestableNotificationRankingManager(
+ lazyMedia,
+ mock(NotificationGroupManager::class.java),
+ mock(HeadsUpManager::class.java),
+ mock(NotificationFilter::class.java),
+ mock(NotifLog::class.java),
+ mock(NotificationSectionsFeatureManager::class.java),
+ personNotificationIdentifier
+ )
}
@Test
fun testPeopleNotification_isHighPriority() {
- val person = Person.Builder()
- .setName("name")
- .setKey("abc")
- .setUri("uri")
- .setBot(true)
- .build()
-
val notification = Notification.Builder(mContext, "test")
- .addPerson(person)
.build()
val sbn = StatusBarNotification("pkg", "pkg", 0, "tag", 0, 0,
notification, mContext.user, "", 0)
- val e = NotificationEntryBuilder()
- .setNotification(notification)
- .setSbn(sbn)
- .build()
-
- assertTrue(rankingManager.isHighPriority2(e))
- }
-
- @Test
- fun messagingStyleHighPriority() {
-
- val notif = Notification.Builder(mContext, "test")
- .setStyle(Notification.MessagingStyle(""))
- .build()
-
- val sbn = StatusBarNotification("pkg", "pkg", 0, "tag", 0, 0,
- notif, mContext.getUser(), "", 0)
+ `when`(personNotificationIdentifier.isPeopleNotification(sbn)).thenReturn(true)
val e = NotificationEntryBuilder()
- .setNotification(notif)
+ .setNotification(notification)
.setSbn(sbn)
.build()
@@ -117,7 +96,7 @@ class NotificationRankingManagerTest
@Test
fun lowForegroundHighPriority() {
val notification = mock(Notification::class.java)
- `when`<Boolean>(notification.isForegroundService).thenReturn(true)
+ `when`(notification.isForegroundService).thenReturn(true)
val sbn = StatusBarNotification("pkg", "pkg", 0, "tag", 0, 0,
notification, mContext.user, "", 0)
@@ -136,15 +115,7 @@ class NotificationRankingManagerTest
@Test
fun userChangeTrumpsHighPriorityCharacteristics() {
- val person = Person.Builder()
- .setName("name")
- .setKey("abc")
- .setUri("uri")
- .setBot(true)
- .build()
-
val notification = Notification.Builder(mContext, "test")
- .addPerson(person)
.setStyle(Notification.MessagingStyle(""))
.setFlag(Notification.FLAG_FOREGROUND_SERVICE, true)
.build()
@@ -152,6 +123,8 @@ class NotificationRankingManagerTest
val sbn = StatusBarNotification("pkg", "pkg", 0, "tag", 0, 0,
notification, mContext.user, "", 0)
+ `when`(personNotificationIdentifier.isPeopleNotification(sbn)).thenReturn(true)
+
val channel = NotificationChannel("a", "a", IMPORTANCE_LOW)
channel.lockFields(NotificationChannel.USER_LOCKED_IMPORTANCE)
@@ -297,14 +270,16 @@ class NotificationRankingManagerTest
headsUpManager: HeadsUpManager,
filter: NotificationFilter,
notifLog: NotifLog,
- sectionsFeatureManager: NotificationSectionsFeatureManager
+ sectionsFeatureManager: NotificationSectionsFeatureManager,
+ peopleNotificationIdentifier: PeopleNotificationIdentifier
) : NotificationRankingManager(
mediaManager,
groupManager,
headsUpManager,
filter,
notifLog,
- sectionsFeatureManager
+ sectionsFeatureManager,
+ peopleNotificationIdentifier
) {
fun isHighPriority2(e: NotificationEntry): Boolean {
@@ -315,4 +290,4 @@ class NotificationRankingManagerTest
rankingMap = r
}
}
-} \ No newline at end of file
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
index d20a37a18d2e..d2b4a20ca3a9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
@@ -74,6 +74,7 @@ import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.NotificationRankingManager;
import com.android.systemui.statusbar.notification.logging.NotifLog;
import com.android.systemui.statusbar.notification.people.PeopleHubSectionFooterViewAdapter;
+import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.row.FooterView;
import com.android.systemui.statusbar.notification.row.NotificationBlockingHelperManager;
@@ -164,7 +165,8 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase {
mHeadsUpManager,
mock(NotificationFilter.class),
mock(NotifLog.class),
- mock(NotificationSectionsFeatureManager.class)
+ mock(NotificationSectionsFeatureManager.class),
+ mock(PeopleNotificationIdentifier.class)
),
mock(NotificationEntryManager.KeyguardEnvironment.class));
mDependency.injectTestDependency(NotificationEntryManager.class, mEntryManager);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeServiceHostTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeServiceHostTest.java
index 222fcb696c8b..46f6cfe39e3c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeServiceHostTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeServiceHostTest.java
@@ -85,7 +85,6 @@ public class DozeServiceHostTest extends SysuiTestCase {
@Mock private StatusBar mStatusBar;
@Mock private NotificationIconAreaController mNotificationIconAreaController;
@Mock private StatusBarWindowViewController mStatusBarWindowViewController;
- @Mock private StatusBarWindowView mStatusBarWindow;
@Mock private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
@Mock private NotificationPanelView mNotificationPanel;
@Mock private View mAmbientIndicationContainer;
@@ -101,10 +100,11 @@ public class DozeServiceHostTest extends SysuiTestCase {
mKeyguardViewMediator, () -> mAssistManager, mDozeScrimController,
mKeyguardUpdateMonitor, mVisualStabilityManager, mPulseExpansionHandler,
mStatusBarWindowController, mNotificationWakeUpCoordinator,
- mStatusBarWindowViewController, mLockscreenLockIconController);
+ mLockscreenLockIconController);
- mDozeServiceHost.initialize(mStatusBar, mNotificationIconAreaController, mStatusBarWindow,
- mStatusBarKeyguardViewManager, mNotificationPanel, mAmbientIndicationContainer);
+ mDozeServiceHost.initialize(mStatusBar, mNotificationIconAreaController,
+ mStatusBarKeyguardViewManager, mStatusBarWindowViewController, mNotificationPanel,
+ mAmbientIndicationContainer);
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java
index 6f5cfbecb5d0..77cdc025bbc9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java
@@ -102,7 +102,7 @@ public class StatusBarNotificationActivityStarterTest extends SysuiTestCase {
@Mock
private RemoteInputController mRemoteInputController;
@Mock
- private ShadeController mShadeController;
+ private StatusBar mStatusBar;
@Mock
private KeyguardStateController mKeyguardStateController;
@Mock
@@ -175,7 +175,7 @@ public class StatusBarNotificationActivityStarterTest extends SysuiTestCase {
mock(NotificationInterruptionStateProvider.class), mock(MetricsLogger.class),
mock(LockPatternUtils.class), mHandler, mHandler, mActivityIntentHelper,
mBubbleController, mSuperStatusBarViewFactory))
- .setShadeController(mShadeController)
+ .setStatusBar(mStatusBar)
.setNotificationPresenter(mock(NotificationPresenter.class))
.setActivityLaunchAnimator(mock(ActivityLaunchAnimator.class))
.build();
@@ -186,11 +186,11 @@ public class StatusBarNotificationActivityStarterTest extends SysuiTestCase {
// set up addAfterKeyguardGoneRunnable to synchronously invoke the Runnable arg
doAnswer(answerVoid(Runnable::run))
- .when(mShadeController).addAfterKeyguardGoneRunnable(any(Runnable.class));
+ .when(mStatusBar).addAfterKeyguardGoneRunnable(any(Runnable.class));
// set up addPostCollapseAction to synchronously invoke the Runnable arg
doAnswer(answerVoid(Runnable::run))
- .when(mShadeController).addPostCollapseAction(any(Runnable.class));
+ .when(mStatusBar).addPostCollapseAction(any(Runnable.class));
// set up Handler to synchronously invoke the Runnable arg
doAnswer(answerVoid(Runnable::run))
@@ -209,13 +209,13 @@ public class StatusBarNotificationActivityStarterTest extends SysuiTestCase {
sbn.getNotification().flags |= Notification.FLAG_AUTO_CANCEL;
when(mKeyguardStateController.isShowing()).thenReturn(true);
- when(mShadeController.isOccluded()).thenReturn(true);
+ when(mStatusBar.isOccluded()).thenReturn(true);
// When
mNotificationActivityStarter.onNotificationClicked(sbn, mNotificationRow);
// Then
- verify(mShadeController, atLeastOnce()).collapsePanel();
+ verify(mStatusBar, atLeastOnce()).collapsePanel();
verify(mContentIntent).sendAndReturnResult(
any(Context.class),
@@ -250,7 +250,7 @@ public class StatusBarNotificationActivityStarterTest extends SysuiTestCase {
verify(mBubbleController).expandStackAndSelectBubble(eq(sbn.getKey()));
// This is called regardless, and simply short circuits when there is nothing to do.
- verify(mShadeController, atLeastOnce()).collapsePanel();
+ verify(mStatusBar, atLeastOnce()).collapsePanel();
verify(mAssistManager).hideAssist();
@@ -272,7 +272,7 @@ public class StatusBarNotificationActivityStarterTest extends SysuiTestCase {
// Given
sbn.getNotification().contentIntent = null;
when(mKeyguardStateController.isShowing()).thenReturn(true);
- when(mShadeController.isOccluded()).thenReturn(true);
+ when(mStatusBar.isOccluded()).thenReturn(true);
// When
mNotificationActivityStarter.onNotificationClicked(sbn, mBubbleNotificationRow);
@@ -280,7 +280,7 @@ public class StatusBarNotificationActivityStarterTest extends SysuiTestCase {
// Then
verify(mBubbleController).expandStackAndSelectBubble(eq(sbn.getKey()));
- verify(mShadeController, atLeastOnce()).collapsePanel();
+ verify(mStatusBar, atLeastOnce()).collapsePanel();
verify(mAssistManager).hideAssist();
@@ -302,7 +302,7 @@ public class StatusBarNotificationActivityStarterTest extends SysuiTestCase {
// Given
sbn.getNotification().contentIntent = mContentIntent;
when(mKeyguardStateController.isShowing()).thenReturn(true);
- when(mShadeController.isOccluded()).thenReturn(true);
+ when(mStatusBar.isOccluded()).thenReturn(true);
// When
mNotificationActivityStarter.onNotificationClicked(sbn, mBubbleNotificationRow);
@@ -310,7 +310,7 @@ public class StatusBarNotificationActivityStarterTest extends SysuiTestCase {
// Then
verify(mBubbleController).expandStackAndSelectBubble(eq(sbn.getKey()));
- verify(mShadeController, atLeastOnce()).collapsePanel();
+ verify(mStatusBar, atLeastOnce()).collapsePanel();
verify(mAssistManager).hideAssist();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java
index 1c02b60902b8..14f5795c39f1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java
@@ -71,10 +71,11 @@ import java.util.ArrayList;
public class StatusBarNotificationPresenterTest extends SysuiTestCase {
- private StatusBarNotificationPresenter mStatusBar;
+ private StatusBarNotificationPresenter mStatusBarNotificationPresenter;
private CommandQueue mCommandQueue;
private FakeMetricsLogger mMetricsLogger;
private ShadeController mShadeController = mock(ShadeController.class);
+ private StatusBar mStatusBar = mock(StatusBar.class);
@Before
public void setup() {
@@ -105,14 +106,14 @@ public class StatusBarNotificationPresenterTest extends SysuiTestCase {
StatusBarWindowView statusBarWindowView = mock(StatusBarWindowView.class);
when(statusBarWindowView.getResources()).thenReturn(mContext.getResources());
- mStatusBar = new StatusBarNotificationPresenter(mContext,
+ mStatusBarNotificationPresenter = new StatusBarNotificationPresenter(mContext,
mock(NotificationPanelView.class), mock(HeadsUpManagerPhone.class),
statusBarWindowView, mock(NotificationListContainerViewGroup.class),
mock(DozeScrimController.class), mock(ScrimController.class),
mock(ActivityLaunchAnimator.class), mock(DynamicPrivacyController.class),
mock(NotificationAlertingManager.class),
mock(NotificationRowBinderImpl.class), mock(KeyguardStateController.class),
- mCommandQueue);
+ mStatusBar, mCommandQueue);
}
@Test
@@ -129,7 +130,7 @@ public class StatusBarNotificationPresenterTest extends SysuiTestCase {
TestableLooper.get(this).processAllMessages();
assertFalse("The panel shouldn't allow heads up while disabled",
- mStatusBar.canHeadsUp(entry, entry.getSbn()));
+ mStatusBarNotificationPresenter.canHeadsUp(entry, entry.getSbn()));
}
@Test
@@ -146,13 +147,13 @@ public class StatusBarNotificationPresenterTest extends SysuiTestCase {
TestableLooper.get(this).processAllMessages();
assertFalse("The panel shouldn't allow heads up while notitifcation shade disabled",
- mStatusBar.canHeadsUp(entry, entry.getSbn()));
+ mStatusBarNotificationPresenter.canHeadsUp(entry, entry.getSbn()));
}
@Test
public void onActivatedMetrics() {
ActivatableNotificationView view = mock(ActivatableNotificationView.class);
- mStatusBar.onActivated(view);
+ mStatusBarNotificationPresenter.onActivated(view);
MetricsAsserts.assertHasLog("missing lockscreen note tap log",
mMetricsLogger.getLogs(),
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
index e78fb9e521e1..be6809732963 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
@@ -145,6 +145,8 @@ import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Optional;
+import javax.inject.Provider;
+
import dagger.Lazy;
@SmallTest
@@ -227,6 +229,9 @@ public class StatusBarTest extends SysuiTestCase {
@Mock private VolumeComponent mVolumeComponent;
@Mock private CommandQueue mCommandQueue;
@Mock private Recents mRecents;
+ @Mock private Provider<StatusBarComponent.Builder> mStatusBarComponentBuilderProvider;
+ @Mock private StatusBarComponent.Builder mStatusBarComponentBuilder;
+ @Mock private StatusBarComponent mStatusBarComponent;
@Mock private PluginManager mPluginManager;
@Mock private Divider mDivider;
@Mock private SuperStatusBarViewFactory mSuperStatusBarViewFactory;
@@ -300,6 +305,11 @@ public class StatusBarTest extends SysuiTestCase {
when(mLockscreenWallpaperLazy.get()).thenReturn(mLockscreenWallpaper);
when(mBiometricUnlockControllerLazy.get()).thenReturn(mBiometricUnlockController);
+ when(mStatusBarComponentBuilderProvider.get()).thenReturn(mStatusBarComponentBuilder);
+ when(mStatusBarComponentBuilder.build()).thenReturn(mStatusBarComponent);
+ when(mStatusBarComponent.getStatusBarWindowViewController()).thenReturn(
+ mStatusBarWindowViewController);
+
mStatusBar = new StatusBar(
mContext,
mFeatureFlags,
@@ -354,7 +364,6 @@ public class StatusBarTest extends SysuiTestCase {
mNotificationListener,
configurationController,
mStatusBarWindowController,
- mStatusBarWindowViewController,
mLockscreenLockIconController,
mDozeParameters,
mScrimController,
@@ -367,6 +376,7 @@ public class StatusBarTest extends SysuiTestCase {
mVolumeComponent,
mCommandQueue,
Optional.of(mRecents),
+ mStatusBarComponentBuilderProvider,
mPluginManager,
mRemoteInputUriController,
Optional.of(mDivider),
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarWindowViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarWindowViewTest.java
index ee9ea9f26a95..529333effa2c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarWindowViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarWindowViewTest.java
@@ -36,7 +36,6 @@ import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.DragDownHelper;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
import com.android.systemui.statusbar.PulseExpansionHandler;
-import com.android.systemui.statusbar.SuperStatusBarViewFactory;
import com.android.systemui.statusbar.SysuiStatusBarStateController;
import com.android.systemui.statusbar.notification.DynamicPrivacyController;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
@@ -74,7 +73,6 @@ public class StatusBarWindowViewTest extends SysuiTestCase {
@Mock private StatusBar mStatusBar;
@Mock private DozeLog mDozeLog;
@Mock private DozeParameters mDozeParameters;
- @Mock private SuperStatusBarViewFactory mSuperStatusBarViewFactory;
@Mock private DockManager mDockManager;
@Before
@@ -85,7 +83,6 @@ public class StatusBarWindowViewTest extends SysuiTestCase {
when(mStatusBar.isDozing()).thenReturn(false);
mDependency.injectTestDependency(ShadeController.class, mShadeController);
- when(mSuperStatusBarViewFactory.getStatusBarWindowView()).thenReturn(mView);
when(mDockManager.isDocked()).thenReturn(false);
mController = new StatusBarWindowViewController(
@@ -105,9 +102,9 @@ public class StatusBarWindowViewTest extends SysuiTestCase {
mDozeLog,
mDozeParameters,
new CommandQueue(mContext),
- mSuperStatusBarViewFactory,
() -> mShadeController,
- mDockManager);
+ mDockManager,
+ mView);
mController.setupExpandedStatusBar();
mController.setService(mStatusBar);
mController.setDragDownHelper(mDragDownHelper);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/concurrency/FakeExecutor.java b/packages/SystemUI/tests/src/com/android/systemui/util/concurrency/FakeExecutor.java
new file mode 100644
index 000000000000..3ed6c5b2b11b
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/concurrency/FakeExecutor.java
@@ -0,0 +1,227 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.util.concurrency;
+
+import com.android.systemui.util.time.FakeSystemClock;
+import com.android.systemui.util.time.FakeSystemClock.ClockTickListener;
+
+import java.util.Collections;
+import java.util.PriorityQueue;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
+
+public class FakeExecutor implements DelayableExecutor {
+ private final FakeSystemClock mClock;
+ private PriorityQueue<QueuedRunnable> mQueuedRunnables = new PriorityQueue<>();
+ private boolean mIgnoreClockUpdates;
+
+ private ClockTickListener mClockTickListener = new ClockTickListener() {
+ @Override
+ public void onUptimeMillis(long uptimeMillis) {
+ if (!mIgnoreClockUpdates) {
+ runAllReady();
+ }
+ }
+ };
+
+ /**
+ * Initializes a fake executor.
+ *
+ * @param clock FakeSystemClock allowing control over delayed runnables. It is strongly
+ * recommended that this clock have its auto-increment setting set to false to
+ * prevent unexpected advancement of the time.
+ */
+ public FakeExecutor(FakeSystemClock clock) {
+ mClock = clock;
+ mClock.addListener(mClockTickListener);
+ }
+
+ /**
+ * Runs a single runnable if it's scheduled to run according to the internal clock.
+ *
+ * If constructed to advance the clock automatically, this will advance the clock enough to
+ * run the next pending item.
+ *
+ * This method does not advance the clock past the item that was run.
+ *
+ * @return Returns true if an item was run.
+ */
+ public boolean runNextReady() {
+ if (!mQueuedRunnables.isEmpty() && mQueuedRunnables.peek().mWhen <= mClock.uptimeMillis()) {
+ mQueuedRunnables.poll().mRunnable.run();
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * Runs all Runnables that are scheduled to run according to the internal clock.
+ *
+ * If constructed to advance the clock automatically, this will advance the clock enough to
+ * run all the pending items. This method does not advance the clock past items that were
+ * run. It is equivalent to calling {@link #runNextReady()} in a loop.
+ *
+ * @return Returns the number of items that ran.
+ */
+ public int runAllReady() {
+ int num = 0;
+ while (runNextReady()) {
+ num++;
+ }
+
+ return num;
+ }
+
+ /**
+ * Advances the internal clock to the next item to run.
+ *
+ * The clock will only move forward. If the next item is set to run in the past or there is no
+ * next item, the clock does not change.
+ *
+ * Note that this will cause one or more items to actually run.
+ *
+ * @return The delta in uptimeMillis that the clock advanced, or 0 if the clock did not advance.
+ */
+ public long advanceClockToNext() {
+ if (mQueuedRunnables.isEmpty()) {
+ return 0;
+ }
+
+ long startTime = mClock.uptimeMillis();
+ long nextTime = mQueuedRunnables.peek().mWhen;
+ if (nextTime <= startTime) {
+ return 0;
+ }
+ updateClock(nextTime);
+
+ return nextTime - startTime;
+ }
+
+
+ /**
+ * Advances the internal clock to the last item to run.
+ *
+ * The clock will only move forward. If the last item is set to run in the past or there is no
+ * next item, the clock does not change.
+ *
+ * @return The delta in uptimeMillis that the clock advanced, or 0 if the clock did not advance.
+ */
+ public long advanceClockToLast() {
+ if (mQueuedRunnables.isEmpty()) {
+ return 0;
+ }
+
+ long startTime = mClock.uptimeMillis();
+ long nextTime = Collections.max(mQueuedRunnables).mWhen;
+ if (nextTime <= startTime) {
+ return 0;
+ }
+
+ updateClock(nextTime);
+
+ return nextTime - startTime;
+ }
+
+ /**
+ * Returns the number of un-executed runnables waiting to run.
+ */
+ public int numPending() {
+ return mQueuedRunnables.size();
+ }
+
+ @Override
+ public Runnable executeDelayed(Runnable r, long delay, TimeUnit unit) {
+ if (delay < 0) {
+ delay = 0;
+ }
+ return executeAtTime(r, mClock.uptimeMillis() + unit.toMillis(delay));
+ }
+
+ @Override
+ public Runnable executeAtTime(Runnable r, long uptime, TimeUnit unit) {
+ long uptimeMillis = unit.toMillis(uptime);
+
+ QueuedRunnable container = new QueuedRunnable(r, uptimeMillis);
+
+ mQueuedRunnables.offer(container);
+
+ return () -> mQueuedRunnables.remove(container);
+ }
+
+ @Override
+ public void execute(Runnable command) {
+ executeDelayed(command, 0);
+ }
+
+ @Override
+ public void removeAll() {
+ mQueuedRunnables.clear();
+ }
+
+ /**
+ * Run all Executors in a loop until they all report they have no ready work to do.
+ *
+ * Useful if you have Executors the post work to other Executors, and you simply want to
+ * run them all until they stop posting work.
+ */
+ public static void exhaustExecutors(FakeExecutor ...executors) {
+ boolean didAnything;
+ do {
+ didAnything = false;
+ for (FakeExecutor executor : executors) {
+ didAnything = didAnything || executor.runAllReady() != 0;
+ }
+ } while (didAnything);
+ }
+
+ private void updateClock(long nextTime) {
+ mIgnoreClockUpdates = true;
+ mClock.setUptimeMillis(nextTime);
+ mIgnoreClockUpdates = false;
+ }
+
+ private static class QueuedRunnable implements Comparable<QueuedRunnable> {
+ private static AtomicInteger sCounter = new AtomicInteger();
+
+ Runnable mRunnable;
+ long mWhen;
+ private int mCounter;
+
+ private QueuedRunnable(Runnable r, long when) {
+ mRunnable = r;
+ mWhen = when;
+
+ // PrioirityQueue orders items arbitrarily when equal. We want to ensure that
+ // otherwise-equal elements are ordered according to their insertion order. Because this
+ // class only is constructed right before insertion, we use a static counter to track
+ // insertion order of otherwise equal elements.
+ mCounter = sCounter.incrementAndGet();
+ }
+
+ @Override
+ public int compareTo(QueuedRunnable other) {
+ long diff = mWhen - other.mWhen;
+
+ if (diff == 0) {
+ return mCounter - other.mCounter;
+ }
+
+ return diff > 0 ? 1 : -1;
+ }
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/concurrency/FakeExecutorTest.java b/packages/SystemUI/tests/src/com/android/systemui/util/concurrency/FakeExecutorTest.java
new file mode 100644
index 000000000000..7fd694244afa
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/concurrency/FakeExecutorTest.java
@@ -0,0 +1,366 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.util.concurrency;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import android.testing.AndroidTestingRunner;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.util.time.FakeSystemClock;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import kotlin.jvm.functions.Function4;
+
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+public class FakeExecutorTest extends SysuiTestCase {
+ @Before
+ public void setUp() throws Exception {
+ }
+
+ /**
+ * Test FakeExecutor that receives non-delayed items to execute.
+ */
+ @Test
+ public void testNoDelay() {
+ FakeSystemClock clock = new FakeSystemClock();
+ clock.setAutoIncrement(false);
+ FakeExecutor fakeExecutor = new FakeExecutor(clock);
+ RunnableImpl runnable = new RunnableImpl();
+
+ assertEquals(0, clock.uptimeMillis());
+ assertEquals(0, runnable.mRunCount);
+
+ // Execute two runnables. They should not run and should be left pending.
+ fakeExecutor.execute(runnable);
+ assertEquals(0, runnable.mRunCount);
+ assertEquals(0, clock.uptimeMillis());
+ assertEquals(1, fakeExecutor.numPending());
+ fakeExecutor.execute(runnable);
+ assertEquals(0, runnable.mRunCount);
+ assertEquals(0, clock.uptimeMillis());
+ assertEquals(2, fakeExecutor.numPending());
+
+ // Run one pending runnable.
+ assertTrue(fakeExecutor.runNextReady());
+ assertEquals(1, runnable.mRunCount);
+ assertEquals(0, clock.uptimeMillis());
+ assertEquals(1, fakeExecutor.numPending());
+ // Run a second pending runnable.
+ assertTrue(fakeExecutor.runNextReady());
+ assertEquals(2, runnable.mRunCount);
+ assertEquals(0, clock.uptimeMillis());
+ assertEquals(0, fakeExecutor.numPending());
+
+ // No more runnables to run.
+ assertFalse(fakeExecutor.runNextReady());
+
+ // Add two more runnables.
+ fakeExecutor.execute(runnable);
+ fakeExecutor.execute(runnable);
+ assertEquals(2, runnable.mRunCount);
+ assertEquals(0, clock.uptimeMillis());
+ assertEquals(2, fakeExecutor.numPending());
+ // Execute all pending runnables in batch.
+ assertEquals(2, fakeExecutor.runAllReady());
+ assertEquals(4, runnable.mRunCount);
+ assertEquals(0, clock.uptimeMillis());
+ assertEquals(0, fakeExecutor.runAllReady());
+ }
+
+ /**
+ * Test FakeExecutor that is told to delay execution on items.
+ */
+ @Test
+ public void testDelayed() {
+ FakeSystemClock clock = new FakeSystemClock();
+ clock.setAutoIncrement(false);
+ FakeExecutor fakeExecutor = new FakeExecutor(clock);
+ RunnableImpl runnable = new RunnableImpl();
+
+ // Add three delayed runnables.
+ fakeExecutor.executeDelayed(runnable, 1);
+ fakeExecutor.executeDelayed(runnable, 50);
+ fakeExecutor.executeDelayed(runnable, 100);
+ assertEquals(0, runnable.mRunCount);
+ assertEquals(0, clock.uptimeMillis());
+ assertEquals(3, fakeExecutor.numPending());
+ // Delayed runnables should not advance the clock and therefore should not run.
+ assertFalse(fakeExecutor.runNextReady());
+ assertEquals(0, fakeExecutor.runAllReady());
+ assertEquals(3, fakeExecutor.numPending());
+
+ // Advance the clock to the next runnable. One runnable should execute.
+ assertEquals(1, fakeExecutor.advanceClockToNext());
+ assertEquals(1, fakeExecutor.runAllReady());
+ assertEquals(2, fakeExecutor.numPending());
+ assertEquals(1, runnable.mRunCount);
+ // Advance the clock to the last runnable.
+ assertEquals(99, fakeExecutor.advanceClockToLast());
+ assertEquals(2, fakeExecutor.runAllReady());
+ // Now all remaining runnables should execute.
+ assertEquals(0, fakeExecutor.numPending());
+ assertEquals(3, runnable.mRunCount);
+ }
+
+ /**
+ * Test FakeExecutor that is told to delay execution on items.
+ */
+ @Test
+ public void testDelayed_AdvanceAndRun() {
+ FakeSystemClock clock = new FakeSystemClock();
+ clock.setAutoIncrement(false);
+ FakeExecutor fakeExecutor = new FakeExecutor(clock);
+ RunnableImpl runnable = new RunnableImpl();
+
+ // Add three delayed runnables.
+ fakeExecutor.executeDelayed(runnable, 1);
+ fakeExecutor.executeDelayed(runnable, 50);
+ fakeExecutor.executeDelayed(runnable, 100);
+ assertEquals(0, runnable.mRunCount);
+ assertEquals(0, clock.uptimeMillis());
+ assertEquals(3, fakeExecutor.numPending());
+ // Delayed runnables should not advance the clock and therefore should not run.
+ assertFalse(fakeExecutor.runNextReady());
+ assertEquals(0, fakeExecutor.runAllReady());
+ assertEquals(3, fakeExecutor.numPending());
+
+ // Advance the clock to the next runnable. Check that it is run.
+ assertEquals(1, fakeExecutor.advanceClockToNext());
+ assertEquals(1, fakeExecutor.runAllReady());
+ assertEquals(1, clock.uptimeMillis());
+ assertEquals(2, fakeExecutor.numPending());
+ assertEquals(1, runnable.mRunCount);
+ assertEquals(49, fakeExecutor.advanceClockToNext());
+ assertEquals(1, fakeExecutor.runAllReady());
+ assertEquals(50, clock.uptimeMillis());
+ assertEquals(1, fakeExecutor.numPending());
+ assertEquals(2, runnable.mRunCount);
+ assertEquals(50, fakeExecutor.advanceClockToNext());
+ assertEquals(1, fakeExecutor.runAllReady());
+ assertEquals(100, clock.uptimeMillis());
+ assertEquals(0, fakeExecutor.numPending());
+ assertEquals(3, runnable.mRunCount);
+
+ // Nothing left to do
+ assertEquals(0, fakeExecutor.advanceClockToNext());
+ assertEquals(0, fakeExecutor.runAllReady());
+ assertEquals(100, clock.uptimeMillis());
+ assertEquals(0, fakeExecutor.numPending());
+ assertEquals(3, runnable.mRunCount);
+ }
+
+ /**
+ * Test execution order.
+ */
+ @Test
+ public void testExecutionOrder() {
+ FakeSystemClock clock = new FakeSystemClock();
+ clock.setAutoIncrement(false);
+ FakeExecutor fakeExecutor = new FakeExecutor(clock);
+ RunnableImpl runnableA = new RunnableImpl();
+ RunnableImpl runnableB = new RunnableImpl();
+ RunnableImpl runnableC = new RunnableImpl();
+ RunnableImpl runnableD = new RunnableImpl();
+
+ Function4<Integer, Integer, Integer, Integer, Void> checkRunCounts =
+ (Integer argA, Integer argB, Integer argC, Integer argD) -> {
+ assertEquals("RunnableA run count wrong", argA.intValue(), runnableA.mRunCount);
+ assertEquals("RunnableB run count wrong", argB.intValue(), runnableB.mRunCount);
+ assertEquals("RunnableC run count wrong", argC.intValue(), runnableC.mRunCount);
+ assertEquals("RunnableD run count wrong", argD.intValue(), runnableD.mRunCount);
+ return null;
+ };
+
+ assertEquals(0, clock.uptimeMillis());
+ checkRunCounts.invoke(0, 0, 0, 0);
+
+ fakeExecutor.execute(runnableA);
+ fakeExecutor.execute(runnableB);
+ fakeExecutor.execute(runnableC);
+ fakeExecutor.execute(runnableD);
+
+ fakeExecutor.runNextReady();
+ checkRunCounts.invoke(1, 0, 0, 0);
+ fakeExecutor.runNextReady();
+ checkRunCounts.invoke(1, 1, 0, 0);
+ fakeExecutor.runNextReady();
+ checkRunCounts.invoke(1, 1, 1, 0);
+ fakeExecutor.runNextReady();
+ checkRunCounts.invoke(1, 1, 1, 1);
+
+ fakeExecutor.executeDelayed(runnableA, 100);
+ fakeExecutor.execute(runnableB);
+ fakeExecutor.executeDelayed(runnableC, 50);
+ fakeExecutor.execute(runnableD);
+
+ fakeExecutor.advanceClockToNext();
+ fakeExecutor.runAllReady();
+ checkRunCounts.invoke(1, 2, 1, 2);
+ fakeExecutor.advanceClockToNext();
+ fakeExecutor.runAllReady();
+ checkRunCounts.invoke(1, 2, 2, 2);
+ fakeExecutor.advanceClockToNext();
+ fakeExecutor.runAllReady();
+ checkRunCounts.invoke(2, 2, 2, 2);
+
+ fakeExecutor.execute(runnableA);
+ fakeExecutor.executeAtTime(runnableB, 0); // this is in the past!
+ fakeExecutor.executeAtTime(runnableC, 1000);
+ fakeExecutor.executeAtTime(runnableD, 500);
+
+ fakeExecutor.advanceClockToNext();
+ fakeExecutor.runAllReady();
+ checkRunCounts.invoke(3, 3, 2, 2);
+ fakeExecutor.advanceClockToNext();
+ fakeExecutor.runAllReady();
+ checkRunCounts.invoke(3, 3, 2, 3);
+ fakeExecutor.advanceClockToNext();
+ fakeExecutor.runAllReady();
+ checkRunCounts.invoke(3, 3, 3, 3);
+ }
+
+ /**
+ * Test removing a single item.
+ */
+ @Test
+ public void testRemoval_single() {
+ FakeSystemClock clock = new FakeSystemClock();
+ clock.setAutoIncrement(false);
+ FakeExecutor fakeExecutor = new FakeExecutor(clock);
+ RunnableImpl runnable = new RunnableImpl();
+ Runnable removeFunction;
+
+ // Nothing to remove.
+ assertEquals(0, runnable.mRunCount);
+ assertEquals(0, fakeExecutor.numPending());
+
+ // Two pending items that have not yet run.
+ // We will try to remove the second item.
+ fakeExecutor.executeDelayed(runnable, 100);
+ removeFunction = fakeExecutor.executeDelayed(runnable, 200);
+ assertEquals(2, fakeExecutor.numPending());
+ assertEquals(0, runnable.mRunCount);
+
+ // Remove the item.
+ removeFunction.run();
+ assertEquals(1, fakeExecutor.numPending());
+ assertEquals(0, runnable.mRunCount);
+
+ // One item to run.
+ fakeExecutor.advanceClockToLast();
+ fakeExecutor.runAllReady();
+ assertEquals(0, fakeExecutor.numPending());
+ assertEquals(1, runnable.mRunCount);
+
+ // Nothing to remove.
+ removeFunction.run();
+ fakeExecutor.runAllReady();
+ assertEquals(0, fakeExecutor.numPending());
+ assertEquals(1, runnable.mRunCount);
+ }
+
+ /**
+ * Test removing multiple items.
+ */
+ @Test
+ public void testRemoval_multi() {
+ FakeSystemClock clock = new FakeSystemClock();
+ clock.setAutoIncrement(false);
+ FakeExecutor fakeExecutor = new FakeExecutor(clock);
+ List<Runnable> removeFunctions = new ArrayList<>();
+ RunnableImpl runnable = new RunnableImpl();
+
+ // Nothing to remove.
+ assertEquals(0, runnable.mRunCount);
+ assertEquals(0, fakeExecutor.numPending());
+
+ // Three pending items that have not yet run.
+ // We will try to remove the first and third items.
+ removeFunctions.add(fakeExecutor.executeDelayed(runnable, 100));
+ fakeExecutor.executeDelayed(runnable, 200);
+ removeFunctions.add(fakeExecutor.executeDelayed(runnable, 300));
+ assertEquals(3, fakeExecutor.numPending());
+ assertEquals(0, runnable.mRunCount);
+
+ // Remove the items.
+ removeFunctions.forEach(Runnable::run);
+ assertEquals(1, fakeExecutor.numPending());
+ assertEquals(0, runnable.mRunCount);
+
+ // One item to run.
+ fakeExecutor.advanceClockToLast();
+ fakeExecutor.runAllReady();
+ assertEquals(0, fakeExecutor.numPending());
+ assertEquals(1, runnable.mRunCount);
+
+ // Nothing to remove.
+ removeFunctions.forEach(Runnable::run);
+ assertEquals(0, fakeExecutor.numPending());
+ assertEquals(1, runnable.mRunCount);
+ }
+
+ /**
+ * Test removing everything
+ */
+ @Test
+ public void testRemoval_all() {
+ FakeSystemClock clock = new FakeSystemClock();
+ clock.setAutoIncrement(false);
+ FakeExecutor fakeExecutor = new FakeExecutor(clock);
+ RunnableImpl runnable = new RunnableImpl();
+
+ // Nothing to remove.
+ assertEquals(0, runnable.mRunCount);
+ assertEquals(0, fakeExecutor.numPending());
+
+ // Two pending items that have not yet run.
+ fakeExecutor.executeDelayed(runnable, 100);
+ fakeExecutor.executeDelayed(runnable, 200);
+ assertEquals(2, fakeExecutor.numPending());
+ assertEquals(0, runnable.mRunCount);
+
+ // Remove the items.
+ fakeExecutor.removeAll();
+
+ // Nothing to run
+ fakeExecutor.advanceClockToLast();
+ assertEquals(0, fakeExecutor.runAllReady());
+ assertEquals(0, fakeExecutor.numPending());
+ assertEquals(0, runnable.mRunCount);
+ }
+
+ private static class RunnableImpl implements Runnable {
+ int mRunCount;
+
+ @Override
+ public void run() {
+ mRunCount++;
+ }
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/time/FakeSystemClock.java b/packages/SystemUI/tests/src/com/android/systemui/util/time/FakeSystemClock.java
index 7b5417cd5c36..65e5902c84df 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/util/time/FakeSystemClock.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/time/FakeSystemClock.java
@@ -16,6 +16,9 @@
package com.android.systemui.util.time;
+import java.util.ArrayList;
+import java.util.List;
+
public class FakeSystemClock implements SystemClock {
private boolean mAutoIncrement = true;
@@ -26,11 +29,13 @@ public class FakeSystemClock implements SystemClock {
private long mCurrentThreadTimeMicro;
private long mCurrentTimeMicro;
+ List<ClockTickListener> mListeners = new ArrayList<>();
+
@Override
public long uptimeMillis() {
long value = mUptimeMillis;
if (mAutoIncrement) {
- mUptimeMillis++;
+ setUptimeMillis(mUptimeMillis + 1);
}
return value;
}
@@ -39,7 +44,7 @@ public class FakeSystemClock implements SystemClock {
public long elapsedRealtime() {
long value = mElapsedRealtime;
if (mAutoIncrement) {
- mElapsedRealtime++;
+ setElapsedRealtime(mElapsedRealtime + 1);
}
return value;
}
@@ -48,7 +53,7 @@ public class FakeSystemClock implements SystemClock {
public long elapsedRealtimeNanos() {
long value = mElapsedRealtimeNanos;
if (mAutoIncrement) {
- mElapsedRealtimeNanos++;
+ setElapsedRealtimeNanos(mElapsedRealtimeNanos + 1);
}
return value;
}
@@ -57,7 +62,7 @@ public class FakeSystemClock implements SystemClock {
public long currentThreadTimeMillis() {
long value = mCurrentThreadTimeMillis;
if (mAutoIncrement) {
- mCurrentThreadTimeMillis++;
+ setCurrentThreadTimeMillis(mCurrentThreadTimeMillis + 1);
}
return value;
}
@@ -66,7 +71,7 @@ public class FakeSystemClock implements SystemClock {
public long currentThreadTimeMicro() {
long value = mCurrentThreadTimeMicro;
if (mAutoIncrement) {
- mCurrentThreadTimeMicro++;
+ setCurrentThreadTimeMicro(mCurrentThreadTimeMicro + 1);
}
return value;
}
@@ -75,37 +80,90 @@ public class FakeSystemClock implements SystemClock {
public long currentTimeMicro() {
long value = mCurrentTimeMicro;
if (mAutoIncrement) {
- mCurrentTimeMicro++;
+ setCurrentTimeMicro(mCurrentTimeMicro + 1);
}
return value;
}
public void setUptimeMillis(long uptimeMillis) {
mUptimeMillis = uptimeMillis;
+ for (ClockTickListener listener : mListeners) {
+ listener.onUptimeMillis(mUptimeMillis);
+ }
}
public void setElapsedRealtime(long elapsedRealtime) {
mElapsedRealtime = elapsedRealtime;
+ for (ClockTickListener listener : mListeners) {
+ listener.onElapsedRealtime(mElapsedRealtime);
+ }
}
public void setElapsedRealtimeNanos(long elapsedRealtimeNanos) {
mElapsedRealtimeNanos = elapsedRealtimeNanos;
+ for (ClockTickListener listener : mListeners) {
+ listener.onElapsedRealtimeNanos(mElapsedRealtimeNanos);
+ }
}
public void setCurrentThreadTimeMillis(long currentThreadTimeMillis) {
mCurrentThreadTimeMillis = currentThreadTimeMillis;
+ for (ClockTickListener listener : mListeners) {
+ listener.onCurrentThreadTimeMillis(mCurrentThreadTimeMillis);
+ }
}
public void setCurrentThreadTimeMicro(long currentThreadTimeMicro) {
mCurrentThreadTimeMicro = currentThreadTimeMicro;
+ for (ClockTickListener listener : mListeners) {
+ listener.onCurrentThreadTimeMicro(mCurrentThreadTimeMicro);
+ }
}
public void setCurrentTimeMicro(long currentTimeMicro) {
mCurrentTimeMicro = currentTimeMicro;
+ for (ClockTickListener listener : mListeners) {
+ listener.onCurrentTimeMicro(mCurrentTimeMicro);
+ }
}
/** If true, each call to get____ will be one higher than the previous call to that method. */
public void setAutoIncrement(boolean autoIncrement) {
mAutoIncrement = autoIncrement;
}
+
+ public void addListener(ClockTickListener listener) {
+ mListeners.add(listener);
+ }
+
+ public void removeListener(ClockTickListener listener) {
+ mListeners.remove(listener);
+ }
+
+ /** Alert all the listeners about the current time. */
+ public void synchronizeListeners() {
+ for (ClockTickListener listener : mListeners) {
+ listener.onUptimeMillis(mUptimeMillis);
+ listener.onElapsedRealtime(mElapsedRealtime);
+ listener.onElapsedRealtimeNanos(mElapsedRealtimeNanos);
+ listener.onCurrentThreadTimeMillis(mCurrentThreadTimeMillis);
+ listener.onCurrentThreadTimeMicro(mCurrentThreadTimeMicro);
+ listener.onCurrentTimeMicro(mCurrentTimeMicro);
+ }
+ }
+
+
+ public interface ClockTickListener {
+ default void onUptimeMillis(long uptimeMillis) {}
+
+ default void onElapsedRealtime(long elapsedRealtime) {}
+
+ default void onElapsedRealtimeNanos(long elapsedRealtimeNanos) {}
+
+ default void onCurrentThreadTimeMillis(long currentThreadTimeMillis) {}
+
+ default void onCurrentThreadTimeMicro(long currentThreadTimeMicro) {}
+
+ default void onCurrentTimeMicro(long currentTimeMicro) {}
+ }
}
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityWindowManager.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityWindowManager.java
index 339fc963b427..8ce92a3154f3 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityWindowManager.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityWindowManager.java
@@ -972,6 +972,9 @@ public class AccessibilityWindowManager {
if (shouldComputeWindows) {
mWindowManagerInternal.computeWindowsForAccessibility(displayId);
}
+
+ mWindowManagerInternal.setAccessibilityIdToSurfaceMetadata(
+ windowToken.asBinder(), windowId);
return windowId;
}
@@ -991,7 +994,7 @@ public class AccessibilityWindowManager {
final int removedWindowId = removeAccessibilityInteractionConnectionInternalLocked(
token, mGlobalWindowTokens, mGlobalInteractionConnections);
if (removedWindowId >= 0) {
- onAccessibilityInteractionConnectionRemovedLocked(removedWindowId);
+ onAccessibilityInteractionConnectionRemovedLocked(removedWindowId, token);
if (DEBUG) {
Slog.i(LOG_TAG, "Removed global connection for pid:" + Binder.getCallingPid()
+ " with windowId: " + removedWindowId + " and token: "
@@ -1007,7 +1010,8 @@ public class AccessibilityWindowManager {
getWindowTokensForUserLocked(userId),
getInteractionConnectionsForUserLocked(userId));
if (removedWindowIdForUser >= 0) {
- onAccessibilityInteractionConnectionRemovedLocked(removedWindowIdForUser);
+ onAccessibilityInteractionConnectionRemovedLocked(
+ removedWindowIdForUser, token);
if (DEBUG) {
Slog.i(LOG_TAG, "Removed user connection for pid:" + Binder.getCallingPid()
+ " with windowId: " + removedWindowIdForUser + " and userId:"
@@ -1069,18 +1073,21 @@ public class AccessibilityWindowManager {
* @param userId The userId to remove
*/
private void removeAccessibilityInteractionConnectionLocked(int windowId, int userId) {
+ IBinder window = null;
if (userId == UserHandle.USER_ALL) {
+ window = mGlobalWindowTokens.get(windowId);
mGlobalWindowTokens.remove(windowId);
mGlobalInteractionConnections.remove(windowId);
} else {
if (isValidUserForWindowTokensLocked(userId)) {
+ window = getWindowTokensForUserLocked(userId).get(windowId);
getWindowTokensForUserLocked(userId).remove(windowId);
}
if (isValidUserForInteractionConnectionsLocked(userId)) {
getInteractionConnectionsForUserLocked(userId).remove(windowId);
}
}
- onAccessibilityInteractionConnectionRemovedLocked(windowId);
+ onAccessibilityInteractionConnectionRemovedLocked(windowId, window);
if (DEBUG) {
Slog.i(LOG_TAG, "Removing interaction connection to windowId: " + windowId);
}
@@ -1091,12 +1098,17 @@ public class AccessibilityWindowManager {
*
* @param windowId Removed windowId
*/
- private void onAccessibilityInteractionConnectionRemovedLocked(int windowId) {
+ private void onAccessibilityInteractionConnectionRemovedLocked(
+ int windowId, @Nullable IBinder binder) {
// Active window will not update, if windows callback is unregistered.
// Update active window to invalid, when its a11y interaction connection is removed.
if (!isTrackingWindowsLocked() && windowId >= 0 && mActiveWindowId == windowId) {
mActiveWindowId = AccessibilityWindowInfo.UNDEFINED_WINDOW_ID;
}
+ if (binder != null) {
+ mWindowManagerInternal.setAccessibilityIdToSurfaceMetadata(
+ binder, AccessibilityWindowInfo.UNDEFINED_WINDOW_ID);
+ }
}
/**
diff --git a/services/accessibility/java/com/android/server/accessibility/SystemActionPerformer.java b/services/accessibility/java/com/android/server/accessibility/SystemActionPerformer.java
index 19ac0d3c1024..17549268503e 100644
--- a/services/accessibility/java/com/android/server/accessibility/SystemActionPerformer.java
+++ b/services/accessibility/java/com/android/server/accessibility/SystemActionPerformer.java
@@ -17,6 +17,8 @@
package com.android.server.accessibility;
import android.accessibilityservice.AccessibilityService;
+import android.app.PendingIntent;
+import android.app.RemoteAction;
import android.app.StatusBarManager;
import android.content.Context;
import android.hardware.input.InputManager;
@@ -25,81 +27,272 @@ import android.os.Handler;
import android.os.Looper;
import android.os.PowerManager;
import android.os.SystemClock;
+import android.util.ArrayMap;
+import android.util.Slog;
import android.view.InputDevice;
import android.view.KeyCharacterMap;
import android.view.KeyEvent;
+import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction;
+import com.android.internal.R;
+import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.ScreenshotHelper;
import com.android.server.LocalServices;
import com.android.server.statusbar.StatusBarManagerInternal;
import com.android.server.wm.WindowManagerInternal;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
import java.util.function.Supplier;
/**
- * Handle the back-end of AccessibilityService#performGlobalAction
+ * Handle the back-end of system AccessibilityAction.
+ *
+ * This class should support three use cases with combined usage of new API and legacy API:
+ *
+ * Use case 1: SystemUI doesn't use the new system action registration API. Accessibility
+ * service doesn't use the new system action API to obtain action list. Accessibility
+ * service uses legacy global action id to perform predefined system actions.
+ * Use case 2: SystemUI uses the new system action registration API to register available system
+ * actions. Accessibility service doesn't use the new system action API to obtain action
+ * list. Accessibility service uses legacy global action id to trigger the system
+ * actions registered by SystemUI.
+ * Use case 3: SystemUI doesn't use the new system action registration API.Accessibility service
+ * obtains the available system actions using new AccessibilityService API and trigger
+ * the predefined system actions.
*/
public class SystemActionPerformer {
+ private static final String TAG = "SystemActionPerformer";
+
+ interface SystemActionsChangedListener {
+ void onSystemActionsChanged();
+ }
+ private final SystemActionsChangedListener mListener;
+
+ private final Object mSystemActionLock = new Object();
+ // Resource id based ActionId -> RemoteAction
+ @GuardedBy("mSystemActionLock")
+ private final Map<Integer, RemoteAction> mRegisteredSystemActions = new ArrayMap<>();
+
+ // Legacy system actions.
+ private final AccessibilityAction mLegacyHomeAction;
+ private final AccessibilityAction mLegacyBackAction;
+ private final AccessibilityAction mLegacyRecentsAction;
+ private final AccessibilityAction mLegacyNotificationsAction;
+ private final AccessibilityAction mLegacyQuickSettingsAction;
+ private final AccessibilityAction mLegacyPowerDialogAction;
+ private final AccessibilityAction mLegacyToggleSplitScreenAction;
+ private final AccessibilityAction mLegacyLockScreenAction;
+ private final AccessibilityAction mLegacyTakeScreenshotAction;
+
private final WindowManagerInternal mWindowManagerService;
private final Context mContext;
private Supplier<ScreenshotHelper> mScreenshotHelperSupplier;
- public SystemActionPerformer(Context context, WindowManagerInternal windowManagerInternal) {
- mContext = context;
- mWindowManagerService = windowManagerInternal;
- mScreenshotHelperSupplier = null;
+ public SystemActionPerformer(
+ Context context,
+ WindowManagerInternal windowManagerInternal) {
+ this(context, windowManagerInternal, null, null);
}
// Used to mock ScreenshotHelper
@VisibleForTesting
- public SystemActionPerformer(Context context, WindowManagerInternal windowManagerInternal,
+ public SystemActionPerformer(
+ Context context,
+ WindowManagerInternal windowManagerInternal,
Supplier<ScreenshotHelper> screenshotHelperSupplier) {
- this(context, windowManagerInternal);
+ this(context, windowManagerInternal, screenshotHelperSupplier, null);
+ }
+
+ public SystemActionPerformer(
+ Context context,
+ WindowManagerInternal windowManagerInternal,
+ Supplier<ScreenshotHelper> screenshotHelperSupplier,
+ SystemActionsChangedListener listener) {
+ mContext = context;
+ mWindowManagerService = windowManagerInternal;
+ mListener = listener;
mScreenshotHelperSupplier = screenshotHelperSupplier;
+
+ mLegacyHomeAction = new AccessibilityAction(
+ AccessibilityService.GLOBAL_ACTION_HOME,
+ mContext.getResources().getString(
+ R.string.accessibility_system_action_home_label));
+ mLegacyBackAction = new AccessibilityAction(
+ AccessibilityService.GLOBAL_ACTION_BACK,
+ mContext.getResources().getString(
+ R.string.accessibility_system_action_back_label));
+ mLegacyRecentsAction = new AccessibilityAction(
+ AccessibilityService.GLOBAL_ACTION_RECENTS,
+ mContext.getResources().getString(
+ R.string.accessibility_system_action_recents_label));
+ mLegacyNotificationsAction = new AccessibilityAction(
+ AccessibilityService.GLOBAL_ACTION_NOTIFICATIONS,
+ mContext.getResources().getString(
+ R.string.accessibility_system_action_notifications_label));
+ mLegacyQuickSettingsAction = new AccessibilityAction(
+ AccessibilityService.GLOBAL_ACTION_QUICK_SETTINGS,
+ mContext.getResources().getString(
+ R.string.accessibility_system_action_quick_settings_label));
+ mLegacyPowerDialogAction = new AccessibilityAction(
+ AccessibilityService.GLOBAL_ACTION_POWER_DIALOG,
+ mContext.getResources().getString(
+ R.string.accessibility_system_action_power_dialog_label));
+ mLegacyToggleSplitScreenAction = new AccessibilityAction(
+ AccessibilityService.GLOBAL_ACTION_TOGGLE_SPLIT_SCREEN,
+ mContext.getResources().getString(
+ R.string.accessibility_system_action_toggle_split_screen_label));
+ mLegacyLockScreenAction = new AccessibilityAction(
+ AccessibilityService.GLOBAL_ACTION_LOCK_SCREEN,
+ mContext.getResources().getString(
+ R.string.accessibility_system_action_lock_screen_label));
+ mLegacyTakeScreenshotAction = new AccessibilityAction(
+ AccessibilityService.GLOBAL_ACTION_TAKE_SCREENSHOT,
+ mContext.getResources().getString(
+ R.string.accessibility_system_action_screenshot_label));
+ }
+
+ /**
+ * This method is called to register a system action. If a system action is already registered
+ * with the given id, the existing system action will be overwritten.
+ */
+ void registerSystemAction(int id, RemoteAction action) {
+ synchronized (mSystemActionLock) {
+ mRegisteredSystemActions.put(id, action);
+ }
+ if (mListener != null) {
+ mListener.onSystemActionsChanged();
+ }
+ }
+
+ /**
+ * This method is called to unregister a system action previously registered through
+ * registerSystemAction.
+ */
+ void unregisterSystemAction(int id) {
+ synchronized (mSystemActionLock) {
+ mRegisteredSystemActions.remove(id);
+ }
+ if (mListener != null) {
+ mListener.onSystemActionsChanged();
+ }
}
/**
- * Performe the system action matching the given action id.
+ * This method returns the list of available system actions.
*/
- public boolean performSystemAction(int action) {
+ List<AccessibilityAction> getSystemActions() {
+ List<AccessibilityAction> systemActions = new ArrayList<>();
+ synchronized (mSystemActionLock) {
+ for (Map.Entry<Integer, RemoteAction> entry : mRegisteredSystemActions.entrySet()) {
+ AccessibilityAction systemAction = new AccessibilityAction(
+ entry.getKey(),
+ entry.getValue().getTitle());
+ systemActions.add(systemAction);
+ }
+
+ // add AccessibilitySystemAction entry for legacy system actions if not overwritten
+ addLegacySystemActions(systemActions);
+ }
+ return systemActions;
+ }
+
+ private void addLegacySystemActions(List<AccessibilityAction> systemActions) {
+ if (!mRegisteredSystemActions.containsKey(AccessibilityService.GLOBAL_ACTION_BACK)) {
+ systemActions.add(mLegacyBackAction);
+ }
+ if (!mRegisteredSystemActions.containsKey(AccessibilityService.GLOBAL_ACTION_HOME)) {
+ systemActions.add(mLegacyHomeAction);
+ }
+ if (!mRegisteredSystemActions.containsKey(AccessibilityService.GLOBAL_ACTION_RECENTS)) {
+ systemActions.add(mLegacyRecentsAction);
+ }
+ if (!mRegisteredSystemActions.containsKey(
+ AccessibilityService.GLOBAL_ACTION_NOTIFICATIONS)) {
+ systemActions.add(mLegacyNotificationsAction);
+ }
+ if (!mRegisteredSystemActions.containsKey(
+ AccessibilityService.GLOBAL_ACTION_QUICK_SETTINGS)) {
+ systemActions.add(mLegacyQuickSettingsAction);
+ }
+ if (!mRegisteredSystemActions.containsKey(
+ AccessibilityService.GLOBAL_ACTION_POWER_DIALOG)) {
+ systemActions.add(mLegacyPowerDialogAction);
+ }
+ if (!mRegisteredSystemActions.containsKey(
+ AccessibilityService.GLOBAL_ACTION_TOGGLE_SPLIT_SCREEN)) {
+ systemActions.add(mLegacyToggleSplitScreenAction);
+ }
+ if (!mRegisteredSystemActions.containsKey(
+ AccessibilityService.GLOBAL_ACTION_LOCK_SCREEN)) {
+ systemActions.add(mLegacyLockScreenAction);
+ }
+ if (!mRegisteredSystemActions.containsKey(
+ AccessibilityService.GLOBAL_ACTION_TAKE_SCREENSHOT)) {
+ systemActions.add(mLegacyTakeScreenshotAction);
+ }
+ }
+
+ /**
+ * Trigger the registered action by the matching action id.
+ */
+ public boolean performSystemAction(int actionId) {
final long identity = Binder.clearCallingIdentity();
try {
- switch (action) {
+ synchronized (mSystemActionLock) {
+ // If a system action is registered with the given actionId, call the corresponding
+ // RemoteAction.
+ RemoteAction registeredAction = mRegisteredSystemActions.get(actionId);
+ if (registeredAction != null) {
+ try {
+ registeredAction.getActionIntent().send();
+ return true;
+ } catch (PendingIntent.CanceledException ex) {
+ Slog.e(TAG,
+ "canceled PendingIntent for global action "
+ + registeredAction.getTitle(),
+ ex);
+ }
+ return false;
+ }
+ }
+
+ // No RemoteAction registered with the given actionId, try the default legacy system
+ // actions.
+ switch (actionId) {
case AccessibilityService.GLOBAL_ACTION_BACK: {
sendDownAndUpKeyEvents(KeyEvent.KEYCODE_BACK);
+ return true;
}
- return true;
case AccessibilityService.GLOBAL_ACTION_HOME: {
sendDownAndUpKeyEvents(KeyEvent.KEYCODE_HOME);
+ return true;
}
- return true;
- case AccessibilityService.GLOBAL_ACTION_RECENTS: {
+ case AccessibilityService.GLOBAL_ACTION_RECENTS:
return openRecents();
- }
case AccessibilityService.GLOBAL_ACTION_NOTIFICATIONS: {
expandNotifications();
+ return true;
}
- return true;
case AccessibilityService.GLOBAL_ACTION_QUICK_SETTINGS: {
expandQuickSettings();
+ return true;
}
- return true;
case AccessibilityService.GLOBAL_ACTION_POWER_DIALOG: {
showGlobalActions();
+ return true;
}
- return true;
- case AccessibilityService.GLOBAL_ACTION_TOGGLE_SPLIT_SCREEN: {
+ case AccessibilityService.GLOBAL_ACTION_TOGGLE_SPLIT_SCREEN:
return toggleSplitScreen();
- }
- case AccessibilityService.GLOBAL_ACTION_LOCK_SCREEN: {
+ case AccessibilityService.GLOBAL_ACTION_LOCK_SCREEN:
return lockScreen();
- }
- case AccessibilityService.GLOBAL_ACTION_TAKE_SCREENSHOT: {
+ case AccessibilityService.GLOBAL_ACTION_TAKE_SCREENSHOT:
return takeScreenshot();
- }
+ default:
+ return false;
}
- return false;
} finally {
Binder.restoreCallingIdentity(identity);
}
diff --git a/services/core/java/com/android/server/OWNERS b/services/core/java/com/android/server/OWNERS
index a9c38bcf2532..76e0c137d2f5 100644
--- a/services/core/java/com/android/server/OWNERS
+++ b/services/core/java/com/android/server/OWNERS
@@ -4,3 +4,6 @@ per-file ConnectivityService.java,NetworkManagementService.java,NsdService.java
# Vibrator / Threads
per-file VibratorService.java, DisplayThread.java = michaelwr@google.com
per-file VibratorService.java, DisplayThread.java = ogunwale@google.com
+
+# Zram writeback
+per-file ZramWriteback.java = minchan@google.com, rajekumar@google.com, srnvs@google.com
diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java
index 9875f6db749c..1f7d9eab9675 100644
--- a/services/core/java/com/android/server/TelephonyRegistry.java
+++ b/services/core/java/com/android/server/TelephonyRegistry.java
@@ -17,6 +17,8 @@
package com.android.server;
import static android.telephony.TelephonyManager.ACTION_MULTI_SIM_CONFIG_CHANGED;
+import static android.telephony.TelephonyRegistryManager.SIM_ACTIVATION_TYPE_DATA;
+import static android.telephony.TelephonyRegistryManager.SIM_ACTIVATION_TYPE_VOICE;
import static java.util.Arrays.copyOf;
@@ -1201,10 +1203,10 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
synchronized (mRecords) {
if (validatePhoneId(phoneId)) {
switch (activationType) {
- case TelephonyManager.SIM_ACTIVATION_TYPE_VOICE:
+ case SIM_ACTIVATION_TYPE_VOICE:
mVoiceActivationState[phoneId] = activationState;
break;
- case TelephonyManager.SIM_ACTIVATION_TYPE_DATA:
+ case SIM_ACTIVATION_TYPE_DATA:
mDataActivationState[phoneId] = activationState;
break;
default:
@@ -1217,10 +1219,10 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
+ " state=" + activationState);
}
try {
- if ((activationType == TelephonyManager.SIM_ACTIVATION_TYPE_VOICE) &&
- r.matchPhoneStateListenerEvent(
- PhoneStateListener.LISTEN_VOICE_ACTIVATION_STATE) &&
- idMatch(r.subId, subId, phoneId)) {
+ if ((activationType == SIM_ACTIVATION_TYPE_VOICE)
+ && r.matchPhoneStateListenerEvent(
+ PhoneStateListener.LISTEN_VOICE_ACTIVATION_STATE)
+ && idMatch(r.subId, subId, phoneId)) {
if (DBG) {
log("notifyVoiceActivationStateForPhoneId: callback.onVASC r=" + r
+ " subId=" + subId + " phoneId=" + phoneId
@@ -1228,10 +1230,10 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
}
r.callback.onVoiceActivationStateChanged(activationState);
}
- if ((activationType == TelephonyManager.SIM_ACTIVATION_TYPE_DATA) &&
- r.matchPhoneStateListenerEvent(
- PhoneStateListener.LISTEN_DATA_ACTIVATION_STATE) &&
- idMatch(r.subId, subId, phoneId)) {
+ if ((activationType == SIM_ACTIVATION_TYPE_DATA)
+ && r.matchPhoneStateListenerEvent(
+ PhoneStateListener.LISTEN_DATA_ACTIVATION_STATE)
+ && idMatch(r.subId, subId, phoneId)) {
if (DBG) {
log("notifyDataActivationStateForPhoneId: callback.onDASC r=" + r
+ " subId=" + subId + " phoneId=" + phoneId
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 53a5fc6c203a..663e8a2929a0 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -8365,6 +8365,31 @@ public class ActivityManagerService extends IActivityManager.Stub
requestBugReportWithDescription(null, null, BugreportParams.BUGREPORT_MODE_REMOTE);
}
+ /**
+ * Launches a bugreport-whitelisted app to handle a bugreport.
+ *
+ * <p>Allows a bug report handler app to take bugreports on the user's behalf. The handler can
+ * be predefined in the config, meant to be launched with the primary user. The user can
+ * override this with a different (or same) handler app on possibly a different user. This is
+ * useful for capturing bug reports from work profile, for instance.
+ *
+ * @return true if there is a bugreport-whitelisted app to handle a bugreport, or false
+ * otherwise.
+ */
+ @Override
+ public boolean launchBugReportHandlerApp() {
+ if (!BugReportHandlerUtil.isBugReportHandlerEnabled(mContext)) {
+ return false;
+ }
+
+ // Always log caller, even if it does not have permission to dump.
+ Slog.i(TAG, "launchBugReportHandlerApp requested by UID " + Binder.getCallingUid());
+ enforceCallingPermission(android.Manifest.permission.DUMP,
+ "launchBugReportHandlerApp");
+
+ return BugReportHandlerUtil.launchBugReportHandlerApp(mContext);
+ }
+
public void registerProcessObserver(IProcessObserver observer) {
enforceCallingPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER,
"registerProcessObserver()");
diff --git a/services/core/java/com/android/server/am/BugReportHandlerUtil.java b/services/core/java/com/android/server/am/BugReportHandlerUtil.java
new file mode 100644
index 000000000000..ba89fce0b3f8
--- /dev/null
+++ b/services/core/java/com/android/server/am/BugReportHandlerUtil.java
@@ -0,0 +1,179 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.am;
+
+import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
+import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
+
+import android.app.BroadcastOptions;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.os.Binder;
+import android.os.UserHandle;
+import android.provider.Settings;
+import android.text.TextUtils;
+import android.util.ArraySet;
+import android.util.Slog;
+
+import com.android.server.SystemConfig;
+
+import java.util.List;
+
+/**
+ * Static utility methods related to BugReportHandler.
+ */
+public final class BugReportHandlerUtil {
+ private static final String TAG = TAG_WITH_CLASS_NAME ? "BugReportHandlerUtil" : TAG_AM;
+ private static final String SHELL_APP_PACKAGE = "com.android.shell";
+ private static final String INTENT_BUGREPORT_REQUESTED =
+ "com.android.internal.intent.action.BUGREPORT_REQUESTED";
+
+ /**
+ * Check is BugReportHandler enabled on the device.
+ *
+ * @param context Context
+ * @return true if BugReportHandler is enabled, or false otherwise
+ */
+ static boolean isBugReportHandlerEnabled(Context context) {
+ return context.getResources().getBoolean(
+ com.android.internal.R.bool.config_bugReportHandlerEnabled);
+ }
+
+ /**
+ * Launches a bugreport-whitelisted app to handle a bugreport.
+ *
+ * <p>Allows a bug report handler app to take bugreports on the user's behalf. The handler can
+ * be predefined in the config, meant to be launched with the primary user. The user can
+ * override this with a different (or same) handler app on possibly a different user. This is
+ * useful for capturing bug reports from work profile, for instance.
+ *
+ * @param context Context
+ * @return true if there is a bugreport-whitelisted app to handle a bugreport, or false
+ * otherwise
+ */
+ static boolean launchBugReportHandlerApp(Context context) {
+ if (!isBugReportHandlerEnabled(context)) {
+ return false;
+ }
+
+ String handlerApp = getCustomBugReportHandlerApp(context);
+ if (isShellApp(handlerApp)) {
+ return false;
+ }
+
+ int handlerUser = getCustomBugReportHandlerUser(context);
+ if (!isValidBugReportHandlerApp(handlerApp)) {
+ handlerApp = getDefaultBugReportHandlerApp(context);
+ handlerUser = UserHandle.USER_SYSTEM;
+ } else if (getBugReportHandlerAppReceivers(context, handlerApp, handlerUser).isEmpty()) {
+ // It looks like the settings are outdated, reset outdated settings.
+ //
+ // i.e.
+ // If user chooses which profile and which bugreport-whitelisted app in that
+ // profile to handle a bugreport, then user remove the profile.
+ // === RESULT ===
+ // The chosen bugreport handler app is outdated because the profile is removed,
+ // so reset the chosen app and profile
+ handlerApp = getDefaultBugReportHandlerApp(context);
+ handlerUser = UserHandle.USER_SYSTEM;
+ resetCustomBugreportHandlerAppAndUser(context);
+ }
+
+ if (isShellApp(handlerApp) || !isValidBugReportHandlerApp(handlerApp)
+ || getBugReportHandlerAppReceivers(context, handlerApp, handlerUser).isEmpty()) {
+ return false;
+ }
+
+ Slog.i(TAG, "Launching bug report handler app: " + handlerApp);
+ Intent intent = new Intent(INTENT_BUGREPORT_REQUESTED);
+ intent.setPackage(handlerApp);
+ intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
+ intent.addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
+ // Send broadcast to the receiver while allowing starting activity from background
+ final BroadcastOptions options = BroadcastOptions.makeBasic();
+ options.setBackgroundActivityStartsAllowed(true);
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ context.sendBroadcastAsUser(intent, UserHandle.of(handlerUser),
+ android.Manifest.permission.DUMP,
+ options.toBundle());
+ } catch (RuntimeException e) {
+ Slog.e(TAG, "Error while trying to launch bugreport handler app.", e);
+ return false;
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ return true;
+ }
+
+ private static String getCustomBugReportHandlerApp(Context context) {
+ // Get the package of custom bugreport handler app
+ return Settings.Global.getString(context.getContentResolver(),
+ Settings.Global.CUSTOM_BUGREPORT_HANDLER_APP);
+ }
+
+ private static int getCustomBugReportHandlerUser(Context context) {
+ return Settings.Global.getInt(context.getContentResolver(),
+ Settings.Global.CUSTOM_BUGREPORT_HANDLER_USER, UserHandle.USER_NULL);
+ }
+
+ private static boolean isShellApp(String app) {
+ return SHELL_APP_PACKAGE.equals(app);
+ }
+
+ private static boolean isValidBugReportHandlerApp(String app) {
+ return !TextUtils.isEmpty(app) && isBugreportWhitelistedApp(app);
+ }
+
+ private static boolean isBugreportWhitelistedApp(String app) {
+ // Verify the app is bugreport-whitelisted
+ final ArraySet<String> whitelistedApps = SystemConfig.getInstance()
+ .getBugreportWhitelistedPackages();
+ return whitelistedApps.contains(app);
+ }
+
+ private static List<ResolveInfo> getBugReportHandlerAppReceivers(Context context,
+ String handlerApp, int handlerUser) {
+ // Use the app package and the user id to retrieve the receiver that can handle a
+ // broadcast of the intent.
+ Intent intent = new Intent(INTENT_BUGREPORT_REQUESTED);
+ intent.setPackage(handlerApp);
+ return context.getPackageManager()
+ .queryBroadcastReceiversAsUser(intent, PackageManager.MATCH_SYSTEM_ONLY,
+ handlerUser);
+ }
+
+ private static String getDefaultBugReportHandlerApp(Context context) {
+ return context.getResources().getString(
+ com.android.internal.R.string.config_defaultBugReportHandlerApp);
+ }
+
+ private static void resetCustomBugreportHandlerAppAndUser(Context context) {
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ Settings.Global.putString(context.getContentResolver(),
+ Settings.Global.CUSTOM_BUGREPORT_HANDLER_APP,
+ getDefaultBugReportHandlerApp(context));
+ Settings.Global.putInt(context.getContentResolver(),
+ Settings.Global.CUSTOM_BUGREPORT_HANDLER_USER, UserHandle.USER_SYSTEM);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/am/OomAdjuster.java b/services/core/java/com/android/server/am/OomAdjuster.java
index 0591704a0502..12f46569bd20 100644
--- a/services/core/java/com/android/server/am/OomAdjuster.java
+++ b/services/core/java/com/android/server/am/OomAdjuster.java
@@ -376,7 +376,11 @@ public final class OomAdjuster {
ConnectionRecord cr = pr.connections.valueAt(i);
ProcessRecord service = (cr.flags & ServiceInfo.FLAG_ISOLATED_PROCESS) != 0
? cr.binding.service.isolatedProc : cr.binding.service.app;
- if (service == null || service == pr || (containsCycle |= service.mReachable)) {
+ if (service == null || service == pr) {
+ continue;
+ }
+ containsCycle |= service.mReachable;
+ if (service.mReachable) {
continue;
}
if ((cr.flags & (Context.BIND_WAIVE_PRIORITY
@@ -394,6 +398,10 @@ public final class OomAdjuster {
if (provider == null || provider == pr || (containsCycle |= provider.mReachable)) {
continue;
}
+ containsCycle |= provider.mReachable;
+ if (provider.mReachable) {
+ continue;
+ }
queue.offer(provider);
provider.mReachable = true;
}
@@ -482,12 +490,15 @@ public final class OomAdjuster {
// need to reset cycle state before calling computeOomAdjLocked because of service conns
for (int i = numProc - 1; i >= 0; i--) {
ProcessRecord app = activeProcesses.get(i);
- app.containsCycle = false;
app.mReachable = false;
- app.setCurRawProcState(PROCESS_STATE_CACHED_EMPTY);
- app.setCurRawAdj(ProcessList.UNKNOWN_ADJ);
- app.setCapability = PROCESS_CAPABILITY_NONE;
- app.resetCachedInfo();
+ // No need to compute again it has been evaluated in previous iteration
+ if (app.adjSeq != mAdjSeq) {
+ app.containsCycle = false;
+ app.setCurRawProcState(PROCESS_STATE_CACHED_EMPTY);
+ app.setCurRawAdj(ProcessList.UNKNOWN_ADJ);
+ app.setCapability = PROCESS_CAPABILITY_NONE;
+ app.resetCachedInfo();
+ }
}
for (int i = numProc - 1; i >= 0; i--) {
ProcessRecord app = activeProcesses.get(i);
diff --git a/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java b/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java
index bc83780ad82d..21795184b1bd 100644
--- a/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java
+++ b/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java
@@ -31,7 +31,6 @@ import android.net.NetworkSpecifier;
import android.net.StringNetworkSpecifier;
import android.net.wifi.WifiInfo;
import android.os.UserHandle;
-import android.telephony.AccessNetworkConstants.TransportType;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
import android.text.TextUtils;
@@ -105,8 +104,7 @@ public class NetworkNotificationManager {
return -1;
}
- // TODO: Remove @TransportType or change it to @Transport.
- private static String getTransportName(@TransportType int transportType) {
+ private static String getTransportName(final int transportType) {
Resources r = Resources.getSystem();
String[] networkTypes = r.getStringArray(R.array.network_switch_type_name);
try {
diff --git a/services/core/java/com/android/server/pm/AppsFilter.java b/services/core/java/com/android/server/pm/AppsFilter.java
index ec11a97cfc30..14ef2d3a38e1 100644
--- a/services/core/java/com/android/server/pm/AppsFilter.java
+++ b/services/core/java/com/android/server/pm/AppsFilter.java
@@ -136,8 +136,11 @@ public class AppsFilter {
DeviceConfig.addOnPropertiesChangedListener(
NAMESPACE_PACKAGE_MANAGER_SERVICE, FgThread.getExecutor(),
properties -> {
- synchronized (FeatureConfigImpl.this) {
- mFeatureEnabled = properties.getBoolean(FILTERING_ENABLED_NAME, false);
+ if (properties.getKeyset().contains(FILTERING_ENABLED_NAME)) {
+ synchronized (FeatureConfigImpl.this) {
+ mFeatureEnabled = properties.getBoolean(FILTERING_ENABLED_NAME,
+ false);
+ }
}
});
}
diff --git a/services/core/java/com/android/server/pm/DataLoaderManagerService.java b/services/core/java/com/android/server/pm/DataLoaderManagerService.java
new file mode 100644
index 000000000000..0719797ed85a
--- /dev/null
+++ b/services/core/java/com/android/server/pm/DataLoaderManagerService.java
@@ -0,0 +1,246 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.pm;
+
+import android.annotation.Nullable;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.IDataLoader;
+import android.content.pm.IDataLoaderManager;
+import android.content.pm.IDataLoaderStatusListener;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.util.Slog;
+import android.util.SparseArray;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.server.SystemService;
+
+import java.util.List;
+
+/**
+ * Data loader manager service manages data loader binder services.
+ *
+ * @hide
+ */
+public class DataLoaderManagerService extends SystemService {
+ private static final String TAG = "DataLoaderManager";
+ private final Context mContext;
+ private final DataLoaderManagerBinderService mBinderService;
+ private final Object mLock = new Object();
+ @GuardedBy("mLock")
+ private SparseArray<DataLoaderServiceConnection> mServiceConnections;
+
+ public DataLoaderManagerService(Context context) {
+ super(context);
+ mContext = context;
+ mBinderService = new DataLoaderManagerBinderService();
+ }
+
+ @Override
+ public void onStart() {
+ publishBinderService(Context.DATA_LOADER_MANAGER_SERVICE, mBinderService);
+ }
+
+ final class DataLoaderManagerBinderService extends IDataLoaderManager.Stub {
+ @Override
+ public boolean initializeDataLoader(int dataLoaderId, Bundle params,
+ IDataLoaderStatusListener listener) {
+ synchronized (mLock) {
+ if (mServiceConnections == null) {
+ mServiceConnections = new SparseArray<>();
+ }
+ if (mServiceConnections.get(dataLoaderId) != null) {
+ Slog.e(TAG, "Data loader of ID=" + dataLoaderId + " already exists.");
+ return false;
+ }
+ }
+ CharSequence packageNameSeq = params.getCharSequence("packageName");
+ if (packageNameSeq == null) {
+ Slog.e(TAG, "Must specify package name.");
+ return false;
+ }
+ String packageName = packageNameSeq.toString();
+ ComponentName dataLoaderComponent = getDataLoaderServiceName(packageName);
+ if (dataLoaderComponent == null) {
+ return false;
+ }
+ // Binds to the specific data loader service
+ DataLoaderServiceConnection connection =
+ new DataLoaderServiceConnection(dataLoaderId, params, listener);
+ Intent intent = new Intent();
+ intent.setComponent(dataLoaderComponent);
+ if (!mContext.bindServiceAsUser(intent, connection, Context.BIND_AUTO_CREATE,
+ UserHandle.of(UserHandle.getCallingUserId()))) {
+ Slog.e(TAG, "Failed to bind to data loader binder service.");
+ mContext.unbindService(connection);
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Find the ComponentName of the data loader service provider, given its package name.
+ *
+ * @param packageName the package name of the provider.
+ * @return ComponentName of the data loader service provider. Null if provider not found.
+ */
+ private @Nullable ComponentName getDataLoaderServiceName(String packageName) {
+ final PackageManager pm = mContext.getPackageManager();
+ if (pm == null) {
+ Slog.e(TAG, "PackageManager is not available.");
+ return null;
+ }
+ Intent intent = new Intent(Intent.ACTION_LOAD_DATA);
+ intent.setPackage(packageName);
+ List<ResolveInfo> services =
+ pm.queryIntentServicesAsUser(intent, 0, UserHandle.getCallingUserId());
+ if (services == null || services.isEmpty()) {
+ Slog.e(TAG,
+ "Failed to find data loader service provider in package " + packageName);
+ return null;
+ }
+
+ // TODO(b/136132412): better way to enable privileged data loaders in tests
+ boolean checkLoader =
+ android.os.SystemProperties.getBoolean("incremental.check_loader", false);
+ int numServices = services.size();
+ for (int i = 0; i < numServices; i++) {
+ ResolveInfo ri = services.get(i);
+ ComponentName componentName = new ComponentName(
+ ri.serviceInfo.packageName, ri.serviceInfo.name);
+ // There should only be one matching provider inside the given package.
+ // If there's more than one, return the first one found.
+ try {
+ ApplicationInfo ai = pm.getApplicationInfo(componentName.getPackageName(), 0);
+ if (checkLoader && !ai.isPrivilegedApp()) {
+ Slog.w(TAG,
+ "Data loader: " + componentName.getPackageName()
+ + " is not a privileged app, skipping.");
+ continue;
+ }
+ return componentName;
+ } catch (PackageManager.NameNotFoundException ex) {
+ Slog.w(TAG,
+ "Privileged data loader: " + componentName.getPackageName()
+ + " not found, skipping.");
+ }
+
+ }
+ Slog.e(TAG, "Didn't find any matching data loader service provider.");
+ return null;
+ }
+
+ /**
+ * Returns the binder object of a data loader, specified by its ID.
+ */
+ @Override
+ public @Nullable IDataLoader getDataLoader(int dataLoaderId) {
+ synchronized (mLock) {
+ if (mServiceConnections == null) {
+ return null;
+ }
+ DataLoaderServiceConnection serviceConnection = mServiceConnections.get(
+ dataLoaderId, null);
+ if (serviceConnection == null) {
+ return null;
+ }
+ return serviceConnection.getDataLoader();
+ }
+ }
+
+ /**
+ * Destroys a data loader binder service, specified by its ID.
+ */
+ @Override
+ public void destroyDataLoader(int dataLoaderId) {
+ synchronized (mLock) {
+ if (mServiceConnections == null) {
+ return;
+ }
+ DataLoaderServiceConnection serviceConnection = mServiceConnections.get(
+ dataLoaderId, null);
+
+ if (serviceConnection == null) {
+ return;
+ }
+ serviceConnection.destroy();
+ }
+ }
+ }
+
+ class DataLoaderServiceConnection implements ServiceConnection {
+ final int mId;
+ final Bundle mParams;
+ final IDataLoaderStatusListener mListener;
+ IDataLoader mDataLoader;
+
+ DataLoaderServiceConnection(int id, Bundle params, IDataLoaderStatusListener listener) {
+ mId = id;
+ mParams = params;
+ mListener = listener;
+ mDataLoader = null;
+ }
+
+ @Override
+ public void onServiceConnected(ComponentName className, IBinder service) {
+ mDataLoader = IDataLoader.Stub.asInterface(service);
+ synchronized (mLock) {
+ mServiceConnections.append(mId, this);
+ }
+ try {
+ mDataLoader.create(mId, mParams, mListener);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Failed to create data loader service.", e);
+ }
+ }
+
+ @Override
+ public void onServiceDisconnected(ComponentName arg0) {
+ remove();
+ }
+
+ IDataLoader getDataLoader() {
+ return mDataLoader;
+ }
+
+ void destroy() {
+ try {
+ mDataLoader.destroy();
+ } catch (RemoteException ignored) {
+ }
+ mContext.unbindService(this);
+ }
+
+ private void remove() {
+ synchronized (mLock) {
+ mServiceConnections.remove(mId);
+ if (mServiceConnections.size() == 0) {
+ mServiceConnections = null;
+ }
+ }
+ mParams.clear();
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index 4852947619f9..883baf7886af 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -54,6 +54,7 @@ import android.content.IntentSender;
import android.content.pm.ApplicationInfo;
import android.content.pm.IPackageInstallObserver2;
import android.content.pm.IPackageInstallerSession;
+import android.content.pm.InstallationFile;
import android.content.pm.PackageInfo;
import android.content.pm.PackageInstaller;
import android.content.pm.PackageInstaller.SessionInfo;
@@ -81,6 +82,8 @@ import android.os.Process;
import android.os.RevocableFileDescriptor;
import android.os.SystemProperties;
import android.os.UserHandle;
+import android.os.incremental.IncrementalFileStorages;
+import android.os.incremental.IncrementalManager;
import android.os.storage.StorageManager;
import android.stats.devicepolicy.DevicePolicyEnums;
import android.system.ErrnoException;
@@ -309,6 +312,8 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
@GuardedBy("mLock")
private boolean mVerityFound;
+ private IncrementalFileStorages mIncrementalFileStorages;
+
private static final FileFilter sAddedFilter = new FileFilter() {
@Override
public boolean accept(File file) {
@@ -471,6 +476,18 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
mStagedSessionErrorCode = stagedSessionErrorCode;
mStagedSessionErrorMessage =
stagedSessionErrorMessage != null ? stagedSessionErrorMessage : "";
+
+ // TODO(b/136132412): sanity check if session should not be incremental
+ if (!params.isStaged && params.incrementalParams != null
+ && !params.incrementalParams.getPackageName().isEmpty()) {
+ IncrementalManager incrementalManager = (IncrementalManager) mContext.getSystemService(
+ Context.INCREMENTAL_SERVICE);
+ if (incrementalManager != null) {
+ mIncrementalFileStorages =
+ new IncrementalFileStorages(mPackageName, stageDir, incrementalManager,
+ params.incrementalParams);
+ }
+ }
}
public SessionInfo generateInfo() {
@@ -874,10 +891,18 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
}
}
+ if (mIncrementalFileStorages != null) {
+ mIncrementalFileStorages.finishSetUp();
+ }
+
mHandler.obtainMessage(MSG_SEAL, statusReceiver).sendToTarget();
}
private void handleSeal(@NonNull IntentSender statusReceiver) {
+ // TODO(b/136132412): update with new APIs
+ if (mIncrementalFileStorages != null) {
+ mIncrementalFileStorages.startLoading();
+ }
if (!markAsCommitted(statusReceiver)) {
return;
}
@@ -1492,6 +1517,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
computeProgressLocked(true);
// Unpack native libraries
+ // TODO(b/136132412): skip for incremental installation
extractNativeLibraries(stageDir, params.abiOverride, mayInheritNativeLibs());
}
@@ -2182,7 +2208,6 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
}
destroyInternal();
}
-
dispatchSessionFinished(INSTALL_FAILED_ABORTED, "Session was abandoned", null);
}
@@ -2268,6 +2293,20 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
return mParentSessionId;
}
+ @Override
+ public void addFile(@NonNull String name, long size, @NonNull byte[] metadata) {
+ if (mIncrementalFileStorages == null) {
+ throw new IllegalStateException(
+ "Cannot add Incremental File to a non-Incremental session.");
+ }
+ try {
+ mIncrementalFileStorages.addFile(new InstallationFile(name, size, metadata));
+ } catch (IOException ex) {
+ throw new IllegalStateException(
+ "Failed to add and configure Incremental File: " + name, ex);
+ }
+ }
+
private void dispatchSessionFinished(int returnCode, String msg, Bundle extras) {
final IntentSender statusReceiver;
final String packageName;
@@ -2390,6 +2429,9 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
// since these packages are supposed to be read on reboot.
// Those dirs are deleted when the staged session has reached a final state.
if (stageDir != null && !params.isStaged) {
+ if (mIncrementalFileStorages != null) {
+ mIncrementalFileStorages.cleanUp();
+ }
try {
mPm.mInstaller.rmPackageDir(stageDir.getAbsolutePath());
} catch (InstallerException ignored) {
@@ -2403,6 +2445,9 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
mSessionProvider.getSession(childSessionId).cleanStageDir();
}
} else {
+ if (mIncrementalFileStorages != null) {
+ mIncrementalFileStorages.cleanUp();
+ }
try {
mPm.mInstaller.rmPackageDir(stageDir.getAbsolutePath());
} catch (InstallerException ignored) {
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 4e0e4ffb3a13..c5e79426a421 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -153,6 +153,7 @@ import android.content.pm.IPackageManager;
import android.content.pm.IPackageManagerNative;
import android.content.pm.IPackageMoveObserver;
import android.content.pm.IPackageStatsObserver;
+import android.content.pm.InstallSourceInfo;
import android.content.pm.InstantAppInfo;
import android.content.pm.InstantAppRequest;
import android.content.pm.InstrumentationInfo;
@@ -20128,17 +20129,93 @@ public class PackageManagerService extends IPackageManager.Stub
public String getInstallerPackageName(String packageName) {
final int callingUid = Binder.getCallingUid();
synchronized (mLock) {
- final PackageSetting ps = mSettings.mPackages.get(packageName);
- if (shouldFilterApplicationLocked(
- ps, callingUid, UserHandle.getUserId(callingUid))) {
- return null;
+ final InstallSource installSource = getInstallSourceLocked(packageName, callingUid);
+ if (installSource == null) {
+ throw new IllegalArgumentException("Unknown package: " + packageName);
}
- // InstallerPackageName for Apex is not stored in PackageManager
- if (ps == null && mApexManager.isApexPackage(packageName)) {
+ String installerPackageName = installSource.installerPackageName;
+ if (installerPackageName != null) {
+ final PackageSetting ps = mSettings.mPackages.get(installerPackageName);
+ if (ps == null || shouldFilterApplicationLocked(ps, callingUid,
+ UserHandle.getUserId(callingUid))) {
+ installerPackageName = null;
+ }
+ }
+ return installerPackageName;
+ }
+ }
+
+ @Override
+ @Nullable
+ public InstallSourceInfo getInstallSourceInfo(String packageName) {
+ final int callingUid = Binder.getCallingUid();
+ final int userId = UserHandle.getUserId(callingUid);
+
+ String installerPackageName;
+ String initiatingPackageName;
+ String originatingPackageName;
+
+ synchronized (mLock) {
+ final InstallSource installSource = getInstallSourceLocked(packageName, callingUid);
+ if (installSource == null) {
return null;
}
- return mSettings.getInstallerPackageNameLPr(packageName);
+
+ installerPackageName = installSource.installerPackageName;
+ if (installerPackageName != null) {
+ final PackageSetting ps = mSettings.mPackages.get(installerPackageName);
+ if (ps == null || shouldFilterApplicationLocked(ps, callingUid, userId)) {
+ installerPackageName = null;
+ }
+ }
+
+ // All installSource strings are interned, so == is ok here
+ if (installSource.initiatingPackageName == installSource.installerPackageName) {
+ // The installer and initiator will often be the same, and when they are
+ // we can skip doing the same check again.
+ initiatingPackageName = installerPackageName;
+ } else {
+ initiatingPackageName = installSource.initiatingPackageName;
+ final PackageSetting ps = mSettings.mPackages.get(initiatingPackageName);
+ if (ps == null || shouldFilterApplicationLocked(ps, callingUid, userId)) {
+ initiatingPackageName = null;
+ }
+
+ }
+ originatingPackageName = installSource.originatingPackageName;
+ if (originatingPackageName != null) {
+ final PackageSetting ps = mSettings.mPackages.get(originatingPackageName);
+ if (ps == null || shouldFilterApplicationLocked(ps, callingUid, userId)) {
+ originatingPackageName = null;
+ }
+ }
+ }
+
+ if (originatingPackageName != null && mContext.checkCallingOrSelfPermission(
+ Manifest.permission.INSTALL_PACKAGES) != PackageManager.PERMISSION_GRANTED) {
+ originatingPackageName = null;
}
+
+ return new InstallSourceInfo(initiatingPackageName, originatingPackageName,
+ installerPackageName);
+ }
+
+ @GuardedBy("mLock")
+ @Nullable
+ private InstallSource getInstallSourceLocked(String packageName, int callingUid) {
+ final PackageSetting ps = mSettings.mPackages.get(packageName);
+
+ // Installer info for Apex is not stored in PackageManager
+ if (ps == null && mApexManager.isApexPackage(packageName)) {
+ return InstallSource.EMPTY;
+ }
+
+ if (ps == null || shouldFilterApplicationLocked(ps, callingUid,
+ UserHandle.getUserId(callingUid))) {
+ return null;
+ }
+
+ return ps.installSource;
}
public boolean isOrphaned(String packageName) {
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index f67d3c0f7523..6e67687ae6d7 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -4257,14 +4257,6 @@ public final class Settings {
return userState.isMatch(componentInfo, flags);
}
- String getInstallerPackageNameLPr(String packageName) {
- final PackageSetting pkg = mPackages.get(packageName);
- if (pkg == null) {
- throw new IllegalArgumentException("Unknown package: " + packageName);
- }
- return pkg.installSource.installerPackageName;
- }
-
boolean isOrphaned(String packageName) {
final PackageSetting pkg = mPackages.get(packageName);
if (pkg == null) {
diff --git a/services/core/java/com/android/server/policy/PermissionPolicyService.java b/services/core/java/com/android/server/policy/PermissionPolicyService.java
index 3c4e3f64a52e..9b9f93f7b5c4 100644
--- a/services/core/java/com/android/server/policy/PermissionPolicyService.java
+++ b/services/core/java/com/android/server/policy/PermissionPolicyService.java
@@ -29,10 +29,8 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
import android.app.AppOpsManager;
-import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
-import android.content.IntentFilter;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
@@ -171,23 +169,6 @@ public final class PermissionPolicyService extends SystemService {
} catch (RemoteException doesNotHappen) {
Slog.wtf(LOG_TAG, "Cannot set up app-ops listener");
}
-
- IntentFilter intentFilter = new IntentFilter();
- intentFilter.addAction(Intent.ACTION_PACKAGE_CHANGED);
- intentFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
- intentFilter.addDataScheme("package");
-
- getContext().registerReceiverAsUser(new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- UserHandle user =
- UserHandle.getUserHandleForUid(intent.getIntExtra(Intent.EXTRA_UID, -1));
- new PermissionControllerManager(
- getUserContext(getContext(), user), FgThread.getHandler())
- .updateUserSensitive();
- }
- }, UserHandle.ALL, intentFilter, null, null);
-
}
/**
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index 114a16a96f07..14617d38739e 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -203,8 +203,11 @@ public final class PowerManagerService extends SystemService
// System Property indicating that retail demo mode is currently enabled.
private static final String SYSTEM_PROPERTY_RETAIL_DEMO_ENABLED = "sys.retaildemo.enabled";
- // Possible reasons for shutting down or reboot for use in REBOOT_PROPERTY(sys.boot.reason)
- // which is set by bootstat
+ // System property for last reboot reason
+ private static final String SYSTEM_PROPERTY_REBOOT_REASON = "sys.boot.reason";
+
+ // Possible reasons for shutting down or reboot for use in
+ // SYSTEM_PROPERTY_REBOOT_REASON(sys.boot.reason) which is set by bootstat
private static final String REASON_SHUTDOWN = "shutdown";
private static final String REASON_REBOOT = "reboot";
private static final String REASON_USERREQUESTED = "shutdown,userrequested";
@@ -225,9 +228,6 @@ public final class PowerManagerService extends SystemService
private static final int HALT_MODE_REBOOT = 1;
private static final int HALT_MODE_REBOOT_SAFE_MODE = 2;
- // property for last reboot reason
- private static final String REBOOT_PROPERTY = "sys.boot.reason";
-
private final Context mContext;
private final ServiceThread mHandlerThread;
private final PowerManagerHandler mHandler;
@@ -240,6 +240,7 @@ public final class PowerManagerService extends SystemService
private final BinderService mBinderService;
private final LocalService mLocalService;
private final NativeWrapper mNativeWrapper;
+ private final SystemPropertiesWrapper mSystemProperties;
private final Injector mInjector;
private LightsManager mLightsManager;
@@ -756,6 +757,20 @@ public final class PowerManagerService extends SystemService
InattentiveSleepWarningController createInattentiveSleepWarningController() {
return new InattentiveSleepWarningController();
}
+
+ public SystemPropertiesWrapper createSystemPropertiesWrapper() {
+ return new SystemPropertiesWrapper() {
+ @Override
+ public String get(String key, String def) {
+ return SystemProperties.get(key, def);
+ }
+
+ @Override
+ public void set(String key, String val) {
+ SystemProperties.set(key, val);
+ }
+ };
+ }
}
final Constants mConstants;
@@ -781,6 +796,7 @@ public final class PowerManagerService extends SystemService
mBinderService = new BinderService();
mLocalService = new LocalService();
mNativeWrapper = injector.createNativeWrapper();
+ mSystemProperties = injector.createSystemPropertiesWrapper();
mInjector = injector;
mHandlerThread = new ServiceThread(TAG,
@@ -816,7 +832,7 @@ public final class PowerManagerService extends SystemService
mHalInteractiveModeEnabled = true;
mWakefulness = WAKEFULNESS_AWAKE;
- sQuiescent = SystemProperties.get(SYSTEM_PROPERTY_QUIESCENT, "0").equals("1");
+ sQuiescent = mSystemProperties.get(SYSTEM_PROPERTY_QUIESCENT, "0").equals("1");
mNativeWrapper.nativeInit(this);
mNativeWrapper.nativeSetAutoSuspend(false);
@@ -1067,8 +1083,9 @@ public final class PowerManagerService extends SystemService
}
final String retailDemoValue = UserManager.isDeviceInDemoMode(mContext) ? "1" : "0";
- if (!retailDemoValue.equals(SystemProperties.get(SYSTEM_PROPERTY_RETAIL_DEMO_ENABLED))) {
- SystemProperties.set(SYSTEM_PROPERTY_RETAIL_DEMO_ENABLED, retailDemoValue);
+ if (!retailDemoValue.equals(
+ mSystemProperties.get(SYSTEM_PROPERTY_RETAIL_DEMO_ENABLED, null))) {
+ mSystemProperties.set(SYSTEM_PROPERTY_RETAIL_DEMO_ENABLED, retailDemoValue);
}
mScreenBrightnessModeSetting = Settings.System.getIntForUser(resolver,
@@ -4820,7 +4837,7 @@ public final class PowerManagerService extends SystemService
final long ident = Binder.clearCallingIdentity();
try {
- return getLastShutdownReasonInternal(REBOOT_PROPERTY);
+ return getLastShutdownReasonInternal();
} finally {
Binder.restoreCallingIdentity(ident);
}
@@ -5054,12 +5071,8 @@ public final class PowerManagerService extends SystemService
}
@VisibleForTesting
- // lastRebootReasonProperty argument to permit testing
- int getLastShutdownReasonInternal(String lastRebootReasonProperty) {
- String line = SystemProperties.get(lastRebootReasonProperty);
- if (line == null) {
- return PowerManager.SHUTDOWN_REASON_UNKNOWN;
- }
+ int getLastShutdownReasonInternal() {
+ String line = mSystemProperties.get(SYSTEM_PROPERTY_REBOOT_REASON, null);
switch (line) {
case REASON_SHUTDOWN:
return PowerManager.SHUTDOWN_REASON_SHUTDOWN;
diff --git a/services/core/java/com/android/server/power/SystemPropertiesWrapper.java b/services/core/java/com/android/server/power/SystemPropertiesWrapper.java
new file mode 100644
index 000000000000..1acf798eb099
--- /dev/null
+++ b/services/core/java/com/android/server/power/SystemPropertiesWrapper.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.power;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.SystemProperties;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+/**
+ * Wrapper interface to access {@link SystemProperties}.
+ *
+ * @hide
+ */
+@VisibleForTesting
+interface SystemPropertiesWrapper {
+ /**
+ * Get the String value for the given {@code key}.
+ *
+ * @param key the key to lookup
+ * @param def the default value in case the property is not set or empty
+ * @return if the {@code key} isn't found, return {@code def} if it isn't null, or an empty
+ * string otherwise
+ */
+ @NonNull
+ String get(@NonNull String key, @Nullable String def);
+
+ /**
+ * Set the value for the given {@code key} to {@code val}.
+ *
+ * @throws IllegalArgumentException if the {@code val} exceeds 91 characters
+ * @throws RuntimeException if the property cannot be set, for example, if it was blocked by
+ * SELinux. libc will log the underlying reason.
+ */
+ void set(@NonNull String key, @Nullable String val);
+}
diff --git a/services/core/java/com/android/server/utils/TimingsTraceAndSlog.java b/services/core/java/com/android/server/utils/TimingsTraceAndSlog.java
index 03c96e99a5ad..6bdb5cea7f9c 100644
--- a/services/core/java/com/android/server/utils/TimingsTraceAndSlog.java
+++ b/services/core/java/com/android/server/utils/TimingsTraceAndSlog.java
@@ -55,7 +55,16 @@ public final class TimingsTraceAndSlog extends TimingsTraceLog {
* Default constructor using {@code system_server} tags.
*/
public TimingsTraceAndSlog() {
- this(SYSTEM_SERVER_TIMING_TAG, Trace.TRACE_TAG_SYSTEM_SERVER);
+ this(SYSTEM_SERVER_TIMING_TAG);
+ }
+
+ /**
+ * Custom constructor using {@code system_server} trace tag.
+ *
+ * @param tag {@code logcat} tag
+ */
+ public TimingsTraceAndSlog(@NonNull String tag) {
+ this(tag, Trace.TRACE_TAG_SYSTEM_SERVER);
}
/**
diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
index d66aa18950d0..03139d2e5e03 100644
--- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
+++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
@@ -104,6 +104,7 @@ import com.android.server.EventLogTags;
import com.android.server.FgThread;
import com.android.server.LocalServices;
import com.android.server.SystemService;
+import com.android.server.utils.TimingsTraceAndSlog;
import com.android.server.wm.WindowManagerInternal;
import libcore.io.IoUtils;
@@ -1785,25 +1786,26 @@ public class WallpaperManagerService extends IWallpaperManager.Stub
@Override
public void onUnlockUser(final int userId) {
- synchronized (mLock) {
- if (mCurrentUserId == userId) {
- if (mWaitingForUnlock) {
- // the desired wallpaper is not direct-boot aware, load it now
- final WallpaperData systemWallpaper =
- getWallpaperSafeLocked(userId, FLAG_SYSTEM);
- switchWallpaper(systemWallpaper, null);
- notifyCallbacksLocked(systemWallpaper);
- }
-
- // Make sure that the SELinux labeling of all the relevant files is correct.
- // This corrects for mislabeling bugs that might have arisen from move-to
- // operations involving the wallpaper files. This isn't timing-critical,
- // so we do it in the background to avoid holding up the user unlock operation.
- if (!mUserRestorecon.get(userId)) {
- mUserRestorecon.put(userId, true);
- Runnable relabeler = new Runnable() {
- @Override
- public void run() {
+ TimingsTraceAndSlog t = new TimingsTraceAndSlog(TAG);
+ t.traceBegin("on-unlock-user-" + userId);
+ try {
+ synchronized (mLock) {
+ if (mCurrentUserId == userId) {
+ if (mWaitingForUnlock) {
+ // the desired wallpaper is not direct-boot aware, load it now
+ final WallpaperData systemWallpaper =
+ getWallpaperSafeLocked(userId, FLAG_SYSTEM);
+ switchWallpaper(systemWallpaper, null);
+ notifyCallbacksLocked(systemWallpaper);
+ }
+
+ // Make sure that the SELinux labeling of all the relevant files is correct.
+ // This corrects for mislabeling bugs that might have arisen from move-to
+ // operations involving the wallpaper files. This isn't timing-critical,
+ // so we do it in the background to avoid holding up the user unlock operation.
+ if (!mUserRestorecon.get(userId)) {
+ mUserRestorecon.put(userId, true);
+ Runnable relabeler = () -> {
final File wallpaperDir = getWallpaperDir(userId);
for (String filename : sPerUserFiles) {
File f = new File(wallpaperDir, filename);
@@ -1811,11 +1813,13 @@ public class WallpaperManagerService extends IWallpaperManager.Stub
SELinux.restorecon(f);
}
}
- }
- };
- BackgroundThread.getHandler().post(relabeler);
+ };
+ BackgroundThread.getHandler().post(relabeler);
+ }
}
}
+ } finally {
+ t.traceEnd();
}
}
@@ -1833,31 +1837,37 @@ public class WallpaperManagerService extends IWallpaperManager.Stub
}
void switchUser(int userId, IRemoteCallback reply) {
- final WallpaperData systemWallpaper;
- final WallpaperData lockWallpaper;
- synchronized (mLock) {
- if (mCurrentUserId == userId) {
- return;
- }
- mCurrentUserId = userId;
- systemWallpaper = getWallpaperSafeLocked(userId, FLAG_SYSTEM);
- final WallpaperData tmpLockWallpaper = mLockWallpaperMap.get(userId);
- lockWallpaper = tmpLockWallpaper == null ? systemWallpaper : tmpLockWallpaper;
- // Not started watching yet, in case wallpaper data was loaded for other reasons.
- if (systemWallpaper.wallpaperObserver == null) {
- systemWallpaper.wallpaperObserver = new WallpaperObserver(systemWallpaper);
- systemWallpaper.wallpaperObserver.startWatching();
+ TimingsTraceAndSlog t = new TimingsTraceAndSlog(TAG);
+ t.traceBegin("switch-user-" + userId);
+ try {
+ final WallpaperData systemWallpaper;
+ final WallpaperData lockWallpaper;
+ synchronized (mLock) {
+ if (mCurrentUserId == userId) {
+ return;
+ }
+ mCurrentUserId = userId;
+ systemWallpaper = getWallpaperSafeLocked(userId, FLAG_SYSTEM);
+ final WallpaperData tmpLockWallpaper = mLockWallpaperMap.get(userId);
+ lockWallpaper = tmpLockWallpaper == null ? systemWallpaper : tmpLockWallpaper;
+ // Not started watching yet, in case wallpaper data was loaded for other reasons.
+ if (systemWallpaper.wallpaperObserver == null) {
+ systemWallpaper.wallpaperObserver = new WallpaperObserver(systemWallpaper);
+ systemWallpaper.wallpaperObserver.startWatching();
+ }
+ switchWallpaper(systemWallpaper, reply);
}
- switchWallpaper(systemWallpaper, reply);
- }
- // Offload color extraction to another thread since switchUser will be called
- // from the main thread.
- FgThread.getHandler().post(() -> {
- notifyWallpaperColorsChanged(systemWallpaper, FLAG_SYSTEM);
- notifyWallpaperColorsChanged(lockWallpaper, FLAG_LOCK);
- notifyWallpaperColorsChanged(mFallbackWallpaper, FLAG_SYSTEM);
- });
+ // Offload color extraction to another thread since switchUser will be called
+ // from the main thread.
+ FgThread.getHandler().post(() -> {
+ notifyWallpaperColorsChanged(systemWallpaper, FLAG_SYSTEM);
+ notifyWallpaperColorsChanged(lockWallpaper, FLAG_LOCK);
+ notifyWallpaperColorsChanged(mFallbackWallpaper, FLAG_SYSTEM);
+ });
+ } finally {
+ t.traceEnd();
+ }
}
void switchWallpaper(WallpaperData wallpaper, IRemoteCallback reply) {
diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java
index 77e557b87648..2283041367ef 100644
--- a/services/core/java/com/android/server/wm/DisplayPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayPolicy.java
@@ -2215,9 +2215,22 @@ public class DisplayPolicy {
}
private void offsetInputMethodWindowLw(WindowState win, DisplayFrames displayFrames) {
+ final int rotation = displayFrames.mRotation;
+ final int navBarPosition = navigationBarPosition(displayFrames.mDisplayWidth,
+ displayFrames.mDisplayHeight, rotation);
+
int top = Math.max(win.getDisplayFrameLw().top, win.getContentFrameLw().top);
top += win.getGivenContentInsetsLw().top;
displayFrames.mContent.bottom = Math.min(displayFrames.mContent.bottom, top);
+ if (navBarPosition == NAV_BAR_BOTTOM) {
+ // Always account for the nav bar frame height on the bottom since in all navigation
+ // modes we make room to show the dismiss-ime button, even if the IME does not report
+ // insets (ie. when floating)
+ final int uimode = mService.mPolicy.getUiMode();
+ final int navFrameHeight = getNavigationBarFrameHeight(rotation, uimode);
+ displayFrames.mContent.bottom = Math.min(displayFrames.mContent.bottom,
+ displayFrames.mUnrestricted.bottom - navFrameHeight);
+ }
displayFrames.mVoiceContent.bottom = Math.min(displayFrames.mVoiceContent.bottom, top);
top = win.getVisibleFrameLw().top;
top += win.getGivenVisibleInsetsLw().top;
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 88a38e02de6a..6e8d0b71353f 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -968,6 +968,11 @@ class Task extends WindowContainer<WindowContainer> {
final ActivityStack oldStack = ((ActivityStack) oldParent);
final ActivityStack newStack = ((ActivityStack) newParent);
+ // Task is going to be removed, clean it up before detaching from hierarchy.
+ if (oldParent != null && newParent == null) {
+ cleanUpResourcesForDestroy();
+ }
+
mStack = newStack;
super.onParentChanged(newParent, oldParent);
@@ -1012,12 +1017,6 @@ class Task extends WindowContainer<WindowContainer> {
updateOverrideConfigurationFromLaunchBounds();
}
- // Task is being removed.
- if (oldParent != null && newParent == null) {
- cleanUpResourcesForDestroy();
- }
-
-
// Update task bounds if needed.
adjustBoundsForDisplayChangeIfNeeded(getDisplayContent());
diff --git a/services/core/java/com/android/server/wm/WindowManagerInternal.java b/services/core/java/com/android/server/wm/WindowManagerInternal.java
index 46faf3b40f85..ea90e49d879e 100644
--- a/services/core/java/com/android/server/wm/WindowManagerInternal.java
+++ b/services/core/java/com/android/server/wm/WindowManagerInternal.java
@@ -550,4 +550,10 @@ public abstract class WindowManagerInternal {
* the next time the activities are opened.
*/
public abstract void clearSnapshotCache();
+
+ /**
+ * Assigns accessibility ID a window surface as a layer metadata.
+ */
+ public abstract void setAccessibilityIdToSurfaceMetadata(
+ IBinder windowToken, int accessibilityWindowId);
}
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 0a87fdaed3a1..51221dde3101 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -7398,6 +7398,27 @@ public class WindowManagerService extends IWindowManager.Stub
public @Nullable KeyInterceptionInfo getKeyInterceptionInfoFromToken(IBinder inputToken) {
return mKeyInterceptionInfoForToken.get(inputToken);
}
+
+ @Override
+ public void setAccessibilityIdToSurfaceMetadata(
+ IBinder windowToken, int accessibilityWindowId) {
+ synchronized (mGlobalLock) {
+ final WindowState state = mWindowMap.get(windowToken);
+ if (state == null) {
+ Slog.w(TAG, "Cannot find window which accessibility connection is added to");
+ return;
+ }
+ try (SurfaceControl.Transaction t = new SurfaceControl.Transaction()) {
+ t.setMetadata(
+ state.mSurfaceControl,
+ SurfaceControl.METADATA_ACCESSIBILITY_ID,
+ accessibilityWindowId);
+ t.apply();
+ } finally {
+ SurfaceControl.closeTransaction();
+ }
+ }
+ }
}
void registerAppFreezeListener(AppFreezeListener listener) {
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 8cc0736b7537..dcf4b38db8ab 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -35,6 +35,7 @@ import static android.view.WindowInsetsController.BEHAVIOR_SHOW_TRANSIENT_BARS_B
import static android.view.WindowManager.LayoutParams.FIRST_SUB_WINDOW;
import static android.view.WindowManager.LayoutParams.FIRST_SYSTEM_WINDOW;
import static android.view.WindowManager.LayoutParams.FLAG_ALLOW_LOCK_WHILE_SCREEN_ON;
+import static android.view.WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
import static android.view.WindowManager.LayoutParams.FLAG_DIM_BEHIND;
import static android.view.WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD;
import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS;
@@ -2162,12 +2163,13 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
return false;
}
- // Can be an IME target only if:
- // 1. FLAG_NOT_FOCUSABLE is not set
- // 2. FLAG_ALT_FOCUSABLE_IM is not set
- // 3. not a starting window.
- if (!WindowManager.LayoutParams.mayUseInputMethod(mAttrs.flags)
- || mAttrs.type == TYPE_APPLICATION_STARTING) {
+ final int fl = mAttrs.flags & (FLAG_NOT_FOCUSABLE | FLAG_ALT_FOCUSABLE_IM);
+ final int type = mAttrs.type;
+
+ // Can only be an IME target if both FLAG_NOT_FOCUSABLE and FLAG_ALT_FOCUSABLE_IM are set or
+ // both are cleared...and not a starting window.
+ if (fl != 0 && fl != (FLAG_NOT_FOCUSABLE | FLAG_ALT_FOCUSABLE_IM)
+ && type != TYPE_APPLICATION_STARTING) {
return false;
}
diff --git a/services/core/jni/com_android_server_VibratorService.cpp b/services/core/jni/com_android_server_VibratorService.cpp
index 612a1e7074f9..dcff5a11aca0 100644
--- a/services/core/jni/com_android_server_VibratorService.cpp
+++ b/services/core/jni/com_android_server_VibratorService.cpp
@@ -338,7 +338,7 @@ static jlong vibratorPerformEffect(JNIEnv* env, jclass, jlong effect, jlong stre
if (auto hal = getHal<aidl::IVibrator>()) {
int32_t lengthMs;
sp<AidlVibratorCallback> effectCallback = new AidlVibratorCallback(env, vibration);
- aidl::Effect effectType(static_cast<aidl::Effect>(strength));
+ aidl::Effect effectType(static_cast<aidl::Effect>(effect));
aidl::EffectStrength effectStrength(static_cast<aidl::EffectStrength>(strength));
auto status = hal->call(&aidl::IVibrator::perform, effectType, effectStrength, effectCallback, &lengthMs);
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 2499ad816b2d..cb599be82aa6 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -139,6 +139,8 @@ import android.app.admin.SystemUpdatePolicy;
import android.app.backup.IBackupManager;
import android.app.timedetector.ManualTimeSuggestion;
import android.app.timedetector.TimeDetector;
+import android.app.timezonedetector.ManualTimeZoneSuggestion;
+import android.app.timezonedetector.TimeZoneDetector;
import android.app.trust.TrustManager;
import android.app.usage.UsageStatsManagerInternal;
import android.compat.annotation.ChangeId;
@@ -1962,6 +1964,10 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
return mContext.getSystemService(TimeDetector.class);
}
+ TimeZoneDetector getTimeZoneDetector() {
+ return mContext.getSystemService(TimeZoneDetector.class);
+ }
+
ConnectivityManager getConnectivityManager() {
return mContext.getSystemService(ConnectivityManager.class);
}
@@ -2748,6 +2754,9 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
return null;
}
+ // Code for handling failure from getActiveAdminWithPolicyForUidLocked to find an admin
+ // that satisfies the required policy.
+ // Throws a security exception with the right error message.
if (who != null) {
final int userId = UserHandle.getUserId(callingUid);
final DevicePolicyData policy = getUserData(userId);
@@ -2763,6 +2772,10 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
throw new SecurityException("Admin " + admin.info.getComponent()
+ " does not own the profile");
}
+ if (reqPolicy == DeviceAdminInfo.USES_POLICY_ORGANIZATION_OWNED_PROFILE_OWNER) {
+ throw new SecurityException("Admin " + admin.info.getComponent()
+ + " is not the profile owner on organization-owned device");
+ }
if (DA_DISALLOWED_POLICIES.contains(reqPolicy) && !isDeviceOwner && !isProfileOwner) {
throw new SecurityException("Admin " + admin.info.getComponent()
+ " is not a device owner or profile owner, so may not use policy: "
@@ -2869,12 +2882,16 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
ensureLocked();
final boolean ownsDevice = isDeviceOwner(admin.info.getComponent(), userId);
final boolean ownsProfile = isProfileOwner(admin.info.getComponent(), userId);
+ final boolean ownsProfileOnOrganizationOwnedDevice =
+ isProfileOwnerOfOrganizationOwnedDevice(admin.info.getComponent(), userId);
if (reqPolicy == DeviceAdminInfo.USES_POLICY_DEVICE_OWNER) {
return ownsDevice;
+ } else if (reqPolicy == DeviceAdminInfo.USES_POLICY_ORGANIZATION_OWNED_PROFILE_OWNER) {
+ return ownsDevice || ownsProfileOnOrganizationOwnedDevice;
} else if (reqPolicy == DeviceAdminInfo.USES_POLICY_PROFILE_OWNER) {
// DO always has the PO power.
- return ownsDevice || ownsProfile;
+ return ownsDevice || ownsProfileOnOrganizationOwnedDevice || ownsProfile;
} else {
boolean allowedToUsePolicy = ownsDevice || ownsProfile
|| !DA_DISALLOWED_POLICIES.contains(reqPolicy)
@@ -5574,6 +5591,13 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
}
}
+ private void enforceDeviceOwnerOrProfileOwnerOnOrganizationOwnedDevice(ComponentName who) {
+ synchronized (getLockObject()) {
+ getActiveAdminForCallerLocked(
+ who, DeviceAdminInfo.USES_POLICY_ORGANIZATION_OWNED_PROFILE_OWNER);
+ }
+ }
+
private void enforceProfileOwnerOfOrganizationOwnedDevice(ActiveAdmin admin) {
if (!isProfileOwnerOfOrganizationOwnedDevice(admin)) {
throw new SecurityException(String.format("Provided admin %s is either not a profile "
@@ -8071,21 +8095,12 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
return false;
}
- final int adminUserId = admin.getUserHandle().getIdentifier();
-
- if (!isProfileOwner(admin.info.getComponent(), adminUserId)) {
- Slog.w(LOG_TAG, String.format("%s is not profile owner of user %d",
- admin.info.getComponent(), adminUserId));
- return false;
- }
-
- if (!canProfileOwnerAccessDeviceIds(adminUserId)) {
- Slog.w(LOG_TAG, String.format("Profile owner of user %d does not own the device.",
- adminUserId));
- return false;
- }
+ return isProfileOwnerOfOrganizationOwnedDevice(
+ admin.info.getComponent(), admin.getUserHandle().getIdentifier());
+ }
- return true;
+ private boolean isProfileOwnerOfOrganizationOwnedDevice(ComponentName who, int userId) {
+ return isProfileOwner(who, userId) && canProfileOwnerAccessDeviceIds(userId);
}
@Override
@@ -11123,8 +11138,11 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
if (mInjector.settingsGlobalGetInt(Global.AUTO_TIME_ZONE, 0) == 1) {
return false;
}
+ ManualTimeZoneSuggestion manualTimeZoneSuggestion =
+ TimeZoneDetector.createManualTimeZoneSuggestion(
+ timeZone, "DevicePolicyManagerService: setTimeZone");
mInjector.binderWithCleanCallingIdentity(() ->
- mInjector.getAlarmManager().setTimeZone(timeZone));
+ mInjector.getTimeZoneDetector().suggestManualTimeZone(manualTimeZoneSuggestion));
return true;
}
@@ -12377,7 +12395,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
@Override
public String getWifiMacAddress(ComponentName admin) {
// Make sure caller has DO.
- enforceDeviceOwner(admin);
+ enforceDeviceOwnerOrProfileOwnerOnOrganizationOwnedDevice(admin);
final long ident = mInjector.binderClearCallingIdentity();
try {
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java b/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java
index 6c09239251bd..8e6114aaeffe 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java
@@ -1053,6 +1053,35 @@ public class MockingOomAdjusterTests {
@SuppressWarnings("GuardedBy")
@Test
+ public void testUpdateOomAdj_DoOne_Service_Chain_BoundByFgService_Cycle_2() {
+ ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
+ MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false));
+ ProcessRecord client = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID,
+ MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
+ bindService(app, client, null, 0, mock(IBinder.class));
+ bindService(client, app, null, 0, mock(IBinder.class));
+ ProcessRecord client2 = spy(makeDefaultProcessRecord(MOCKAPP3_PID, MOCKAPP3_UID,
+ MOCKAPP3_PROCESSNAME, MOCKAPP3_PACKAGENAME, false));
+ bindService(client2, client, null, 0, mock(IBinder.class));
+ client.setHasForegroundServices(true, 0);
+ ArrayList<ProcessRecord> lru = sService.mProcessList.mLruProcesses;
+ lru.clear();
+ lru.add(app);
+ lru.add(client);
+ lru.add(client2);
+ sService.mWakefulness = PowerManagerInternal.WAKEFULNESS_AWAKE;
+ sService.mOomAdjuster.updateOomAdjLocked(app, true, OomAdjuster.OOM_ADJ_REASON_NONE);
+
+ assertProcStates(app, PROCESS_STATE_FOREGROUND_SERVICE, PERCEPTIBLE_APP_ADJ,
+ SCHED_GROUP_DEFAULT);
+ assertProcStates(client, PROCESS_STATE_FOREGROUND_SERVICE, PERCEPTIBLE_APP_ADJ,
+ SCHED_GROUP_DEFAULT);
+ assertProcStates(client2, PROCESS_STATE_FOREGROUND_SERVICE, PERCEPTIBLE_APP_ADJ,
+ SCHED_GROUP_DEFAULT);
+ }
+
+ @SuppressWarnings("GuardedBy")
+ @Test
public void testUpdateOomAdj_DoOne_Service_Chain_BoundByFgService_Cycle_Branch() {
ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false));
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/SystemActionPerformerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/SystemActionPerformerTest.java
index 37f5b87ac115..335217719cc9 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/SystemActionPerformerTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/SystemActionPerformerTest.java
@@ -16,18 +16,39 @@
package com.android.server.accessibility;
+import static org.hamcrest.Matchers.hasItem;
+import static org.hamcrest.Matchers.is;
+import static org.hamcrest.Matchers.not;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
import android.accessibilityservice.AccessibilityService;
+import android.app.PendingIntent;
+import android.app.PendingIntent.CanceledException;
+import android.app.RemoteAction;
import android.app.StatusBarManager;
+import android.content.BroadcastReceiver;
import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.graphics.drawable.Icon;
import android.os.Handler;
+import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction;
+
+import androidx.test.InstrumentationRegistry;
import com.android.internal.util.ScreenshotHelper;
+import com.android.server.LocalServices;
+import com.android.server.statusbar.StatusBarManagerInternal;
import com.android.server.wm.WindowManagerInternal;
import org.junit.Before;
@@ -35,55 +56,290 @@ import org.junit.Test;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import java.util.List;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
/**
* Tests for SystemActionPerformer
*/
public class SystemActionPerformerTest {
- SystemActionPerformer mSystemActionPerformer;
+ private static final int LATCH_TIMEOUT_MS = 500;
+ private static final int LEGACY_SYSTEM_ACTION_COUNT = 9;
+ private static final int NEW_ACTION_ID = 20;
+ private static final String LABEL_1 = "label1";
+ private static final String LABEL_2 = "label2";
+ private static final String INTENT_ACTION1 = "TESTACTION1";
+ private static final String INTENT_ACTION2 = "TESTACTION2";
+ private static final String DESCRIPTION1 = "description1";
+ private static final String DESCRIPTION2 = "description2";
+ private static final PendingIntent TEST_PENDING_INTENT_1 = PendingIntent.getBroadcast(
+ InstrumentationRegistry.getTargetContext(), 0, new Intent(INTENT_ACTION1), 0);
+ private static final RemoteAction NEW_TEST_ACTION_1 = new RemoteAction(
+ Icon.createWithContentUri("content://test"),
+ LABEL_1,
+ DESCRIPTION1,
+ TEST_PENDING_INTENT_1);
+ private static final PendingIntent TEST_PENDING_INTENT_2 = PendingIntent.getBroadcast(
+ InstrumentationRegistry.getTargetContext(), 0, new Intent(INTENT_ACTION2), 0);
+ private static final RemoteAction NEW_TEST_ACTION_2 = new RemoteAction(
+ Icon.createWithContentUri("content://test"),
+ LABEL_2,
+ DESCRIPTION2,
+ TEST_PENDING_INTENT_2);
+
+ private static final AccessibilityAction NEW_ACCESSIBILITY_ACTION =
+ new AccessibilityAction(NEW_ACTION_ID, LABEL_1);
+ private static final AccessibilityAction LEGACY_NOTIFICATIONS_ACCESSIBILITY_ACTION =
+ new AccessibilityAction(AccessibilityService.GLOBAL_ACTION_NOTIFICATIONS, LABEL_1);
+ private static final AccessibilityAction LEGACY_HOME_ACCESSIBILITY_ACTION =
+ new AccessibilityAction(AccessibilityService.GLOBAL_ACTION_HOME, LABEL_2);
- @Mock Context mMockContext;
- @Mock WindowManagerInternal mMockWindowManagerInternal;
- @Mock StatusBarManager mMockStatusBarManager;
- @Mock ScreenshotHelper mMockScreenshotHelper;
+ private SystemActionPerformer mSystemActionPerformer;
+
+ @Mock private Context mMockContext;
+ @Mock private StatusBarManagerInternal mMockStatusBarManagerInternal;
+ @Mock private WindowManagerInternal mMockWindowManagerInternal;
+ @Mock private StatusBarManager mMockStatusBarManager;
+ @Mock private ScreenshotHelper mMockScreenshotHelper;
+ @Mock private SystemActionPerformer.SystemActionsChangedListener mMockListener;
@Before
public void setup() {
MockitoAnnotations.initMocks(this);
+ LocalServices.removeServiceForTest(StatusBarManagerInternal.class);
+ LocalServices.addService(StatusBarManagerInternal.class, mMockStatusBarManagerInternal);
+ }
+
+ private void setupWithMockContext() {
+ doReturn(mMockStatusBarManager).when(
+ mMockContext).getSystemService(android.app.Service.STATUS_BAR_SERVICE);
+ doReturn(InstrumentationRegistry.getContext().getResources()).when(
+ mMockContext).getResources();
+ mSystemActionPerformer = new SystemActionPerformer(
+ mMockContext,
+ mMockWindowManagerInternal,
+ () -> mMockScreenshotHelper,
+ mMockListener);
+ }
+
+ private void setupWithRealContext() {
+ mSystemActionPerformer = new SystemActionPerformer(
+ InstrumentationRegistry.getContext(),
+ mMockWindowManagerInternal,
+ () -> mMockScreenshotHelper,
+ mMockListener);
+ }
+
+ // We need below two help functions because AccessbilityAction.equals function only compares
+ // action ids. To verify the test result here, we are also looking at action labels.
+ private void assertHasLegacyAccessibilityAction(
+ List<AccessibilityAction> actions, AccessibilityAction action) {
+ boolean foundAction = false;
+ for (AccessibilityAction a : actions) {
+ if ((a.getId() == action.getId()) && (a.getLabel().equals(action.getLabel()))) {
+ foundAction = true;
+ break;
+ }
+ }
+ assertTrue(foundAction);
+ }
+
+ private void assertHasNoLegacyAccessibilityAction(
+ List<AccessibilityAction> actions, AccessibilityAction action) {
+ boolean foundAction = false;
+ for (AccessibilityAction a : actions) {
+ if ((a.getId() == action.getId()) && (a.getLabel().equals(action.getLabel()))) {
+ foundAction = true;
+ break;
+ }
+ }
+ assertFalse(foundAction);
+ }
+
+ @Test
+ public void testRegisterSystemAction_addedIntoAvailableSystemActions() {
+ setupWithRealContext();
+ // Before any new system action is registered, getSystemActions returns all legacy actions
+ List<AccessibilityAction> actions = mSystemActionPerformer.getSystemActions();
+ assertEquals(LEGACY_SYSTEM_ACTION_COUNT, actions.size());
+ // Register a new system action
+ mSystemActionPerformer.registerSystemAction(NEW_ACTION_ID, NEW_TEST_ACTION_1);
+ actions = mSystemActionPerformer.getSystemActions();
+ assertEquals(LEGACY_SYSTEM_ACTION_COUNT + 1, actions.size());
+ assertThat(actions, hasItem(NEW_ACCESSIBILITY_ACTION));
+ }
+
+ @Test
+ public void testRegisterSystemAction_overrideLegacyAction() {
+ setupWithRealContext();
+ // Before any new system action is registered, getSystemActions returns all legacy actions
+ List<AccessibilityAction> actions = mSystemActionPerformer.getSystemActions();
+ assertEquals(LEGACY_SYSTEM_ACTION_COUNT, actions.size());
+ // Overriding a legacy system action using legacy notification action id
+ mSystemActionPerformer.registerSystemAction(
+ AccessibilityService.GLOBAL_ACTION_NOTIFICATIONS, NEW_TEST_ACTION_1);
+ actions = mSystemActionPerformer.getSystemActions();
+ assertEquals(LEGACY_SYSTEM_ACTION_COUNT, actions.size());
+ assertHasLegacyAccessibilityAction(actions, LEGACY_NOTIFICATIONS_ACCESSIBILITY_ACTION);
+ }
+
+ @Test
+ public void testUnregisterSystemAction_removeFromAvailableSystemActions() {
+ setupWithRealContext();
+ // Before any new system action is registered, getSystemActions returns all legacy actions
+ List<AccessibilityAction> actions = mSystemActionPerformer.getSystemActions();
+ assertEquals(LEGACY_SYSTEM_ACTION_COUNT, actions.size());
+ // Register a new system action
+ mSystemActionPerformer.registerSystemAction(NEW_ACTION_ID, NEW_TEST_ACTION_1);
+ actions = mSystemActionPerformer.getSystemActions();
+ assertEquals(LEGACY_SYSTEM_ACTION_COUNT + 1, actions.size());
+
+ mSystemActionPerformer.unregisterSystemAction(NEW_ACTION_ID);
+ actions = mSystemActionPerformer.getSystemActions();
+ assertEquals(LEGACY_SYSTEM_ACTION_COUNT, actions.size());
+ assertThat(actions, is(not(hasItem(NEW_ACCESSIBILITY_ACTION))));
+ }
- when(mMockContext.getSystemService(android.app.Service.STATUS_BAR_SERVICE))
- .thenReturn(mMockStatusBarManager);
+ @Test
+ public void testUnregisterSystemAction_removeOverrideForLegacyAction() {
+ setupWithRealContext();
+
+ // Overriding a legacy system action
+ mSystemActionPerformer.registerSystemAction(
+ AccessibilityService.GLOBAL_ACTION_NOTIFICATIONS, NEW_TEST_ACTION_1);
+ List<AccessibilityAction> actions = mSystemActionPerformer.getSystemActions();
+ assertEquals(LEGACY_SYSTEM_ACTION_COUNT, actions.size());
+ assertHasLegacyAccessibilityAction(actions, LEGACY_NOTIFICATIONS_ACCESSIBILITY_ACTION);
+
+ // Remove the overriding action using legacy action id
+ mSystemActionPerformer.unregisterSystemAction(
+ AccessibilityService.GLOBAL_ACTION_NOTIFICATIONS);
+ actions = mSystemActionPerformer.getSystemActions();
+ assertEquals(LEGACY_SYSTEM_ACTION_COUNT, actions.size());
+ assertHasNoLegacyAccessibilityAction(actions, LEGACY_NOTIFICATIONS_ACCESSIBILITY_ACTION);
+ }
+
+ @Test
+ public void testPerformSystemActionNewAction() throws CanceledException {
+ setupWithRealContext();
- mSystemActionPerformer =
- new SystemActionPerformer(mMockContext, mMockWindowManagerInternal,
- () -> mMockScreenshotHelper);
+ final CountDownLatch latch = new CountDownLatch(1);
+ mSystemActionPerformer.registerSystemAction(NEW_ACTION_ID, NEW_TEST_ACTION_1);
+ TestBroadcastReceiver br = new TestBroadcastReceiver(latch);
+ br.register(InstrumentationRegistry.getTargetContext());
+ mSystemActionPerformer.performSystemAction(NEW_ACTION_ID);
+ try {
+ latch.await(LATCH_TIMEOUT_MS, TimeUnit.MILLISECONDS);
+ } catch (InterruptedException e) {
+ fail("RemoteAction should be triggered.");
+ } finally {
+ br.unregister(InstrumentationRegistry.getTargetContext());
+ }
}
@Test
- public void testNotifications_expandsNotificationPanel() {
+ public void testPerformSystemActionOverrideLegacyActionUsingLegacyActionId()
+ throws CanceledException {
+ setupWithRealContext();
+
+ final CountDownLatch latch = new CountDownLatch(1);
+ mSystemActionPerformer.registerSystemAction(
+ AccessibilityService.GLOBAL_ACTION_RECENTS, NEW_TEST_ACTION_1);
+ TestBroadcastReceiver br = new TestBroadcastReceiver(latch);
+ br.register(InstrumentationRegistry.getTargetContext());
+ mSystemActionPerformer.performSystemAction(AccessibilityService.GLOBAL_ACTION_RECENTS);
+ try {
+ latch.await(LATCH_TIMEOUT_MS, TimeUnit.MILLISECONDS);
+ } catch (InterruptedException e) {
+ fail("RemoteAction should be triggered.");
+ } finally {
+ br.unregister(InstrumentationRegistry.getTargetContext());
+ }
+ verify(mMockStatusBarManagerInternal, never()).toggleRecentApps();
+ // Now revert to legacy action
+ mSystemActionPerformer.unregisterSystemAction(AccessibilityService.GLOBAL_ACTION_RECENTS);
+ mSystemActionPerformer.performSystemAction(AccessibilityService.GLOBAL_ACTION_RECENTS);
+ verify(mMockStatusBarManagerInternal).toggleRecentApps();
+ }
+
+ @Test
+ public void testNotifications_expandsNotificationPanel_legacy() {
+ setupWithMockContext();
mSystemActionPerformer
.performSystemAction(AccessibilityService.GLOBAL_ACTION_NOTIFICATIONS);
verify(mMockStatusBarManager).expandNotificationsPanel();
}
@Test
- public void testQuickSettings_requestsQuickSettingsPanel() {
+ public void testQuickSettings_requestsQuickSettingsPanel_legacy() {
+ setupWithMockContext();
mSystemActionPerformer
.performSystemAction(AccessibilityService.GLOBAL_ACTION_QUICK_SETTINGS);
verify(mMockStatusBarManager).expandSettingsPanel();
}
@Test
- public void testPowerDialog_requestsFromWindowManager() {
+ public void testRecentApps_legacy() {
+ setupWithRealContext();
+ mSystemActionPerformer.performSystemAction(AccessibilityService.GLOBAL_ACTION_RECENTS);
+ verify(mMockStatusBarManagerInternal).toggleRecentApps();
+ }
+
+ @Test
+ public void testPowerDialog_requestsFromWindowManager_legacy() {
+ setupWithMockContext();
mSystemActionPerformer.performSystemAction(AccessibilityService.GLOBAL_ACTION_POWER_DIALOG);
verify(mMockWindowManagerInternal).showGlobalActions();
}
@Test
- public void testScreenshot_requestsFromScreenshotHelper() {
+ public void testToggleSplitScreen_legacy() {
+ setupWithRealContext();
+ mSystemActionPerformer.performSystemAction(
+ AccessibilityService.GLOBAL_ACTION_TOGGLE_SPLIT_SCREEN);
+ verify(mMockStatusBarManagerInternal).toggleSplitScreen();
+ }
+
+ @Test
+ public void testScreenshot_requestsFromScreenshotHelper_legacy() {
+ setupWithMockContext();
mSystemActionPerformer.performSystemAction(
AccessibilityService.GLOBAL_ACTION_TAKE_SCREENSHOT);
verify(mMockScreenshotHelper).takeScreenshot(
eq(android.view.WindowManager.TAKE_SCREENSHOT_FULLSCREEN), anyBoolean(),
anyBoolean(), any(Handler.class), any());
}
+
+ // PendingIntent is a final class and cannot be mocked. So we are using this
+ // Broadcast receiver to verify the registered remote action is called correctly.
+ private static final class TestBroadcastReceiver extends BroadcastReceiver {
+ private CountDownLatch mLatch;
+ private boolean mRegistered;
+ private final IntentFilter mFilter;
+
+ TestBroadcastReceiver(CountDownLatch latch) {
+ mLatch = latch;
+ mRegistered = false;
+ mFilter = new IntentFilter(INTENT_ACTION1);
+ }
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ mLatch.countDown();
+ }
+
+ void register(Context context) {
+ if (!mRegistered) {
+ context.registerReceiver(this, mFilter);
+ mRegistered = true;
+ }
+ }
+
+ void unregister(Context context) {
+ if (mRegistered) {
+ context.unregisterReceiver(this);
+ }
+ }
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/appsearch/impl/FakeIcingTest.java b/services/tests/servicestests/src/com/android/server/appsearch/impl/FakeIcingTest.java
index adef02ee55d7..6f2de7f50379 100644
--- a/services/tests/servicestests/src/com/android/server/appsearch/impl/FakeIcingTest.java
+++ b/services/tests/servicestests/src/com/android/server/appsearch/impl/FakeIcingTest.java
@@ -21,6 +21,7 @@ import androidx.test.runner.AndroidJUnit4;
import com.google.android.icing.proto.DocumentProto;
import com.google.android.icing.proto.PropertyProto;
+import com.google.android.icing.proto.SearchResultProto;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -115,8 +116,9 @@ public class FakeIcingTest {
private static List<String> queryGetUris(FakeIcing icing, String term) {
List<String> uris = new ArrayList<>();
- for (DocumentProto result : icing.query(term)) {
- uris.add(result.getUri());
+ SearchResultProto results = icing.query(term);
+ for (SearchResultProto.ResultProto result : results.getResultsList()) {
+ uris.add(result.getDocument().getUri());
}
return uris;
}
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java
index f86bacf67901..ac555fda2204 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java
@@ -23,6 +23,7 @@ import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.backup.IBackupManager;
import android.app.timedetector.TimeDetector;
+import android.app.timezonedetector.TimeZoneDetector;
import android.app.usage.UsageStatsManagerInternal;
import android.content.Context;
import android.content.Intent;
@@ -235,6 +236,11 @@ public class DevicePolicyManagerServiceTestable extends DevicePolicyManagerServi
}
@Override
+ TimeZoneDetector getTimeZoneDetector() {
+ return services.timeZoneDetector;
+ }
+
+ @Override
LockPatternUtils newLockPatternUtils() {
return services.lockPatternUtils;
}
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
index 059002094bc0..06b8716c0926 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -64,6 +64,8 @@ import android.app.admin.DevicePolicyManager;
import android.app.admin.DevicePolicyManagerInternal;
import android.app.admin.PasswordMetrics;
import android.app.timedetector.ManualTimeSuggestion;
+import android.app.timezonedetector.ManualTimeZoneSuggestion;
+import android.app.timezonedetector.TimeZoneDetector;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Intent;
@@ -138,6 +140,8 @@ public class DevicePolicyManagerTest extends DpmTestBase {
permission.MANAGE_USERS, permission.INTERACT_ACROSS_USERS_FULL);
public static final String NOT_DEVICE_OWNER_MSG = "does not own the device";
public static final String NOT_PROFILE_OWNER_MSG = "does not own the profile";
+ public static final String NOT_ORG_OWNED_PROFILE_OWNER_MSG =
+ "not the profile owner on organization-owned device";
public static final String ONGOING_CALL_MSG = "ongoing call on the device";
// TODO replace all instances of this with explicit {@link #mServiceContext}.
@@ -2114,12 +2118,14 @@ public class DevicePolicyManagerTest extends DpmTestBase {
assertTrue(dpm.isAdminActive(admin1));
// Test 2. Caller has DA, but not DO.
- assertExpectException(SecurityException.class, /* messageRegex= */ NOT_DEVICE_OWNER_MSG,
+ assertExpectException(SecurityException.class,
+ /* messageRegex= */ NOT_ORG_OWNED_PROFILE_OWNER_MSG,
() -> dpm.getWifiMacAddress(admin1));
// Test 3. Caller has PO, but not DO.
assertTrue(dpm.setProfileOwner(admin1, null, UserHandle.USER_SYSTEM));
- assertExpectException(SecurityException.class, /* messageRegex= */ NOT_DEVICE_OWNER_MSG,
+ assertExpectException(SecurityException.class,
+ /* messageRegex= */ NOT_ORG_OWNED_PROFILE_OWNER_MSG,
() -> dpm.getWifiMacAddress(admin1));
// Remove PO.
@@ -2141,6 +2147,15 @@ public class DevicePolicyManagerTest extends DpmTestBase {
assertEquals("11:22:33:44:55:66", dpm.getWifiMacAddress(admin1));
}
+ public void testGetMacAddressByOrgOwnedPO() throws Exception {
+ setupProfileOwner();
+ configureProfileOwnerOfOrgOwnedDevice(admin1, DpmMockContext.CALLER_USER_HANDLE);
+
+ final String[] macAddresses = new String[]{"11:22:33:44:55:66"};
+ when(getServices().wifiManager.getFactoryMacAddresses()).thenReturn(macAddresses);
+ assertEquals("11:22:33:44:55:66", dpm.getWifiMacAddress(admin1));
+ }
+
public void testReboot() throws Exception {
mContext.callerPermissions.add(permission.MANAGE_DEVICE_ADMINS);
mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS);
@@ -3694,7 +3709,9 @@ public class DevicePolicyManagerTest extends DpmTestBase {
mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
setupDeviceOwner();
dpm.setTimeZone(admin1, "Asia/Shanghai");
- verify(getServices().alarmManager).setTimeZone("Asia/Shanghai");
+ ManualTimeZoneSuggestion suggestion =
+ TimeZoneDetector.createManualTimeZoneSuggestion("Asia/Shanghai", "Test debug info");
+ verify(getServices().timeZoneDetector).suggestManualTimeZone(suggestion);
}
public void testSetTimeZoneFailWithPO() throws Exception {
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/MockSystemServices.java b/services/tests/servicestests/src/com/android/server/devicepolicy/MockSystemServices.java
index c9273642635e..6a0d9265f594 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/MockSystemServices.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/MockSystemServices.java
@@ -32,6 +32,7 @@ import android.app.IActivityTaskManager;
import android.app.NotificationManager;
import android.app.backup.IBackupManager;
import android.app.timedetector.TimeDetector;
+import android.app.timezonedetector.TimeZoneDetector;
import android.app.usage.UsageStatsManagerInternal;
import android.content.BroadcastReceiver;
import android.content.ContentValues;
@@ -113,6 +114,7 @@ public class MockSystemServices {
public final AccountManager accountManager;
public final AlarmManager alarmManager;
public final TimeDetector timeDetector;
+ public final TimeZoneDetector timeZoneDetector;
public final KeyChain.KeyChainConnection keyChainConnection;
/** Note this is a partial mock, not a real mock. */
public final PackageManager packageManager;
@@ -155,6 +157,7 @@ public class MockSystemServices {
accountManager = mock(AccountManager.class);
alarmManager = mock(AlarmManager.class);
timeDetector = mock(TimeDetector.class);
+ timeZoneDetector = mock(TimeZoneDetector.class);
keyChainConnection = mock(KeyChain.KeyChainConnection.class, RETURNS_DEEP_STUBS);
// Package manager is huge, so we use a partial mock instead.
diff --git a/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java
index 0ca62e2dcdff..81fb0ec3bf53 100644
--- a/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java
@@ -61,7 +61,6 @@ import android.os.Looper;
import android.os.PowerManager;
import android.os.PowerSaveState;
import android.os.SystemClock;
-import android.os.SystemProperties;
import android.os.UserHandle;
import android.provider.Settings;
import android.test.mock.MockContentResolver;
@@ -97,10 +96,12 @@ import java.util.Map;
* Tests for {@link com.android.server.power.PowerManagerService}
*/
public class PowerManagerServiceTest {
+ private static final String SYSTEM_PROPERTY_QUIESCENT = "ro.boot.quiescent";
+ private static final String SYSTEM_PROPERTY_REBOOT_REASON = "sys.boot.reason";
+
private static final float PRECISION = 0.001f;
private static final float BRIGHTNESS_FACTOR = 0.7f;
private static final boolean BATTERY_SAVER_ENABLED = true;
- private static final String TEST_LAST_REBOOT_PROPERTY = "test.sys.boot.reason";
@Mock private BatterySaverPolicy mBatterySaverPolicyMock;
@Mock private LightsManager mLightsManagerMock;
@@ -112,6 +113,7 @@ public class PowerManagerServiceTest {
@Mock private Notifier mNotifierMock;
@Mock private WirelessChargerDetector mWirelessChargerDetectorMock;
@Mock private AmbientDisplayConfiguration mAmbientDisplayConfigurationMock;
+ @Mock private SystemPropertiesWrapper mSystemPropertiesMock;
@Mock
private InattentiveSleepWarningController mInattentiveSleepWarningControllerMock;
@@ -159,6 +161,7 @@ public class PowerManagerServiceTest {
when(mBatteryManagerInternalMock.isPowered(anyInt())).thenReturn(false);
when(mInattentiveSleepWarningControllerMock.isShown()).thenReturn(false);
when(mDisplayManagerInternalMock.requestPowerState(any(), anyBoolean())).thenReturn(true);
+ when(mSystemPropertiesMock.get(eq(SYSTEM_PROPERTY_QUIESCENT), anyString())).thenReturn("");
mDisplayPowerRequest = new DisplayPowerRequest();
addLocalServiceMock(LightsManager.class, mLightsManagerMock);
@@ -218,6 +221,11 @@ public class PowerManagerServiceTest {
InattentiveSleepWarningController createInattentiveSleepWarningController() {
return mInattentiveSleepWarningControllerMock;
}
+
+ @Override
+ public SystemPropertiesWrapper createSystemPropertiesWrapper() {
+ return mSystemPropertiesMock;
+ }
});
return mService;
}
@@ -228,12 +236,6 @@ public class PowerManagerServiceTest {
LocalServices.removeServiceForTest(DisplayManagerInternal.class);
LocalServices.removeServiceForTest(BatteryManagerInternal.class);
LocalServices.removeServiceForTest(ActivityManagerInternal.class);
-
- Settings.Global.putInt(
- mContextSpy.getContentResolver(), Settings.Global.THEATER_MODE_ON, 0);
- setAttentiveTimeout(-1);
- Settings.Global.putInt(mContextSpy.getContentResolver(),
- Settings.Global.STAY_ON_WHILE_PLUGGED_IN, 0);
}
/**
@@ -322,10 +324,10 @@ public class PowerManagerServiceTest {
@Test
public void testGetLastShutdownReasonInternal() {
+ when(mSystemPropertiesMock.get(eq(SYSTEM_PROPERTY_REBOOT_REASON), any())).thenReturn(
+ "shutdown,thermal");
createService();
- SystemProperties.set(TEST_LAST_REBOOT_PROPERTY, "shutdown,thermal");
- int reason = mService.getLastShutdownReasonInternal(TEST_LAST_REBOOT_PROPERTY);
- SystemProperties.set(TEST_LAST_REBOOT_PROPERTY, "");
+ int reason = mService.getLastShutdownReasonInternal();
assertThat(reason).isEqualTo(PowerManager.SHUTDOWN_REASON_THERMAL_SHUTDOWN);
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
index eed5ef52c8e1..72baedb5ed66 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
@@ -222,7 +222,8 @@ public class WindowStateTests extends WindowTestsBase {
final WindowState appWindow = createWindow(null, TYPE_APPLICATION, "appWindow");
final WindowState imeWindow = createWindow(null, TYPE_INPUT_METHOD, "imeWindow");
- // Setting FLAG_NOT_FOCUSABLE prevents the window from being an IME target.
+ // Setting FLAG_NOT_FOCUSABLE without FLAG_ALT_FOCUSABLE_IM prevents the window from being
+ // an IME target.
appWindow.mAttrs.flags |= FLAG_NOT_FOCUSABLE;
imeWindow.mAttrs.flags |= FLAG_NOT_FOCUSABLE;
@@ -230,7 +231,7 @@ public class WindowStateTests extends WindowTestsBase {
appWindow.setHasSurface(true);
imeWindow.setHasSurface(true);
- // Windows with FLAG_NOT_FOCUSABLE can't be IME targets
+ // Windows without flags (FLAG_NOT_FOCUSABLE|FLAG_ALT_FOCUSABLE_IM) can't be IME targets
assertFalse(appWindow.canBeImeTarget());
assertFalse(imeWindow.canBeImeTarget());
@@ -238,16 +239,10 @@ public class WindowStateTests extends WindowTestsBase {
appWindow.mAttrs.flags |= (FLAG_NOT_FOCUSABLE | FLAG_ALT_FOCUSABLE_IM);
imeWindow.mAttrs.flags |= (FLAG_NOT_FOCUSABLE | FLAG_ALT_FOCUSABLE_IM);
- // Visible app window with flags FLAG_NOT_FOCUSABLE or FLAG_ALT_FOCUSABLE_IM can't be IME
- // target while an IME window can never be an IME target regardless of its visibility
- // or flags.
- assertFalse(appWindow.canBeImeTarget());
- assertFalse(imeWindow.canBeImeTarget());
-
- appWindow.mAttrs.flags &= ~FLAG_ALT_FOCUSABLE_IM;
- assertFalse(appWindow.canBeImeTarget());
- appWindow.mAttrs.flags &= ~FLAG_NOT_FOCUSABLE;
+ // Visible app window with flags can be IME target while an IME window can never be an IME
+ // target regardless of its visibility or flags.
assertTrue(appWindow.canBeImeTarget());
+ assertFalse(imeWindow.canBeImeTarget());
// Make windows invisible
appWindow.hideLw(false /* doAnimation */);
diff --git a/telecomm/java/android/telecom/Call.java b/telecomm/java/android/telecom/Call.java
index a0739c49fb76..86ad795b9ea2 100644
--- a/telecomm/java/android/telecom/Call.java
+++ b/telecomm/java/android/telecom/Call.java
@@ -291,7 +291,6 @@ public final class Call {
*/
public static final int DIRECTION_OUTGOING = 1;
-
/** Call can currently be put on hold or unheld. */
public static final int CAPABILITY_HOLD = 0x00000001;
@@ -571,6 +570,7 @@ public final class Call {
private final Bundle mIntentExtras;
private final long mCreationTimeMillis;
private final @CallDirection int mCallDirection;
+ private final @Connection.VerificationStatus int mCallerNumberVerificationStatus;
/**
* Whether the supplied capabilities supports the specified capability.
@@ -880,6 +880,15 @@ public final class Call {
return mCallDirection;
}
+ /**
+ * Gets the verification status for the phone number of an incoming call as identified in
+ * ATIS-1000082.
+ * @return the verification status.
+ */
+ public @Connection.VerificationStatus int getCallerNumberVerificationStatus() {
+ return mCallerNumberVerificationStatus;
+ }
+
@Override
public boolean equals(Object o) {
if (o instanceof Details) {
@@ -901,7 +910,9 @@ public final class Call {
areBundlesEqual(mExtras, d.mExtras) &&
areBundlesEqual(mIntentExtras, d.mIntentExtras) &&
Objects.equals(mCreationTimeMillis, d.mCreationTimeMillis) &&
- Objects.equals(mCallDirection, d.mCallDirection);
+ Objects.equals(mCallDirection, d.mCallDirection) &&
+ Objects.equals(mCallerNumberVerificationStatus,
+ d.mCallerNumberVerificationStatus);
}
return false;
}
@@ -923,7 +934,8 @@ public final class Call {
mExtras,
mIntentExtras,
mCreationTimeMillis,
- mCallDirection);
+ mCallDirection,
+ mCallerNumberVerificationStatus);
}
/** {@hide} */
@@ -944,7 +956,8 @@ public final class Call {
Bundle extras,
Bundle intentExtras,
long creationTimeMillis,
- int callDirection) {
+ int callDirection,
+ int callerNumberVerificationStatus) {
mTelecomCallId = telecomCallId;
mHandle = handle;
mHandlePresentation = handlePresentation;
@@ -962,6 +975,7 @@ public final class Call {
mIntentExtras = intentExtras;
mCreationTimeMillis = creationTimeMillis;
mCallDirection = callDirection;
+ mCallerNumberVerificationStatus = callerNumberVerificationStatus;
}
/** {@hide} */
@@ -983,7 +997,8 @@ public final class Call {
parcelableCall.getExtras(),
parcelableCall.getIntentExtras(),
parcelableCall.getCreationTimeMillis(),
- parcelableCall.getCallDirection());
+ parcelableCall.getCallDirection(),
+ parcelableCall.getCallerNumberVerificationStatus());
}
@Override
diff --git a/telecomm/java/android/telecom/Connection.java b/telecomm/java/android/telecom/Connection.java
index ae20aed2d3c7..c06327995bc0 100644
--- a/telecomm/java/android/telecom/Connection.java
+++ b/telecomm/java/android/telecom/Connection.java
@@ -16,6 +16,7 @@
package android.telecom;
+import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemApi;
@@ -48,6 +49,8 @@ import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.nio.channels.Channels;
import java.util.ArrayList;
import java.util.Arrays;
@@ -151,6 +154,32 @@ public abstract class Connection extends Conferenceable {
public static final int STATE_PULLING_CALL = 7;
/**
+ * Indicates that the network could not perform verification.
+ */
+ public static final int VERIFICATION_STATUS_NOT_VERIFIED = 0;
+
+ /**
+ * Indicates that verification by the network passed. This indicates there is a high likelihood
+ * that the call originated from a valid source.
+ */
+ public static final int VERIFICATION_STATUS_PASSED = 1;
+
+ /**
+ * Indicates that verification by the network failed. This indicates there is a high likelihood
+ * that the call did not originate from a valid source.
+ */
+ public static final int VERIFICATION_STATUS_FAILED = 2;
+
+ /**@hide*/
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(prefix = "VERIFICATION_STATUS_", value = {
+ VERIFICATION_STATUS_NOT_VERIFIED,
+ VERIFICATION_STATUS_PASSED,
+ VERIFICATION_STATUS_FAILED
+ })
+ public @interface VerificationStatus {}
+
+ /**
* Connection can currently be put on hold or unheld. This is distinct from
* {@link #CAPABILITY_SUPPORT_HOLD} in that although a connection may support 'hold' most times,
* it does not at the moment support the function. This can be true while the call is in the
@@ -1854,6 +1883,12 @@ public abstract class Connection extends Conferenceable {
private Set<String> mPreviousExtraKeys;
/**
+ * The verification status for an incoming call's phone number.
+ */
+ private @VerificationStatus int mCallerNumberVerificationStatus;
+
+
+ /**
* Create a new Connection.
*/
public Connection() {}
@@ -3355,4 +3390,26 @@ public abstract class Connection extends Conferenceable {
public void setCallDirection(@Call.Details.CallDirection int callDirection) {
mCallDirection = callDirection;
}
+
+ /**
+ * Gets the verification status for the phone number of an incoming call as identified in
+ * ATIS-1000082.
+ * @return the verification status.
+ */
+ public @VerificationStatus int getCallerNumberVerificationStatus() {
+ return mCallerNumberVerificationStatus;
+ }
+
+ /**
+ * Sets the verification status for the phone number of an incoming call as identified in
+ * ATIS-1000082.
+ * <p>
+ * This property can only be set at the time of creation of a {@link Connection} being returned
+ * by
+ * {@link ConnectionService#onCreateIncomingConnection(PhoneAccountHandle, ConnectionRequest)}.
+ */
+ public void setCallerNumberVerificationStatus(
+ @VerificationStatus int callerNumberVerificationStatus) {
+ mCallerNumberVerificationStatus = callerNumberVerificationStatus;
+ }
}
diff --git a/telecomm/java/android/telecom/ConnectionService.java b/telecomm/java/android/telecom/ConnectionService.java
index 812b805675e5..3a0494e17db9 100644
--- a/telecomm/java/android/telecom/ConnectionService.java
+++ b/telecomm/java/android/telecom/ConnectionService.java
@@ -1621,7 +1621,8 @@ public abstract class ConnectionService extends Service {
connection.getStatusHints(),
connection.getDisconnectCause(),
createIdList(connection.getConferenceables()),
- connection.getExtras()));
+ connection.getExtras(),
+ connection.getCallerNumberVerificationStatus()));
if (isIncoming && request.shouldShowIncomingCallUi() && isSelfManaged) {
// Tell ConnectionService to show its incoming call UX.
@@ -2156,7 +2157,8 @@ public abstract class ConnectionService extends Service {
emptyList,
connection.getExtras(),
conferenceId,
- connection.getCallDirection());
+ connection.getCallDirection(),
+ Connection.VERIFICATION_STATUS_NOT_VERIFIED);
mAdapter.addExistingConnection(id, parcelableConnection);
}
}
diff --git a/telecomm/java/android/telecom/ParcelableCall.java b/telecomm/java/android/telecom/ParcelableCall.java
index fdc324308d7a..a234bb0af8fa 100644
--- a/telecomm/java/android/telecom/ParcelableCall.java
+++ b/telecomm/java/android/telecom/ParcelableCall.java
@@ -16,7 +16,6 @@
package android.telecom;
-import android.annotation.Nullable;
import android.annotation.UnsupportedAppUsage;
import android.net.Uri;
import android.os.Build;
@@ -66,6 +65,7 @@ public final class ParcelableCall implements Parcelable {
private final Bundle mExtras;
private final long mCreationTimeMillis;
private final int mCallDirection;
+ private final int mCallerNumberVerificationStatus;
public ParcelableCall(
String id,
@@ -94,7 +94,8 @@ public final class ParcelableCall implements Parcelable {
Bundle intentExtras,
Bundle extras,
long creationTimeMillis,
- int callDirection) {
+ int callDirection,
+ int callerNumberVerificationStatus) {
mId = id;
mState = state;
mDisconnectCause = disconnectCause;
@@ -122,6 +123,7 @@ public final class ParcelableCall implements Parcelable {
mExtras = extras;
mCreationTimeMillis = creationTimeMillis;
mCallDirection = callDirection;
+ mCallerNumberVerificationStatus = callerNumberVerificationStatus;
}
/** The unique ID of the call. */
@@ -322,6 +324,15 @@ public final class ParcelableCall implements Parcelable {
return mCallDirection;
}
+ /**
+ * Gets the verification status for the phone number of an incoming call as identified in
+ * ATIS-1000082.
+ * @return the verification status.
+ */
+ public @Connection.VerificationStatus int getCallerNumberVerificationStatus() {
+ return mCallerNumberVerificationStatus;
+ }
+
/** Responsible for creating ParcelableCall objects for deserialized Parcels. */
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
public static final @android.annotation.NonNull Parcelable.Creator<ParcelableCall> CREATOR =
@@ -360,6 +371,7 @@ public final class ParcelableCall implements Parcelable {
ParcelableRttCall rttCall = source.readParcelable(classLoader);
long creationTimeMillis = source.readLong();
int callDirection = source.readInt();
+ int callerNumberVerificationStatus = source.readInt();
return new ParcelableCall(
id,
state,
@@ -387,7 +399,8 @@ public final class ParcelableCall implements Parcelable {
intentExtras,
extras,
creationTimeMillis,
- callDirection);
+ callDirection,
+ callerNumberVerificationStatus);
}
@Override
@@ -433,6 +446,7 @@ public final class ParcelableCall implements Parcelable {
destination.writeParcelable(mRttCall, 0);
destination.writeLong(mCreationTimeMillis);
destination.writeInt(mCallDirection);
+ destination.writeInt(mCallerNumberVerificationStatus);
}
@Override
diff --git a/telecomm/java/android/telecom/ParcelableConnection.java b/telecomm/java/android/telecom/ParcelableConnection.java
index 4734af6371d4..2b9ce9b46ad7 100644
--- a/telecomm/java/android/telecom/ParcelableConnection.java
+++ b/telecomm/java/android/telecom/ParcelableConnection.java
@@ -54,6 +54,7 @@ public final class ParcelableConnection implements Parcelable {
private final Bundle mExtras;
private String mParentCallId;
private @Call.Details.CallDirection int mCallDirection;
+ private @Connection.VerificationStatus int mCallerNumberVerificationStatus;
/** @hide */
public ParcelableConnection(
@@ -77,12 +78,13 @@ public final class ParcelableConnection implements Parcelable {
List<String> conferenceableConnectionIds,
Bundle extras,
String parentCallId,
- @Call.Details.CallDirection int callDirection) {
+ @Call.Details.CallDirection int callDirection,
+ @Connection.VerificationStatus int callerNumberVerificationStatus) {
this(phoneAccount, state, capabilities, properties, supportedAudioRoutes, address,
addressPresentation, callerDisplayName, callerDisplayNamePresentation,
videoProvider, videoState, ringbackRequested, isVoipAudioMode, connectTimeMillis,
connectElapsedTimeMillis, statusHints, disconnectCause, conferenceableConnectionIds,
- extras);
+ extras, callerNumberVerificationStatus);
mParentCallId = parentCallId;
mCallDirection = callDirection;
}
@@ -107,7 +109,8 @@ public final class ParcelableConnection implements Parcelable {
StatusHints statusHints,
DisconnectCause disconnectCause,
List<String> conferenceableConnectionIds,
- Bundle extras) {
+ Bundle extras,
+ @Connection.VerificationStatus int callerNumberVerificationStatus) {
mPhoneAccount = phoneAccount;
mState = state;
mConnectionCapabilities = capabilities;
@@ -129,6 +132,7 @@ public final class ParcelableConnection implements Parcelable {
mExtras = extras;
mParentCallId = null;
mCallDirection = Call.Details.DIRECTION_UNKNOWN;
+ mCallerNumberVerificationStatus = callerNumberVerificationStatus;
}
public PhoneAccountHandle getPhoneAccount() {
@@ -227,6 +231,10 @@ public final class ParcelableConnection implements Parcelable {
return mCallDirection;
}
+ public @Connection.VerificationStatus int getCallerNumberVerificationStatus() {
+ return mCallerNumberVerificationStatus;
+ }
+
@Override
public String toString() {
return new StringBuilder()
@@ -276,6 +284,7 @@ public final class ParcelableConnection implements Parcelable {
String parentCallId = source.readString();
long connectElapsedTimeMillis = source.readLong();
int callDirection = source.readInt();
+ int callerNumberVerificationStatus = source.readInt();
return new ParcelableConnection(
phoneAccount,
@@ -298,7 +307,8 @@ public final class ParcelableConnection implements Parcelable {
conferenceableConnectionIds,
extras,
parentCallId,
- callDirection);
+ callDirection,
+ callerNumberVerificationStatus);
}
@Override
@@ -338,5 +348,6 @@ public final class ParcelableConnection implements Parcelable {
destination.writeString(mParentCallId);
destination.writeLong(mConnectElapsedTimeMillis);
destination.writeInt(mCallDirection);
+ destination.writeInt(mCallerNumberVerificationStatus);
}
}
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index fc26122912dc..3bc3e49e6433 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -4723,17 +4723,6 @@ public class TelephonyManager {
}
/**
- * Sim activation type: voice
- * @hide
- */
- public static final int SIM_ACTIVATION_TYPE_VOICE = 0;
- /**
- * Sim activation type: data
- * @hide
- */
- public static final int SIM_ACTIVATION_TYPE_DATA = 1;
-
- /**
* Initial SIM activation state, unknown. Not set by any carrier apps.
* @hide
*/
diff --git a/tools/processors/unsupportedappusage/Android.bp b/tools/processors/unsupportedappusage/Android.bp
deleted file mode 100644
index 1e96234543c8..000000000000
--- a/tools/processors/unsupportedappusage/Android.bp
+++ /dev/null
@@ -1,34 +0,0 @@
-
-java_library_host {
- name: "unsupportedappusage-annotation-processor-lib",
- srcs: [
- "src/**/*.java",
- ],
- static_libs: [
- "guava",
- "unsupportedappusage-annotation"
- ],
- openjdk9: {
- javacflags: [
- "--add-modules=jdk.compiler",
- "--add-exports jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED",
- "--add-exports jdk.compiler/com.sun.tools.javac.model=ALL-UNNAMED",
- "--add-exports jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED",
- "--add-exports jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED",
- ],
- },
-}
-
-java_plugin {
- name: "unsupportedappusage-annotation-processor",
- processor_class: "android.processor.unsupportedappusage.UnsupportedAppUsageProcessor",
-
- java_resources: [
- "META-INF/**/*",
- ],
- static_libs: [
- "unsupportedappusage-annotation-processor-lib"
- ],
-
- use_tools_jar: true,
-}
diff --git a/tools/processors/unsupportedappusage/META-INF/services/javax.annotation.processing.Processor b/tools/processors/unsupportedappusage/META-INF/services/javax.annotation.processing.Processor
deleted file mode 100644
index 4a969d319070..000000000000
--- a/tools/processors/unsupportedappusage/META-INF/services/javax.annotation.processing.Processor
+++ /dev/null
@@ -1 +0,0 @@
-android.processor.unsupportedappusage.UnsupportedAppUsageProcessor
diff --git a/tools/processors/unsupportedappusage/src/android/processor/unsupportedappusage/SignatureBuilder.java b/tools/processors/unsupportedappusage/src/android/processor/unsupportedappusage/SignatureBuilder.java
deleted file mode 100644
index 65fc733fa364..000000000000
--- a/tools/processors/unsupportedappusage/src/android/processor/unsupportedappusage/SignatureBuilder.java
+++ /dev/null
@@ -1,258 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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.processor.unsupportedappusage;
-
-import static javax.lang.model.element.ElementKind.PACKAGE;
-import static javax.tools.Diagnostic.Kind.ERROR;
-import static javax.tools.Diagnostic.Kind.WARNING;
-
-import com.google.common.base.Strings;
-import com.google.common.collect.ImmutableMap;
-import com.sun.tools.javac.code.Type;
-
-import java.lang.annotation.Annotation;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-import java.util.Map;
-
-import javax.annotation.processing.Messager;
-import javax.lang.model.element.Element;
-import javax.lang.model.element.ExecutableElement;
-import javax.lang.model.element.PackageElement;
-import javax.lang.model.element.TypeElement;
-import javax.lang.model.element.VariableElement;
-import javax.lang.model.type.ArrayType;
-import javax.lang.model.type.DeclaredType;
-import javax.lang.model.type.TypeKind;
-import javax.lang.model.type.TypeMirror;
-
-/**
- * Builds a dex signature for a given method or field.
- */
-public class SignatureBuilder {
-
- private static final Map<TypeKind, String> TYPE_MAP = ImmutableMap.<TypeKind, String>builder()
- .put(TypeKind.BOOLEAN, "Z")
- .put(TypeKind.BYTE, "B")
- .put(TypeKind.CHAR, "C")
- .put(TypeKind.DOUBLE, "D")
- .put(TypeKind.FLOAT, "F")
- .put(TypeKind.INT, "I")
- .put(TypeKind.LONG, "J")
- .put(TypeKind.SHORT, "S")
- .put(TypeKind.VOID, "V")
- .build();
-
- private final Messager mMessager;
-
- /**
- * Exception used internally when we can't build a signature. Whenever this is thrown, an error
- * will also be written to the Messager.
- */
- private class SignatureBuilderException extends Exception {
- public SignatureBuilderException(String message) {
- super(message);
- }
-
- public void report(Element offendingElement) {
- mMessager.printMessage(ERROR, getMessage(), offendingElement);
- }
- }
-
- public SignatureBuilder(Messager messager) {
- mMessager = messager;
- }
-
- /**
- * Returns a list of enclosing elements for the given element, with the package first, and
- * excluding the element itself.
- */
- private List<Element> getEnclosingElements(Element e) {
- List<Element> enclosing = new ArrayList<>();
- e = e.getEnclosingElement(); // don't include the element itself.
- while (e != null) {
- enclosing.add(e);
- e = e.getEnclosingElement();
- }
- Collections.reverse(enclosing);
- return enclosing;
- }
-
- /**
- * Get the dex signature for a clazz, in format "Lpackage/name/Outer$Inner;"
- */
- private String getClassSignature(TypeElement clazz) {
- StringBuilder sb = new StringBuilder("L");
- for (Element enclosing : getEnclosingElements(clazz)) {
- switch (enclosing.getKind()) {
- case MODULE:
- // ignore this.
- break;
- case PACKAGE:
- sb.append(((PackageElement) enclosing)
- .getQualifiedName()
- .toString()
- .replace('.', '/'));
- sb.append('/');
- break;
- default:
- sb.append(enclosing.getSimpleName()).append('$');
- break;
- }
-
- }
- return sb
- .append(clazz.getSimpleName())
- .append(";")
- .toString();
- }
-
- /**
- * Returns the type signature for a given type. For primitive types, a single character.
- * For classes, the class signature. For arrays, a "[" preceeding the component type.
- */
- private String getTypeSignature(TypeMirror type) throws SignatureBuilderException {
- String sig = TYPE_MAP.get(type.getKind());
- if (sig != null) {
- return sig;
- }
- switch (type.getKind()) {
- case ARRAY:
- return "[" + getTypeSignature(((ArrayType) type).getComponentType());
- case DECLARED:
- Element declaring = ((DeclaredType) type).asElement();
- if (!(declaring instanceof TypeElement)) {
- throw new SignatureBuilderException(
- "Can't handle declared type of kind " + declaring.getKind());
- }
- return getClassSignature((TypeElement) declaring);
- case TYPEVAR:
- Type.TypeVar typeVar = (Type.TypeVar) type;
- if (typeVar.getLowerBound().getKind() != TypeKind.NULL) {
- return getTypeSignature(typeVar.getLowerBound());
- } else if (typeVar.getUpperBound().getKind() != TypeKind.NULL) {
- return getTypeSignature(typeVar.getUpperBound());
- } else {
- throw new SignatureBuilderException("Can't handle typevar with no bound");
- }
-
- default:
- throw new SignatureBuilderException("Can't handle type of kind " + type.getKind());
- }
- }
-
- /**
- * Get the signature for an executable, either a method or a constructor.
- *
- * @param name "<init>" for constructor, else the method name
- * @param method The executable element in question.
- */
- private String getExecutableSignature(CharSequence name, ExecutableElement method)
- throws SignatureBuilderException {
- StringBuilder sig = new StringBuilder();
- sig.append(getClassSignature((TypeElement) method.getEnclosingElement()))
- .append("->")
- .append(name)
- .append("(");
- for (VariableElement param : method.getParameters()) {
- sig.append(getTypeSignature(param.asType()));
- }
- sig.append(")")
- .append(getTypeSignature(method.getReturnType()));
- return sig.toString();
- }
-
- private String buildMethodSignature(ExecutableElement method) throws SignatureBuilderException {
- return getExecutableSignature(method.getSimpleName(), method);
- }
-
- private String buildConstructorSignature(ExecutableElement cons)
- throws SignatureBuilderException {
- return getExecutableSignature("<init>", cons);
- }
-
- private String buildFieldSignature(VariableElement field) throws SignatureBuilderException {
- StringBuilder sig = new StringBuilder();
- sig.append(getClassSignature((TypeElement) field.getEnclosingElement()))
- .append("->")
- .append(field.getSimpleName())
- .append(":")
- .append(getTypeSignature(field.asType()))
- ;
- return sig.toString();
- }
-
- /**
- * Creates the signature for an annotated element.
- *
- * @param annotationType type of annotation being processed.
- * @param element element for which we want to create a signature.
- */
- public String buildSignature(Class<? extends Annotation> annotationType, Element element) {
- try {
- String signature;
- switch (element.getKind()) {
- case METHOD:
- signature = buildMethodSignature((ExecutableElement) element);
- break;
- case CONSTRUCTOR:
- signature = buildConstructorSignature((ExecutableElement) element);
- break;
- case FIELD:
- signature = buildFieldSignature((VariableElement) element);
- break;
- default:
- return null;
- }
- // Obtain annotation objects
- Annotation annotation = element.getAnnotation(annotationType);
- if (annotation == null) {
- throw new IllegalStateException(
- "Element doesn't have any UnsupportedAppUsage annotation");
- }
- try {
- Method expectedSignatureMethod = annotationType.getMethod("expectedSignature");
- // If we have an expected signature on the annotation, warn if it doesn't match.
- String expectedSignature = expectedSignatureMethod.invoke(annotation).toString();
- if (!Strings.isNullOrEmpty(expectedSignature)) {
- if (!signature.equals(expectedSignature)) {
- mMessager.printMessage(
- WARNING,
- String.format(
- "Expected signature doesn't match generated signature.\n"
- + " Expected: %s\n Generated: %s",
- expectedSignature, signature),
- element);
- }
- }
- return signature;
- } catch (NoSuchMethodException e) {
- throw new IllegalStateException(
- "Annotation type does not have expectedSignature parameter", e);
- } catch (IllegalAccessException | InvocationTargetException e) {
- throw new IllegalStateException(
- "Could not get expectedSignature parameter for annotation", e);
- }
- } catch (SignatureBuilderException problem) {
- problem.report(element);
- return null;
- }
- }
-}
diff --git a/tools/processors/unsupportedappusage/src/android/processor/unsupportedappusage/UnsupportedAppUsageProcessor.java b/tools/processors/unsupportedappusage/src/android/processor/unsupportedappusage/UnsupportedAppUsageProcessor.java
deleted file mode 100644
index ca2c2759d702..000000000000
--- a/tools/processors/unsupportedappusage/src/android/processor/unsupportedappusage/UnsupportedAppUsageProcessor.java
+++ /dev/null
@@ -1,246 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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.processor.unsupportedappusage;
-
-import static javax.tools.StandardLocation.CLASS_OUTPUT;
-
-import com.google.common.base.Joiner;
-import com.google.common.collect.ImmutableSet;
-import com.sun.tools.javac.model.JavacElements;
-import com.sun.tools.javac.tree.JCTree;
-import com.sun.tools.javac.util.Pair;
-import com.sun.tools.javac.util.Position;
-
-import java.io.IOException;
-import java.io.PrintStream;
-import java.lang.annotation.Annotation;
-import java.net.URLEncoder;
-import java.util.Map;
-import java.util.Set;
-import java.util.TreeMap;
-import java.util.stream.Stream;
-
-import javax.annotation.processing.AbstractProcessor;
-import javax.annotation.processing.RoundEnvironment;
-import javax.annotation.processing.SupportedAnnotationTypes;
-import javax.lang.model.SourceVersion;
-import javax.lang.model.element.AnnotationMirror;
-import javax.lang.model.element.AnnotationValue;
-import javax.lang.model.element.Element;
-import javax.lang.model.element.ExecutableElement;
-import javax.lang.model.element.TypeElement;
-import javax.tools.Diagnostic;
-
-/**
- * Annotation processor for {@link UnsupportedAppUsage} annotations.
- *
- * This processor currently outputs a CSV file with a mapping of dex signatures to corresponding
- * source positions.
- *
- * This is used for automating updates to the annotations themselves.
- */
-@SupportedAnnotationTypes({"android.annotation.UnsupportedAppUsage",
- "dalvik.annotation.compat.UnsupportedAppUsage"
-})
-public class UnsupportedAppUsageProcessor extends AbstractProcessor {
-
- // Package name for writing output. Output will be written to the "class output" location within
- // this package.
- private static final String PACKAGE = "unsupportedappusage";
- private static final String INDEX_CSV = "unsupportedappusage_index.csv";
-
- private static final ImmutableSet<Class<? extends Annotation>> SUPPORTED_ANNOTATIONS =
- ImmutableSet.of(android.annotation.UnsupportedAppUsage.class,
- dalvik.annotation.compat.UnsupportedAppUsage.class);
- private static final ImmutableSet<String> SUPPORTED_ANNOTATION_NAMES =
- SUPPORTED_ANNOTATIONS.stream().map(annotation -> annotation.getCanonicalName()).collect(
- ImmutableSet.toImmutableSet());
- private static final String OVERRIDE_SOURCE_POSITION_PROPERTY = "overrideSourcePosition";
-
- @Override
- public SourceVersion getSupportedSourceVersion() {
- return SourceVersion.latest();
- }
-
- /**
- * Write the contents of a stream to a text file, with one line per item.
- */
- private void writeToFile(String name,
- String headerLine,
- Stream<?> contents) throws IOException {
- PrintStream out = new PrintStream(processingEnv.getFiler().createResource(
- CLASS_OUTPUT,
- PACKAGE,
- name)
- .openOutputStream());
- out.println(headerLine);
- contents.forEach(o -> out.println(o));
- if (out.checkError()) {
- throw new IOException("Error when writing to " + name);
- }
- out.close();
- }
-
- /**
- * Find the annotation mirror for the @UnsupportedAppUsage annotation on the given element.
- */
- private AnnotationMirror getUnsupportedAppUsageAnnotationMirror(Element e) {
- for (AnnotationMirror m : e.getAnnotationMirrors()) {
- TypeElement type = (TypeElement) m.getAnnotationType().asElement();
- if (SUPPORTED_ANNOTATION_NAMES.contains(type.getQualifiedName().toString())) {
- return m;
- }
- }
- return null;
- }
-
- /**
- * Returns a CSV header line for the columns returned by
- * {@link #getAnnotationIndex(String, Element)}.
- */
- private String getCsvHeaders() {
- return Joiner.on(',').join(
- "signature",
- "file",
- "startline",
- "startcol",
- "endline",
- "endcol",
- "properties"
- );
- }
-
- private String encodeAnnotationProperties(AnnotationMirror annotation) {
- StringBuilder sb = new StringBuilder();
- for (Map.Entry<? extends ExecutableElement, ? extends AnnotationValue> e
- : annotation.getElementValues().entrySet()) {
- if (e.getKey().getSimpleName().toString().equals(OVERRIDE_SOURCE_POSITION_PROPERTY)) {
- continue;
- }
- if (sb.length() > 0) {
- sb.append("&");
- }
- sb.append(e.getKey().getSimpleName())
- .append("=")
- .append(URLEncoder.encode(e.getValue().toString()));
- }
- return sb.toString();
- }
-
- private SourcePosition getSourcePositionOverride(
- Element annotatedElement, AnnotationMirror annotation) {
- for (Map.Entry<? extends ExecutableElement, ? extends AnnotationValue> e
- : annotation.getElementValues().entrySet()) {
- if (e.getKey().getSimpleName().toString().equals(OVERRIDE_SOURCE_POSITION_PROPERTY)) {
- String[] position = e.getValue().getValue().toString().split(":");
- if (position.length != 5) {
- processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, String.format(
- "Expected %s to have format file:startLine:startCol:endLine:endCol",
- OVERRIDE_SOURCE_POSITION_PROPERTY), annotatedElement, annotation);
- return null;
- }
- try {
- return new SourcePosition(position[0], Integer.parseInt(position[1]),
- Integer.parseInt(position[2]), Integer.parseInt(position[3]),
- Integer.parseInt(position[4]));
- } catch (NumberFormatException nfe) {
- processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, String.format(
- "Expected %s to have format file:startLine:startCol:endLine:endCol; "
- + "error parsing integer: %s", OVERRIDE_SOURCE_POSITION_PROPERTY,
- nfe.getMessage()), annotatedElement, annotation);
- return null;
- }
- }
- }
- return null;
- }
-
- /**
- * Maps an annotated element to the source position of the @UnsupportedAppUsage annotation
- * attached to it. It returns CSV in the format:
- * dex-signature,filename,start-line,start-col,end-line,end-col
- *
- * The positions refer to the annotation itself, *not* the annotated member. This can therefore
- * be used to read just the annotation from the file, and to perform in-place edits on it.
- *
- * @param signature the dex signature for the element.
- * @param annotatedElement The annotated element
- * @return A single line of CSV text
- */
- private String getAnnotationIndex(String signature, Element annotatedElement) {
- JavacElements javacElem = (JavacElements) processingEnv.getElementUtils();
- AnnotationMirror unsupportedAppUsage =
- getUnsupportedAppUsageAnnotationMirror(annotatedElement);
- SourcePosition position = getSourcePositionOverride(annotatedElement, unsupportedAppUsage);
- if (position == null) {
- Pair<JCTree, JCTree.JCCompilationUnit> pair =
- javacElem.getTreeAndTopLevel(annotatedElement, unsupportedAppUsage, null);
- Position.LineMap lines = pair.snd.lineMap;
- position = new SourcePosition(
- pair.snd.getSourceFile().getName(),
- lines.getLineNumber(pair.fst.pos().getStartPosition()),
- lines.getColumnNumber(pair.fst.pos().getStartPosition()),
- lines.getLineNumber(pair.fst.pos().getEndPosition(pair.snd.endPositions)),
- lines.getColumnNumber(pair.fst.pos().getEndPosition(pair.snd.endPositions)));
- }
- return Joiner.on(",").join(
- signature,
- position.filename,
- position.startLine,
- position.startCol,
- position.endLine,
- position.endCol,
- encodeAnnotationProperties(unsupportedAppUsage));
- }
-
- /**
- * This is the main entry point in the processor, called by the compiler.
- */
- @Override
- public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
- Map<String, Element> signatureMap = new TreeMap<>();
- SignatureBuilder sb = new SignatureBuilder(processingEnv.getMessager());
- for (Class<? extends Annotation> supportedAnnotation : SUPPORTED_ANNOTATIONS) {
- Set<? extends Element> annotated = roundEnv.getElementsAnnotatedWith(
- supportedAnnotation);
- if (annotated.size() == 0) {
- continue;
- }
- // Build signatures for each annotated member and put them in a map from signature to
- // member.
- for (Element e : annotated) {
- String sig = sb.buildSignature(supportedAnnotation, e);
- if (sig != null) {
- signatureMap.put(sig, e);
- }
- }
- }
-
- if (!signatureMap.isEmpty()) {
- try {
- writeToFile(INDEX_CSV,
- getCsvHeaders(),
- signatureMap.entrySet()
- .stream()
- .map(e -> getAnnotationIndex(e.getKey(), e.getValue())));
- } catch (IOException e) {
- throw new RuntimeException("Failed to write output", e);
- }
- }
- return true;
- }
-}
diff --git a/tools/processors/unsupportedappusage/test/Android.bp b/tools/processors/unsupportedappusage/test/Android.bp
deleted file mode 100644
index e10fd47e8db1..000000000000
--- a/tools/processors/unsupportedappusage/test/Android.bp
+++ /dev/null
@@ -1,28 +0,0 @@
-// Copyright (C) 2019 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-java_test_host {
- name: "unsupportedappusage-processor-test",
-
- srcs: ["src/**/*.java"],
-
- static_libs: [
- "compile-testing-prebuilt",
- "unsupportedappusage-annotation-processor-lib",
- "truth-host-prebuilt",
- "mockito-host",
- "junit-host",
- "objenesis",
- ],
-}
diff --git a/tools/processors/unsupportedappusage/test/src/android/processor/unsupportedappusage/CsvReader.java b/tools/processors/unsupportedappusage/test/src/android/processor/unsupportedappusage/CsvReader.java
deleted file mode 100644
index 23db99e81194..000000000000
--- a/tools/processors/unsupportedappusage/test/src/android/processor/unsupportedappusage/CsvReader.java
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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.processor.unsupportedappusage;
-
-import com.google.common.base.Splitter;
-
-import java.io.BufferedReader;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-public class CsvReader {
-
- private final Splitter mSplitter;
- private final List<String> mColumns;
- private final List<Map<String, String>> mContents;
-
- public CsvReader(InputStream in) throws IOException {
- mSplitter = Splitter.on(",");
- BufferedReader br = new BufferedReader(new InputStreamReader(in));
- mColumns = mSplitter.splitToList(br.readLine());
- mContents = new ArrayList<>();
- String line = br.readLine();
- while (line != null) {
- List<String> contents = mSplitter.splitToList(line);
- Map<String, String> contentMap = new HashMap<>();
- for (int i = 0; i < Math.min(contents.size(), mColumns.size()); ++i) {
- contentMap.put(mColumns.get(i), contents.get(i));
- }
- mContents.add(contentMap);
- line = br.readLine();
- }
- br.close();
- }
-
- public List<String> getColumns() {
- return mColumns;
- }
-
- public List<Map<String, String>> getContents() {
- return mContents;
- }
-}
diff --git a/tools/processors/unsupportedappusage/test/src/android/processor/unsupportedappusage/UnsupportedAppUsageProcessorTest.java b/tools/processors/unsupportedappusage/test/src/android/processor/unsupportedappusage/UnsupportedAppUsageProcessorTest.java
deleted file mode 100644
index 75158eebdfdd..000000000000
--- a/tools/processors/unsupportedappusage/test/src/android/processor/unsupportedappusage/UnsupportedAppUsageProcessorTest.java
+++ /dev/null
@@ -1,154 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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.processor.unsupportedappusage;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import com.google.testing.compile.Compilation;
-import com.google.testing.compile.CompilationSubject;
-import com.google.testing.compile.Compiler;
-import com.google.testing.compile.JavaFileObjects;
-
-import org.junit.Test;
-
-import java.io.IOException;
-import java.util.Map;
-import java.util.Optional;
-
-import javax.tools.JavaFileObject;
-import javax.tools.StandardLocation;
-
-public class UnsupportedAppUsageProcessorTest {
-
- private static final JavaFileObject ANNOTATION = JavaFileObjects.forSourceLines(
- "dalvik.dalvik.annotation.compat.UnsupportedAppUsage",
- "package dalvik.annotation.compat;",
- "public @interface UnsupportedAppUsage {",
- " String expectedSignature() default \"\";\n",
- " String someProperty() default \"\";",
- " String overrideSourcePosition() default \"\";",
- "}");
-
- private CsvReader compileAndReadCsv(JavaFileObject source) throws IOException {
- Compilation compilation =
- Compiler.javac().withProcessors(new UnsupportedAppUsageProcessor())
- .compile(ANNOTATION, source);
- CompilationSubject.assertThat(compilation).succeeded();
- Optional<JavaFileObject> csv = compilation.generatedFile(StandardLocation.CLASS_OUTPUT,
- "unsupportedappusage/unsupportedappusage_index.csv");
- assertThat(csv.isPresent()).isTrue();
-
- return new CsvReader(csv.get().openInputStream());
- }
-
- @Test
- public void testSignatureFormat() throws Exception {
- JavaFileObject src = JavaFileObjects.forSourceLines("a.b.Class",
- "package a.b;",
- "import dalvik.annotation.compat.UnsupportedAppUsage;",
- "public class Class {",
- " @UnsupportedAppUsage",
- " public void method() {}",
- "}");
- assertThat(compileAndReadCsv(src).getContents().get(0)).containsEntry(
- "signature", "La/b/Class;->method()V"
- );
- }
-
- @Test
- public void testSourcePosition() throws Exception {
- JavaFileObject src = JavaFileObjects.forSourceLines("a.b.Class",
- "package a.b;", // 1
- "import dalvik.annotation.compat.UnsupportedAppUsage;", // 2
- "public class Class {", // 3
- " @UnsupportedAppUsage", // 4
- " public void method() {}", // 5
- "}");
- Map<String, String> row = compileAndReadCsv(src).getContents().get(0);
- assertThat(row).containsEntry("startline", "4");
- assertThat(row).containsEntry("startcol", "3");
- assertThat(row).containsEntry("endline", "4");
- assertThat(row).containsEntry("endcol", "23");
- }
-
- @Test
- public void testAnnotationProperties() throws Exception {
- JavaFileObject src = JavaFileObjects.forSourceLines("a.b.Class",
- "package a.b;", // 1
- "import dalvik.annotation.compat.UnsupportedAppUsage;", // 2
- "public class Class {", // 3
- " @UnsupportedAppUsage(someProperty=\"value\")", // 4
- " public void method() {}", // 5
- "}");
- assertThat(compileAndReadCsv(src).getContents().get(0)).containsEntry(
- "properties", "someProperty=%22value%22");
- }
-
- @Test
- public void testSourcePositionOverride() throws Exception {
- JavaFileObject src = JavaFileObjects.forSourceLines("a.b.Class",
- "package a.b;", // 1
- "import dalvik.annotation.compat.UnsupportedAppUsage;", // 2
- "public class Class {", // 3
- " @UnsupportedAppUsage(overrideSourcePosition=\"otherfile.aidl:30:10:31:20\")",
- " public void method() {}", // 5
- "}");
- Map<String, String> row = compileAndReadCsv(src).getContents().get(0);
- assertThat(row).containsEntry("file", "otherfile.aidl");
- assertThat(row).containsEntry("startline", "30");
- assertThat(row).containsEntry("startcol", "10");
- assertThat(row).containsEntry("endline", "31");
- assertThat(row).containsEntry("endcol", "20");
- assertThat(row).containsEntry("properties", "");
- }
-
- @Test
- public void testSourcePositionOverrideWrongFormat() throws Exception {
- JavaFileObject src = JavaFileObjects.forSourceLines("a.b.Class",
- "package a.b;", // 1
- "import dalvik.annotation.compat.UnsupportedAppUsage;", // 2
- "public class Class {", // 3
- " @UnsupportedAppUsage(overrideSourcePosition=\"invalid\")", // 4
- " public void method() {}", // 5
- "}");
- Compilation compilation =
- Compiler.javac().withProcessors(new UnsupportedAppUsageProcessor())
- .compile(ANNOTATION, src);
- CompilationSubject.assertThat(compilation).failed();
- CompilationSubject.assertThat(compilation).hadErrorContaining(
- "Expected overrideSourcePosition to have format "
- + "file:startLine:startCol:endLine:endCol").inFile(src).onLine(4);
- }
-
- @Test
- public void testSourcePositionOverrideInvalidInt() throws Exception {
- JavaFileObject src = JavaFileObjects.forSourceLines("a.b.Class",
- "package a.b;", // 1
- "import dalvik.annotation.compat.UnsupportedAppUsage;", // 2
- "public class Class {", // 3
- " @UnsupportedAppUsage(overrideSourcePosition=\"otherfile.aidl:a:b:c:d\")", // 4
- " public void method() {}", // 5
- "}");
- Compilation compilation =
- Compiler.javac().withProcessors(new UnsupportedAppUsageProcessor())
- .compile(ANNOTATION, src);
- CompilationSubject.assertThat(compilation).failed();
- CompilationSubject.assertThat(compilation).hadErrorContaining(
- "error parsing integer").inFile(src).onLine(4);
- }
-
-}
diff --git a/wifi/java/android/net/wifi/ScanResult.java b/wifi/java/android/net/wifi/ScanResult.java
index 9956901434d0..729ef61f0e4d 100644
--- a/wifi/java/android/net/wifi/ScanResult.java
+++ b/wifi/java/android/net/wifi/ScanResult.java
@@ -499,6 +499,13 @@ public class ScanResult implements Parcelable {
/**
* @hide
+ */
+ public boolean is6GHz() {
+ return ScanResult.is6GHz(frequency);
+ }
+
+ /**
+ * @hide
* TODO: makes real freq boundaries
*/
public static boolean is5GHz(int freq) {
@@ -506,6 +513,13 @@ public class ScanResult implements Parcelable {
}
/**
+ * @hide
+ */
+ public static boolean is6GHz(int freq) {
+ return freq > 5925 && freq < 7125;
+ }
+
+ /**
* @hide
* anqp lines from supplicant BSS response
*/
diff --git a/wifi/java/android/net/wifi/WifiScanner.java b/wifi/java/android/net/wifi/WifiScanner.java
index c743b63483d9..760497b727cd 100644
--- a/wifi/java/android/net/wifi/WifiScanner.java
+++ b/wifi/java/android/net/wifi/WifiScanner.java
@@ -740,6 +740,8 @@ public class WifiScanner {
public int min5GHzRssi;
/** Minimum 2.4GHz RSSI for a BSSID to be considered */
public int min24GHzRssi;
+ /** Minimum 6GHz RSSI for a BSSID to be considered */
+ public int min6GHzRssi;
/** Maximum score that a network can have before bonuses */
public int initialScoreMax;
/**
@@ -753,6 +755,8 @@ public class WifiScanner {
public int secureBonus;
/** 5GHz RSSI score bonus (applied to all 5GHz networks) */
public int band5GHzBonus;
+ /** 6GHz RSSI score bonus (applied to all 5GHz networks) */
+ public int band6GHzBonus;
/** Pno Network filter list */
public PnoNetwork[] networkList;
@@ -766,11 +770,13 @@ public class WifiScanner {
dest.writeInt(isConnected ? 1 : 0);
dest.writeInt(min5GHzRssi);
dest.writeInt(min24GHzRssi);
+ dest.writeInt(min6GHzRssi);
dest.writeInt(initialScoreMax);
dest.writeInt(currentConnectionBonus);
dest.writeInt(sameNetworkBonus);
dest.writeInt(secureBonus);
dest.writeInt(band5GHzBonus);
+ dest.writeInt(band6GHzBonus);
if (networkList != null) {
dest.writeInt(networkList.length);
for (int i = 0; i < networkList.length; i++) {
@@ -792,11 +798,13 @@ public class WifiScanner {
settings.isConnected = in.readInt() == 1;
settings.min5GHzRssi = in.readInt();
settings.min24GHzRssi = in.readInt();
+ settings.min6GHzRssi = in.readInt();
settings.initialScoreMax = in.readInt();
settings.currentConnectionBonus = in.readInt();
settings.sameNetworkBonus = in.readInt();
settings.secureBonus = in.readInt();
settings.band5GHzBonus = in.readInt();
+ settings.band6GHzBonus = in.readInt();
int numNetworks = in.readInt();
settings.networkList = new PnoNetwork[numNetworks];
for (int i = 0; i < numNetworks; i++) {
diff --git a/wifi/tests/src/android/net/wifi/WifiScannerTest.java b/wifi/tests/src/android/net/wifi/WifiScannerTest.java
index b1436c90f5dd..fa4f711056db 100644
--- a/wifi/tests/src/android/net/wifi/WifiScannerTest.java
+++ b/wifi/tests/src/android/net/wifi/WifiScannerTest.java
@@ -79,15 +79,17 @@ public class WifiScannerTest {
private static final boolean TEST_PNOSETTINGS_IS_CONNECTED = false;
private static final int TEST_PNOSETTINGS_MIN_5GHZ_RSSI = -60;
private static final int TEST_PNOSETTINGS_MIN_2GHZ_RSSI = -70;
+ private static final int TEST_PNOSETTINGS_MIN_6GHZ_RSSI = -55;
private static final int TEST_PNOSETTINGS_INITIAL_SCORE_MAX = 50;
private static final int TEST_PNOSETTINGS_CURRENT_CONNECTION_BONUS = 10;
private static final int TEST_PNOSETTINGS_SAME_NETWORK_BONUS = 11;
private static final int TEST_PNOSETTINGS_SECURE_BONUS = 12;
private static final int TEST_PNOSETTINGS_BAND_5GHZ_BONUS = 13;
+ private static final int TEST_PNOSETTINGS_BAND_6GHZ_BONUS = 15;
private static final String TEST_SSID_1 = "TEST1";
private static final String TEST_SSID_2 = "TEST2";
private static final int[] TEST_FREQUENCIES_1 = {};
- private static final int[] TEST_FREQUENCIES_2 = {2500, 5124};
+ private static final int[] TEST_FREQUENCIES_2 = {2500, 5124, 6245};
private static final String DESCRIPTION_NOT_AUTHORIZED = "Not authorized";
private WifiScanner mWifiScanner;
@@ -183,11 +185,13 @@ public class WifiScannerTest {
pnoSettings.isConnected = TEST_PNOSETTINGS_IS_CONNECTED;
pnoSettings.min5GHzRssi = TEST_PNOSETTINGS_MIN_5GHZ_RSSI;
pnoSettings.min24GHzRssi = TEST_PNOSETTINGS_MIN_2GHZ_RSSI;
+ pnoSettings.min6GHzRssi = TEST_PNOSETTINGS_MIN_6GHZ_RSSI;
pnoSettings.initialScoreMax = TEST_PNOSETTINGS_INITIAL_SCORE_MAX;
pnoSettings.currentConnectionBonus = TEST_PNOSETTINGS_CURRENT_CONNECTION_BONUS;
pnoSettings.sameNetworkBonus = TEST_PNOSETTINGS_SAME_NETWORK_BONUS;
pnoSettings.secureBonus = TEST_PNOSETTINGS_SECURE_BONUS;
pnoSettings.band5GHzBonus = TEST_PNOSETTINGS_BAND_5GHZ_BONUS;
+ pnoSettings.band6GHzBonus = TEST_PNOSETTINGS_BAND_6GHZ_BONUS;
Parcel parcel = Parcel.obtain();
pnoSettings.writeToParcel(parcel, 0);
@@ -200,6 +204,7 @@ public class WifiScannerTest {
assertEquals(TEST_PNOSETTINGS_IS_CONNECTED, pnoSettingsDeserialized.isConnected);
assertEquals(TEST_PNOSETTINGS_MIN_5GHZ_RSSI, pnoSettingsDeserialized.min5GHzRssi);
assertEquals(TEST_PNOSETTINGS_MIN_2GHZ_RSSI, pnoSettingsDeserialized.min24GHzRssi);
+ assertEquals(TEST_PNOSETTINGS_MIN_6GHZ_RSSI, pnoSettingsDeserialized.min6GHzRssi);
assertEquals(TEST_PNOSETTINGS_INITIAL_SCORE_MAX, pnoSettingsDeserialized.initialScoreMax);
assertEquals(TEST_PNOSETTINGS_CURRENT_CONNECTION_BONUS,
pnoSettingsDeserialized.currentConnectionBonus);
@@ -207,6 +212,7 @@ public class WifiScannerTest {
pnoSettingsDeserialized.sameNetworkBonus);
assertEquals(TEST_PNOSETTINGS_SECURE_BONUS, pnoSettingsDeserialized.secureBonus);
assertEquals(TEST_PNOSETTINGS_BAND_5GHZ_BONUS, pnoSettingsDeserialized.band5GHzBonus);
+ assertEquals(TEST_PNOSETTINGS_BAND_6GHZ_BONUS, pnoSettingsDeserialized.band6GHzBonus);
// Test parsing of PnoNetwork
assertEquals(pnoSettings.networkList.length, pnoSettingsDeserialized.networkList.length);