summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Android.mk10
-rw-r--r--api/current.txt1
-rw-r--r--api/system-current.txt1
-rw-r--r--api/test-current.txt1
-rw-r--r--core/java/android/accounts/AccountManager.java92
-rw-r--r--core/java/android/accounts/IAccountManager.aidl2
-rw-r--r--core/java/android/annotation/SystemService.java37
-rw-r--r--core/java/android/app/ActivityManager.java8
-rw-r--r--core/java/android/app/AlarmManager.java10
-rw-r--r--core/java/android/app/AppOpsManager.java8
-rw-r--r--core/java/android/app/BroadcastOptions.java2
-rw-r--r--core/java/android/app/DownloadManager.java10
-rw-r--r--core/java/android/app/KeyguardManager.java6
-rw-r--r--core/java/android/app/Notification.java3
-rw-r--r--core/java/android/app/NotificationManager.java10
-rw-r--r--core/java/android/app/SearchManager.java9
-rw-r--r--core/java/android/app/StatusBarManager.java2
-rw-r--r--core/java/android/app/UiModeManager.java6
-rw-r--r--core/java/android/app/VrManager.java13
-rw-r--r--core/java/android/app/WallpaperManager.java13
-rw-r--r--core/java/android/app/admin/DevicePolicyManager.java28
-rw-r--r--core/java/android/app/backup/BackupManager.java39
-rw-r--r--core/java/android/app/job/JobScheduler.java5
-rw-r--r--core/java/android/app/trust/TrustManager.java3
-rw-r--r--core/java/android/app/usage/NetworkStatsManager.java2
-rw-r--r--core/java/android/app/usage/StorageStatsManager.java2
-rw-r--r--core/java/android/app/usage/UsageStatsManager.java5
-rw-r--r--core/java/android/appwidget/AppWidgetManager.java2
-rw-r--r--core/java/android/bluetooth/BluetoothManager.java2
-rw-r--r--core/java/android/companion/CompanionDeviceManager.java2
-rw-r--r--core/java/android/content/ClipboardManager.java8
-rw-r--r--core/java/android/content/Context.java66
-rw-r--r--core/java/android/content/RestrictionsManager.java2
-rw-r--r--core/java/android/content/pm/LauncherApps.java2
-rw-r--r--core/java/android/content/pm/PackageInstaller.java2
-rw-r--r--core/java/android/content/pm/PackageManager.java18
-rw-r--r--core/java/android/content/pm/ShortcutManager.java30
-rw-r--r--core/java/android/content/res/Configuration.java85
-rw-r--r--core/java/android/hardware/ConsumerIrManager.java9
-rw-r--r--core/java/android/hardware/SensorManager.java8
-rw-r--r--core/java/android/hardware/SerialManager.java2
-rw-r--r--core/java/android/hardware/camera2/CameraManager.java7
-rw-r--r--core/java/android/hardware/display/DisplayManager.java8
-rw-r--r--core/java/android/hardware/fingerprint/FingerprintManager.java7
-rw-r--r--core/java/android/hardware/hdmi/HdmiControlManager.java11
-rw-r--r--core/java/android/hardware/input/InputManager.java8
-rw-r--r--core/java/android/hardware/location/ContextHubManager.java14
-rw-r--r--core/java/android/hardware/radio/RadioManager.java2
-rw-r--r--core/java/android/hardware/usb/UsbManager.java8
-rw-r--r--core/java/android/net/ConnectivityManager.java8
-rw-r--r--core/java/android/net/EthernetManager.java2
-rw-r--r--core/java/android/net/IpSecManager.java7
-rw-r--r--core/java/android/net/NetworkCapabilities.java11
-rw-r--r--core/java/android/net/NetworkPolicyManager.java2
-rw-r--r--core/java/android/net/NetworkScoreManager.java14
-rw-r--r--core/java/android/net/TrafficStats.java3
-rw-r--r--core/java/android/net/VpnService.java2
-rw-r--r--core/java/android/net/nsd/NsdManager.java5
-rw-r--r--core/java/android/nfc/NfcAdapter.java8
-rw-r--r--core/java/android/nfc/NfcManager.java3
-rw-r--r--core/java/android/os/BatteryManager.java3
-rw-r--r--core/java/android/os/BatteryStats.java12
-rw-r--r--core/java/android/os/DropBoxManager.java6
-rw-r--r--core/java/android/os/HardwarePropertiesManager.java2
-rw-r--r--core/java/android/os/IncidentManager.java11
-rw-r--r--core/java/android/os/PowerManager.java10
-rw-r--r--core/java/android/os/RecoverySystem.java15
-rw-r--r--core/java/android/os/UserManager.java24
-rw-r--r--core/java/android/os/Vibrator.java5
-rw-r--r--core/java/android/os/health/SystemHealthManager.java2
-rw-r--r--core/java/android/os/storage/StorageManager.java30
-rw-r--r--core/java/android/print/PrintManager.java10
-rwxr-xr-xcore/java/android/provider/Settings.java7
-rw-r--r--core/java/android/service/autofill/FillContext.java2
-rw-r--r--core/java/android/service/oemlock/OemLockManager.java8
-rw-r--r--core/java/android/service/persistentdata/PersistentDataBlockManager.java22
-rw-r--r--core/java/android/view/HapticFeedbackConstants.java15
-rw-r--r--core/java/android/view/IWindowSession.aidl2
-rw-r--r--core/java/android/view/LayoutInflater.java9
-rw-r--r--core/java/android/view/Surface.java8
-rw-r--r--core/java/android/view/SurfaceView.java135
-rw-r--r--core/java/android/view/ViewGroup.java3
-rw-r--r--core/java/android/view/ViewRootImpl.java20
-rw-r--r--core/java/android/view/WindowManager.java7
-rw-r--r--core/java/android/view/accessibility/AccessibilityManager.java11
-rw-r--r--core/java/android/view/accessibility/CaptioningManager.java9
-rw-r--r--core/java/android/view/autofill/AutofillManager.java2
-rw-r--r--core/java/android/view/inputmethod/InputMethodManager.java4
-rw-r--r--core/java/android/view/textclassifier/TextClassificationManager.java5
-rw-r--r--core/java/android/view/textservice/TextServicesManager.java5
-rw-r--r--core/java/android/widget/Editor.java11
-rw-r--r--core/java/com/android/internal/notification/SystemNotificationChannels.java2
-rw-r--r--core/java/com/android/internal/os/BatteryStatsImpl.java24
-rw-r--r--core/res/AndroidManifest.xml21
-rw-r--r--core/res/res/drawable/stat_sys_vitals.xml29
-rwxr-xr-xcore/res/res/values-mcc310-mnc004/config.xml1
-rwxr-xr-xcore/res/res/values-mcc311-mnc480/config.xml1
-rw-r--r--core/res/res/values/config.xml11
-rw-r--r--core/res/res/values/symbols.xml7
-rw-r--r--core/tests/coretests/src/android/text/DynamicLayoutTest.java27
-rw-r--r--core/tests/coretests/src/com/android/internal/widget/ActionBarContainerTest.java4
-rw-r--r--drm/java/android/drm/DrmUtils.java17
-rw-r--r--libs/hwui/Android.bp2
-rw-r--r--libs/hwui/pipeline/skia/SkiaPipeline.cpp3
-rw-r--r--libs/hwui/renderstate/RenderState.h2
-rw-r--r--libs/hwui/renderthread/CacheManager.cpp187
-rw-r--r--libs/hwui/renderthread/CacheManager.h92
-rw-r--r--libs/hwui/renderthread/CanvasContext.cpp40
-rw-r--r--libs/hwui/renderthread/EglManager.cpp2
-rw-r--r--libs/hwui/renderthread/RenderProxy.cpp13
-rw-r--r--libs/hwui/renderthread/RenderThread.cpp47
-rw-r--r--libs/hwui/renderthread/RenderThread.h6
-rw-r--r--libs/hwui/tests/unit/CacheManagerTests.cpp75
-rw-r--r--location/java/android/location/CountryDetector.java7
-rw-r--r--location/java/android/location/LocationManager.java17
-rw-r--r--lowpan/Android.mk31
-rw-r--r--lowpan/java/android/net/lowpan/ILowpanEnergyScanCallback.aidl23
-rw-r--r--lowpan/java/android/net/lowpan/ILowpanInterface.aidl154
-rw-r--r--lowpan/java/android/net/lowpan/ILowpanInterfaceListener.aidl22
-rw-r--r--lowpan/java/android/net/lowpan/ILowpanManager.aidl35
-rw-r--r--lowpan/java/android/net/lowpan/ILowpanManagerListener.aidl25
-rw-r--r--lowpan/java/android/net/lowpan/ILowpanNetScanCallback.aidl23
-rw-r--r--lowpan/java/android/net/lowpan/LowpanBeaconInfo.java150
-rw-r--r--lowpan/java/android/net/lowpan/LowpanChannelInfo.java87
-rw-r--r--lowpan/java/android/net/lowpan/LowpanCommissioningSession.java73
-rw-r--r--lowpan/java/android/net/lowpan/LowpanCredential.java93
-rw-r--r--lowpan/java/android/net/lowpan/LowpanEnergyScanResult.java54
-rw-r--r--lowpan/java/android/net/lowpan/LowpanException.java290
-rw-r--r--lowpan/java/android/net/lowpan/LowpanIdentity.java179
-rw-r--r--lowpan/java/android/net/lowpan/LowpanInterface.java824
-rw-r--r--lowpan/java/android/net/lowpan/LowpanManager.java283
-rw-r--r--lowpan/java/android/net/lowpan/LowpanProperties.java125
-rw-r--r--lowpan/java/android/net/lowpan/LowpanProperty.java34
-rw-r--r--lowpan/java/android/net/lowpan/LowpanProvision.java104
-rw-r--r--lowpan/java/android/net/lowpan/LowpanScanner.java317
-rw-r--r--lowpan/java/android/net/lowpan/package.html29
-rw-r--r--media/java/android/media/AudioManager.java8
-rw-r--r--media/java/android/media/MediaHTTPConnection.java11
-rw-r--r--media/java/android/media/MediaRouter.java2
-rw-r--r--media/java/android/media/midi/MidiManager.java9
-rw-r--r--media/java/android/media/projection/MediaProjectionManager.java9
-rw-r--r--media/java/android/media/session/MediaSessionManager.java8
-rw-r--r--media/java/android/media/soundtrigger/SoundTriggerDetector.java3
-rw-r--r--media/java/android/media/soundtrigger/SoundTriggerManager.java7
-rw-r--r--media/java/android/media/tv/TvInputManager.java9
-rw-r--r--packages/CarrierDefaultApp/res/values/strings.xml2
-rw-r--r--packages/SettingsLib/res/values/strings.xml10
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/Utils.java17
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/applications/InterestingConfigChanges.java10
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java69
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/wifi/AccessPointPreference.java10
-rw-r--r--packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/AccessPointTest.java38
-rw-r--r--packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/WifiTrackerTest.java18
-rw-r--r--packages/SettingsLib/tests/robotests/src/com/android/settingslib/UtilsTest.java20
-rw-r--r--packages/SystemUI/src/com/android/systemui/Dependency.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/ForegroundServiceController.java49
-rw-r--r--packages/SystemUI/src/com/android/systemui/ForegroundServiceControllerImpl.java156
-rw-r--r--packages/SystemUI/src/com/android/systemui/assist/AssistManager.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/fragments/FragmentHostManager.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSFooter.java10
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/views/AnimationProps.java30
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/views/RecentsEntrancePathInterpolator.java47
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/views/TaskStackAnimationHelper.java11
-rw-r--r--packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java12
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java13
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java17
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java19
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java64
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/volume/VolumeDialogComponent.java3
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/ForegroundServiceControllerTest.java296
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/ExpandableNotificationRowTest.java9
-rw-r--r--proto/src/metrics_constants.proto6
-rw-r--r--services/autofill/java/com/android/server/autofill/Session.java60
-rw-r--r--services/autofill/java/com/android/server/autofill/ViewState.java14
-rw-r--r--services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java4
-rw-r--r--services/autofill/java/com/android/server/autofill/ui/FillUi.java24
-rw-r--r--services/autofill/java/com/android/server/autofill/ui/SaveUi.java26
-rw-r--r--services/core/java/com/android/server/GestureLauncherService.java3
-rw-r--r--services/core/java/com/android/server/accounts/AccountManagerService.java124
-rw-r--r--services/core/java/com/android/server/am/ActiveServices.java10
-rw-r--r--services/core/java/com/android/server/am/BatteryStatsService.java23
-rw-r--r--services/core/java/com/android/server/am/TaskChangeNotificationController.java48
-rw-r--r--services/core/java/com/android/server/connectivity/tethering/OffloadController.java49
-rw-r--r--services/core/java/com/android/server/connectivity/tethering/OffloadHardwareInterface.java21
-rw-r--r--services/core/java/com/android/server/display/DisplayPowerController.java45
-rw-r--r--services/core/java/com/android/server/dreams/DreamManagerService.java12
-rw-r--r--services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java2
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerService.java24
-rw-r--r--services/core/java/com/android/server/pm/UserManagerService.java4
-rw-r--r--services/core/java/com/android/server/policy/PhoneWindowManager.java2
-rw-r--r--services/core/java/com/android/server/wm/AppWindowToken.java2
-rw-r--r--services/core/java/com/android/server/wm/DisplayContent.java4
-rw-r--r--services/core/java/com/android/server/wm/TaskSnapshotController.java19
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerService.java41
-rw-r--r--services/core/java/com/android/server/wm/WindowState.java17
-rw-r--r--services/core/jni/Android.mk1
-rw-r--r--services/core/jni/com_android_server_am_BatteryStatsService.cpp99
-rw-r--r--services/tests/servicestests/AndroidManifest.xml4
-rw-r--r--services/tests/servicestests/src/com/android/server/accounts/AccountManagerServiceTest.java243
-rw-r--r--services/tests/servicestests/src/com/android/server/accounts/AccountManagerServiceTestFixtures.java3
-rw-r--r--services/tests/servicestests/src/com/android/server/accounts/TestAccountType1Authenticator.java2
-rw-r--r--telecomm/java/android/telecom/TelecomManager.java21
-rw-r--r--telephony/java/android/telephony/CarrierConfigManager.java13
-rw-r--r--telephony/java/android/telephony/SmsManager.java3
-rw-r--r--telephony/java/android/telephony/SubscriptionManager.java5
-rw-r--r--telephony/java/android/telephony/TelephonyManager.java64
-rw-r--r--tests/net/java/com/android/server/connectivity/tethering/OffloadControllerTest.java95
-rw-r--r--tools/aapt2/ResourceParser_test.cpp5
-rw-r--r--tools/aapt2/integration-tests/AppOne/AndroidManifest.xml7
-rw-r--r--tools/aapt2/link/ManifestFixer.cpp3
-rw-r--r--tools/aapt2/util/Util.cpp2
-rw-r--r--wifi/java/android/net/wifi/RttManager.java10
-rw-r--r--wifi/java/android/net/wifi/WifiConfiguration.java2
-rw-r--r--wifi/java/android/net/wifi/WifiManager.java49
-rw-r--r--wifi/java/android/net/wifi/WifiScanner.java20
-rw-r--r--wifi/java/android/net/wifi/aware/WifiAwareManager.java6
-rw-r--r--wifi/java/android/net/wifi/p2p/IWifiP2pManager.aidl3
-rw-r--r--wifi/java/android/net/wifi/p2p/WifiP2pManager.java35
224 files changed, 6298 insertions, 718 deletions
diff --git a/Android.mk b/Android.mk
index 6631adace544..313f329f50af 100644
--- a/Android.mk
+++ b/Android.mk
@@ -566,6 +566,15 @@ LOCAL_SRC_FILES += \
LOCAL_AIDL_INCLUDES += system/update_engine/binder_bindings
+LOCAL_AIDL_INCLUDES += frameworks/base/lowpan/java
+LOCAL_SRC_FILES += \
+ lowpan/java/android/net/lowpan/ILowpanEnergyScanCallback.aidl \
+ lowpan/java/android/net/lowpan/ILowpanNetScanCallback.aidl \
+ lowpan/java/android/net/lowpan/ILowpanInterfaceListener.aidl \
+ lowpan/java/android/net/lowpan/ILowpanInterface.aidl \
+ lowpan/java/android/net/lowpan/ILowpanManagerListener.aidl \
+ lowpan/java/android/net/lowpan/ILowpanManager.aidl
+
# FRAMEWORKS_BASE_JAVA_SRC_DIRS comes from build/core/pathmap.mk
LOCAL_AIDL_INCLUDES += \
$(FRAMEWORKS_BASE_JAVA_SRC_DIRS) \
@@ -967,6 +976,7 @@ framework_docs_LOCAL_DROIDDOC_OPTIONS := \
-android \
-knowntags ./frameworks/base/docs/knowntags.txt \
-knowntags ./libcore/known_oj_tags.txt \
+ -manifest ./frameworks/base/core/res/AndroidManifest.xml \
-hidePackage com.android.org.conscrypt \
-since $(SRC_API_DIR)/1.xml 1 \
-since $(SRC_API_DIR)/2.xml 2 \
diff --git a/api/current.txt b/api/current.txt
index c4ddfaf359c6..a71c63ae598c 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -43936,6 +43936,7 @@ package android.view {
field public static final int KEYBOARD_TAP = 3; // 0x3
field public static final int LONG_PRESS = 0; // 0x0
field public static final int VIRTUAL_KEY = 1; // 0x1
+ field public static final int VIRTUAL_KEY_RELEASE = 7; // 0x7
}
public class InflateException extends java.lang.RuntimeException {
diff --git a/api/system-current.txt b/api/system-current.txt
index f0f019a12219..fbe210925ab3 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -47483,6 +47483,7 @@ package android.view {
field public static final int KEYBOARD_TAP = 3; // 0x3
field public static final int LONG_PRESS = 0; // 0x0
field public static final int VIRTUAL_KEY = 1; // 0x1
+ field public static final int VIRTUAL_KEY_RELEASE = 7; // 0x7
}
public class InflateException extends java.lang.RuntimeException {
diff --git a/api/test-current.txt b/api/test-current.txt
index 201d9b3f6ddf..d586670b53f9 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -44319,6 +44319,7 @@ package android.view {
field public static final int KEYBOARD_TAP = 3; // 0x3
field public static final int LONG_PRESS = 0; // 0x0
field public static final int VIRTUAL_KEY = 1; // 0x1
+ field public static final int VIRTUAL_KEY_RELEASE = 7; // 0x7
}
public class InflateException extends java.lang.RuntimeException {
diff --git a/core/java/android/accounts/AccountManager.java b/core/java/android/accounts/AccountManager.java
index 8fd8043a772a..a446296fe393 100644
--- a/core/java/android/accounts/AccountManager.java
+++ b/core/java/android/accounts/AccountManager.java
@@ -24,6 +24,7 @@ import android.annotation.RequiresPermission;
import android.annotation.SdkConstant;
import android.annotation.Size;
import android.annotation.SystemApi;
+import android.annotation.SystemService;
import android.annotation.SdkConstant.SdkConstantType;
import android.annotation.BroadcastBehavior;
import android.app.Activity;
@@ -161,6 +162,7 @@ import java.util.concurrent.TimeoutException;
* the application's main event thread. These operations throw
* {@link IllegalStateException} if they are used on the main thread.
*/
+@SystemService(Context.ACCOUNT_SERVICE)
public class AccountManager {
private static final String TAG = "AccountManager";
@@ -2509,6 +2511,18 @@ public class AccountManager {
return new AuthenticatorException(message);
}
+ private void getAccountByTypeAndFeatures(String accountType, String[] features,
+ AccountManagerCallback<Bundle> callback, Handler handler) {
+ (new AmsTask(null, handler, callback) {
+ @Override
+ public void doWork() throws RemoteException {
+ mService.getAccountByTypeAndFeatures(mResponse, accountType, features,
+ mContext.getOpPackageName());
+ }
+
+ }).start();
+ }
+
private class GetAuthTokenByTypeAndFeaturesTask
extends AmsTask implements AccountManagerCallback<Bundle> {
GetAuthTokenByTypeAndFeaturesTask(final String accountType, final String authTokenType,
@@ -2535,13 +2549,16 @@ public class AccountManager {
@Override
public void doWork() throws RemoteException {
- getAccountsByTypeAndFeatures(mAccountType, mFeatures,
- new AccountManagerCallback<Account[]>() {
+ getAccountByTypeAndFeatures(mAccountType, mFeatures,
+ new AccountManagerCallback<Bundle>() {
@Override
- public void run(AccountManagerFuture<Account[]> future) {
- Account[] accounts;
+ public void run(AccountManagerFuture<Bundle> future) {
+ String accountName = null;
+ String accountType = null;
try {
- accounts = future.getResult();
+ Bundle result = future.getResult();
+ accountName = result.getString(AccountManager.KEY_ACCOUNT_NAME);
+ accountType = result.getString(AccountManager.KEY_ACCOUNT_TYPE);
} catch (OperationCanceledException e) {
setException(e);
return;
@@ -2553,9 +2570,7 @@ public class AccountManager {
return;
}
- mNumAccounts = accounts.length;
-
- if (accounts.length == 0) {
+ if (accountName == null) {
if (mActivity != null) {
// no accounts, add one now. pretend that the user directly
// made this request
@@ -2575,63 +2590,17 @@ public class AccountManager {
}
// we are done
}
- } else if (accounts.length == 1) {
+ } else {
+ mNumAccounts = 1;
+ Account account = new Account(accountName, accountType);
// have a single account, return an authtoken for it
if (mActivity == null) {
- mFuture = getAuthToken(accounts[0], mAuthTokenType,
+ mFuture = getAuthToken(account, mAuthTokenType,
false /* notifyAuthFailure */, mMyCallback, mHandler);
} else {
- mFuture = getAuthToken(accounts[0],
- mAuthTokenType, mLoginOptions,
+ mFuture = getAuthToken(account, mAuthTokenType, mLoginOptions,
mActivity, mMyCallback, mHandler);
}
- } else {
- if (mActivity != null) {
- IAccountManagerResponse chooseResponse =
- new IAccountManagerResponse.Stub() {
- @Override
- public void onResult(Bundle value) throws RemoteException {
- Account account = new Account(
- value.getString(KEY_ACCOUNT_NAME),
- value.getString(KEY_ACCOUNT_TYPE),
- value.getString(KEY_ACCOUNT_ACCESS_ID));
- mFuture = getAuthToken(account, mAuthTokenType,
- mLoginOptions, mActivity, mMyCallback,
- mHandler);
- }
-
- @Override
- public void onError(int errorCode, String errorMessage)
- throws RemoteException {
- mResponse.onError(errorCode, errorMessage);
- }
- };
- // have many accounts, launch the chooser
- Intent intent = new Intent();
- // TODO - this activity will not include
- // USER_MANAGED_NOT_VISIBLE
- // accounts. We need to move method to service
- ComponentName componentName = ComponentName.unflattenFromString(
- Resources.getSystem().getString(
- R.string.config_chooseAccountActivity));
- intent.setClassName(componentName.getPackageName(),
- componentName.getClassName());
- intent.putExtra(KEY_ACCOUNTS, accounts);
- intent.putExtra(KEY_ACCOUNT_MANAGER_RESPONSE,
- new AccountManagerResponse(chooseResponse));
- mActivity.startActivity(intent);
- // the result will arrive via the IAccountManagerResponse
- } else {
- // send result since we can't prompt to select an account
- Bundle result = new Bundle();
- result.putString(KEY_ACCOUNTS, null);
- try {
- mResponse.onResult(result);
- } catch (RemoteException e) {
- // this will never happen
- }
- // we are done
- }
}
}}, mHandler);
}
@@ -2721,8 +2690,8 @@ public class AccountManager {
public AccountManagerFuture<Bundle> getAuthTokenByFeatures(
final String accountType, final String authTokenType, final String[] features,
final Activity activity, final Bundle addAccountOptions,
- final Bundle getAuthTokenOptions,
- final AccountManagerCallback<Bundle> callback, final Handler handler) {
+ final Bundle getAuthTokenOptions, final AccountManagerCallback<Bundle> callback,
+ final Handler handler) {
if (accountType == null) throw new IllegalArgumentException("account type is null");
if (authTokenType == null) throw new IllegalArgumentException("authTokenType is null");
final GetAuthTokenByTypeAndFeaturesTask task =
@@ -3237,6 +3206,7 @@ public class AccountManager {
* @hide
*/
@SystemApi
+ @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL)
public AccountManagerFuture<Bundle> finishSessionAsUser(
final Bundle sessionBundle,
final Activity activity,
diff --git a/core/java/android/accounts/IAccountManager.aidl b/core/java/android/accounts/IAccountManager.aidl
index 7494cfc383b4..4cf0a2089fe5 100644
--- a/core/java/android/accounts/IAccountManager.aidl
+++ b/core/java/android/accounts/IAccountManager.aidl
@@ -40,6 +40,8 @@ interface IAccountManager {
Account[] getAccountsAsUser(String accountType, int userId, String opPackageName);
void hasFeatures(in IAccountManagerResponse response, in Account account, in String[] features,
String opPackageName);
+ void getAccountByTypeAndFeatures(in IAccountManagerResponse response, String accountType,
+ in String[] features, String opPackageName);
void getAccountsByFeatures(in IAccountManagerResponse response, String accountType,
in String[] features, String opPackageName);
boolean addAccountExplicitly(in Account account, String password, in Bundle extras);
diff --git a/core/java/android/annotation/SystemService.java b/core/java/android/annotation/SystemService.java
new file mode 100644
index 000000000000..ba5002a4f1b5
--- /dev/null
+++ b/core/java/android/annotation/SystemService.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.annotation;
+
+import static java.lang.annotation.ElementType.TYPE;
+import static java.lang.annotation.RetentionPolicy.SOURCE;
+
+import android.content.Context;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+/**
+ * Description of a system service available through
+ * {@link Context#getSystemService(Class)}.
+ *
+ * @hide
+ */
+@Retention(SOURCE)
+@Target(TYPE)
+public @interface SystemService {
+ String value();
+}
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index dec5f4ffc439..199e856e7a22 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -22,6 +22,7 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
import android.annotation.SystemApi;
+import android.annotation.SystemService;
import android.annotation.TestApi;
import android.content.pm.ActivityInfo;
import android.content.res.Configuration;
@@ -117,6 +118,7 @@ import java.util.List;
* be used for testing and debugging purposes only.
* </p>
*/
+@SystemService(Context.ACTIVITY_SERVICE)
public class ActivityManager {
private static String TAG = "ActivityManager";
@@ -3626,6 +3628,7 @@ public class ActivityManager {
* @hide
*/
@SystemApi @TestApi
+ @RequiresPermission(Manifest.permission.PACKAGE_USAGE_STATS)
public void addOnUidImportanceListener(OnUidImportanceListener listener,
@RunningAppProcessInfo.Importance int importanceCutpoint) {
synchronized (this) {
@@ -3654,6 +3657,7 @@ public class ActivityManager {
* @hide
*/
@SystemApi @TestApi
+ @RequiresPermission(Manifest.permission.PACKAGE_USAGE_STATS)
public void removeOnUidImportanceListener(OnUidImportanceListener listener) {
synchronized (this) {
UidObserver observer = mImportanceListeners.remove(listener);
@@ -4021,6 +4025,10 @@ public class ActivityManager {
* @hide
*/
@SystemApi
+ @RequiresPermission(anyOf = {
+ "android.permission.INTERACT_ACROSS_USERS",
+ "android.permission.INTERACT_ACROSS_USERS_FULL"
+ })
public static int getCurrentUser() {
UserInfo ui;
try {
diff --git a/core/java/android/app/AlarmManager.java b/core/java/android/app/AlarmManager.java
index 620e5cf374ca..2813e8b9707e 100644
--- a/core/java/android/app/AlarmManager.java
+++ b/core/java/android/app/AlarmManager.java
@@ -17,8 +17,10 @@
package android.app;
import android.annotation.IntDef;
+import android.annotation.RequiresPermission;
import android.annotation.SdkConstant;
import android.annotation.SystemApi;
+import android.annotation.SystemService;
import android.content.Context;
import android.content.Intent;
import android.os.Build;
@@ -72,12 +74,8 @@ import java.lang.annotation.RetentionPolicy;
* {@link #setExact(int, long, PendingIntent)}. Applications whose {@code targetSdkVersion}
* is earlier than API 19 will continue to see the previous behavior in which all
* alarms are delivered exactly when requested.
- *
- * <p>You do not
- * instantiate this class directly; instead, retrieve it through
- * {@link android.content.Context#getSystemService
- * Context.getSystemService(Context.ALARM_SERVICE)}.
*/
+@SystemService(Context.ALARM_SERVICE)
public class AlarmManager {
private static final String TAG = "AlarmManager";
@@ -599,6 +597,7 @@ public class AlarmManager {
/** @hide */
@SystemApi
+ @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS)
public void set(@AlarmType int type, long triggerAtMillis, long windowMillis,
long intervalMillis, PendingIntent operation, WorkSource workSource) {
setImpl(type, triggerAtMillis, windowMillis, intervalMillis, 0, operation, null, null,
@@ -633,6 +632,7 @@ public class AlarmManager {
* @hide
*/
@SystemApi
+ @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS)
public void set(@AlarmType int type, long triggerAtMillis, long windowMillis,
long intervalMillis, OnAlarmListener listener, Handler targetHandler,
WorkSource workSource) {
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index 82921524457f..e672ada3cbb4 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -17,7 +17,9 @@
package android.app;
import android.Manifest;
+import android.annotation.RequiresPermission;
import android.annotation.SystemApi;
+import android.annotation.SystemService;
import android.app.usage.UsageStatsManager;
import android.content.Context;
import android.media.AudioAttributes.AttributeUsage;
@@ -42,10 +44,9 @@ import java.util.List;
* API for interacting with "application operation" tracking.
*
* <p>This API is not generally intended for third party application developers; most
- * features are only available to system applications. Obtain an instance of it through
- * {@link Context#getSystemService(String) Context.getSystemService} with
- * {@link Context#APP_OPS_SERVICE Context.APP_OPS_SERVICE}.</p>
+ * features are only available to system applications.
*/
+@SystemService(Context.APP_OPS_SERVICE)
public class AppOpsManager {
/**
* <p>App ops allows callers to:</p>
@@ -1409,6 +1410,7 @@ public class AppOpsManager {
* @hide
*/
@SystemApi
+ @RequiresPermission(android.Manifest.permission.UPDATE_APP_OPS_STATS)
public void setUidMode(String appOp, int uid, int mode) {
try {
mService.setUidMode(AppOpsManager.strOpToOp(appOp), uid, mode);
diff --git a/core/java/android/app/BroadcastOptions.java b/core/java/android/app/BroadcastOptions.java
index 175b9799c5db..b6cff385d752 100644
--- a/core/java/android/app/BroadcastOptions.java
+++ b/core/java/android/app/BroadcastOptions.java
@@ -16,6 +16,7 @@
package android.app;
+import android.annotation.RequiresPermission;
import android.annotation.SystemApi;
import android.os.Build;
import android.os.Bundle;
@@ -72,6 +73,7 @@ public class BroadcastOptions {
* power whitelist when this broadcast is being delivered to it.
* @param duration The duration in milliseconds; 0 means to not place on whitelist.
*/
+ @RequiresPermission(android.Manifest.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST)
public void setTemporaryAppWhitelistDuration(long duration) {
mTemporaryAppWhitelistDuration = duration;
}
diff --git a/core/java/android/app/DownloadManager.java b/core/java/android/app/DownloadManager.java
index b89c16539b4c..5baaeb30e233 100644
--- a/core/java/android/app/DownloadManager.java
+++ b/core/java/android/app/DownloadManager.java
@@ -19,6 +19,7 @@ package android.app;
import android.annotation.Nullable;
import android.annotation.SdkConstant;
import android.annotation.SystemApi;
+import android.annotation.SystemService;
import android.annotation.SdkConstant.SdkConstantType;
import android.content.ContentResolver;
import android.content.ContentUris;
@@ -51,18 +52,15 @@ import java.util.List;
* request that a URI be downloaded to a particular destination file. The download manager will
* conduct the download in the background, taking care of HTTP interactions and retrying downloads
* after failures or across connectivity changes and system reboots.
- *
- * Instances of this class should be obtained through
- * {@link android.content.Context#getSystemService(String)} by passing
- * {@link android.content.Context#DOWNLOAD_SERVICE}.
- *
+ * <p>
* Apps that request downloads through this API should register a broadcast receiver for
* {@link #ACTION_NOTIFICATION_CLICKED} to appropriately handle when the user clicks on a running
* download in a notification or from the downloads UI.
- *
+ * <p>
* Note that the application must have the {@link android.Manifest.permission#INTERNET}
* permission to use this class.
*/
+@SystemService(Context.DOWNLOAD_SERVICE)
public class DownloadManager {
/**
diff --git a/core/java/android/app/KeyguardManager.java b/core/java/android/app/KeyguardManager.java
index 4a0b644d758a..16b21f15353e 100644
--- a/core/java/android/app/KeyguardManager.java
+++ b/core/java/android/app/KeyguardManager.java
@@ -20,6 +20,7 @@ import android.Manifest;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
+import android.annotation.SystemService;
import android.app.trust.ITrustManager;
import android.content.Context;
import android.content.Intent;
@@ -46,12 +47,11 @@ import com.android.internal.widget.LockPatternUtils;
import java.util.List;
/**
- * Class that can be used to lock and unlock the keyboard. Get an instance of this
- * class by calling {@link android.content.Context#getSystemService(java.lang.String)}
- * with argument {@link android.content.Context#KEYGUARD_SERVICE}. The
+ * Class that can be used to lock and unlock the keyboard. The
* actual class to control the keyboard locking is
* {@link android.app.KeyguardManager.KeyguardLock}.
*/
+@SystemService(Context.KEYGUARD_SERVICE)
public class KeyguardManager {
private static final String TAG = "KeyguardManager";
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index df9b64cb7b86..03e9c0a1c9f7 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -22,6 +22,7 @@ import android.annotation.ColorInt;
import android.annotation.DrawableRes;
import android.annotation.IntDef;
import android.annotation.NonNull;
+import android.annotation.RequiresPermission;
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
import android.annotation.SystemApi;
@@ -1009,6 +1010,7 @@ public class Notification implements Parcelable
* @hide
*/
@SystemApi
+ @RequiresPermission(android.Manifest.permission.NOTIFICATION_DURING_SETUP)
public static final String EXTRA_ALLOW_DURING_SETUP = "android.allowDuringSetup";
/**
@@ -1110,6 +1112,7 @@ public class Notification implements Parcelable
/** @hide */
@SystemApi
+ @RequiresPermission(android.Manifest.permission.SUBSTITUTE_NOTIFICATION_APP_NAME)
public static final String EXTRA_SUBSTITUTE_APP_NAME = "android.substName";
/**
diff --git a/core/java/android/app/NotificationManager.java b/core/java/android/app/NotificationManager.java
index 6c55548c2ea4..235b8d445b1c 100644
--- a/core/java/android/app/NotificationManager.java
+++ b/core/java/android/app/NotificationManager.java
@@ -20,6 +20,7 @@ import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SdkConstant;
+import android.annotation.SystemService;
import android.annotation.TestApi;
import android.app.Notification.Builder;
import android.content.ComponentName;
@@ -81,10 +82,6 @@ import java.util.Objects;
* to the {@link #cancel(int)} or {@link #cancel(String, int)} method to clear
* this notification.
*
- * <p>
- * You do not instantiate this class directly; instead, retrieve it through
- * {@link android.content.Context#getSystemService}.
- *
* <div class="special reference">
* <h3>Developer Guides</h3>
* <p>For a guide to creating notifications, read the
@@ -93,10 +90,9 @@ import java.util.Objects;
* </div>
*
* @see android.app.Notification
- * @see android.content.Context#getSystemService
*/
-public class NotificationManager
-{
+@SystemService(Context.NOTIFICATION_SERVICE)
+public class NotificationManager {
private static String TAG = "NotificationManager";
private static boolean localLOGV = false;
diff --git a/core/java/android/app/SearchManager.java b/core/java/android/app/SearchManager.java
index c529e4ba1678..ea990ad2924e 100644
--- a/core/java/android/app/SearchManager.java
+++ b/core/java/android/app/SearchManager.java
@@ -16,6 +16,7 @@
package android.app;
+import android.annotation.SystemService;
import android.content.ActivityNotFoundException;
import android.content.ComponentName;
import android.content.ContentResolver;
@@ -46,10 +47,6 @@ import java.util.List;
* services are provided through methods in {@link android.app.Activity Activity}
* and the {@link android.content.Intent#ACTION_SEARCH ACTION_SEARCH}
* {@link android.content.Intent Intent}.
- * If you do require direct access to the SearchManager, do not instantiate
- * this class directly. Instead, retrieve it through
- * {@link android.content.Context#getSystemService
- * context.getSystemService(Context.SEARCH_SERVICE)}.
*
* <div class="special reference">
* <h3>Developer Guides</h3>
@@ -58,9 +55,9 @@ import java.util.List;
* <a href="{@docRoot}guide/topics/search/index.html">Search</a> developer guide.</p>
* </div>
*/
+@SystemService(Context.SEARCH_SERVICE)
public class SearchManager
- implements DialogInterface.OnDismissListener, DialogInterface.OnCancelListener
-{
+ implements DialogInterface.OnDismissListener, DialogInterface.OnCancelListener {
private static final boolean DBG = false;
private static final String TAG = "SearchManager";
diff --git a/core/java/android/app/StatusBarManager.java b/core/java/android/app/StatusBarManager.java
index ab301bdedcac..4a092140ed78 100644
--- a/core/java/android/app/StatusBarManager.java
+++ b/core/java/android/app/StatusBarManager.java
@@ -18,6 +18,7 @@
package android.app;
import android.annotation.IntDef;
+import android.annotation.SystemService;
import android.content.Context;
import android.os.Binder;
import android.os.RemoteException;
@@ -36,6 +37,7 @@ import java.lang.annotation.RetentionPolicy;
*
* @hide
*/
+@SystemService(Context.STATUS_BAR_SERVICE)
public class StatusBarManager {
public static final int DISABLE_EXPAND = View.STATUS_BAR_DISABLE_EXPAND;
diff --git a/core/java/android/app/UiModeManager.java b/core/java/android/app/UiModeManager.java
index 07e257083fa2..bc616686eced 100644
--- a/core/java/android/app/UiModeManager.java
+++ b/core/java/android/app/UiModeManager.java
@@ -17,6 +17,7 @@
package android.app;
import android.annotation.IntDef;
+import android.annotation.SystemService;
import android.annotation.TestApi;
import android.content.Context;
import android.content.res.Configuration;
@@ -49,11 +50,8 @@ import java.lang.annotation.RetentionPolicy;
* displayed allowing the user to exit dock mode. Thus the dock mode
* represented here may be different than the current state of the underlying
* dock event broadcast.
- *
- * <p>You do not instantiate this class directly; instead, retrieve it through
- * {@link android.content.Context#getSystemService
- * Context.getSystemService(Context.UI_MODE_SERVICE)}.
*/
+@SystemService(Context.UI_MODE_SERVICE)
public class UiModeManager {
private static final String TAG = "UiModeManager";
diff --git a/core/java/android/app/VrManager.java b/core/java/android/app/VrManager.java
index 8014ecafa9a2..b40c96c6f0c8 100644
--- a/core/java/android/app/VrManager.java
+++ b/core/java/android/app/VrManager.java
@@ -1,19 +1,20 @@
package android.app;
+import android.annotation.RequiresPermission;
import android.annotation.SystemApi;
+import android.annotation.SystemService;
import android.content.ComponentName;
+import android.content.Context;
import android.os.RemoteException;
import android.service.vr.IVrManager;
/**
* Used to control aspects of a devices Virtual Reality (VR) capabilities.
- * <p>
- * You do not instantiate this class directly; instead, retrieve it through
- * {@link android.content.Context#getSystemService}.
* @hide
*/
@SystemApi
+@SystemService(Context.VR_SERVICE)
public class VrManager {
private final IVrManager mService;
@@ -29,11 +30,10 @@ public class VrManager {
* remain in VR mode even if the foreground does not specify Vr mode being enabled. Mainly used
* by VR viewers to indicate that a device is placed in a VR viewer.
*
- * <p>Requires {@link android.Manifest.permission#ACCESS_VR_MANAGER} permission.</p>
- *
* @see Activity#setVrModeEnabled(boolean, ComponentName)
* @param enabled true if the device should be placed in persistent VR mode.
*/
+ @RequiresPermission(android.Manifest.permission.RESTRICTED_VR_ACCESS)
public void setPersistentVrModeEnabled(boolean enabled) {
try {
mService.setPersistentVrModeEnabled(enabled);
@@ -46,13 +46,12 @@ public class VrManager {
* Sets the resolution and DPI of the vr2d virtual display used to display 2D
* applications in VR mode.
*
- * <p>Requires {@link android.Manifest.permission#ACCESS_VR_MANAGER} permission.</p>
- *
* @param vr2dDisplayProp properties to be set to the virtual display for
* 2D applications in VR mode.
*
* {@hide}
*/
+ @RequiresPermission(android.Manifest.permission.RESTRICTED_VR_ACCESS)
public void setVr2dDisplayProperties(
Vr2dDisplayProperties vr2dDisplayProp) {
try {
diff --git a/core/java/android/app/WallpaperManager.java b/core/java/android/app/WallpaperManager.java
index 8a33791adfdb..dfcbfc4f8e09 100644
--- a/core/java/android/app/WallpaperManager.java
+++ b/core/java/android/app/WallpaperManager.java
@@ -20,8 +20,10 @@ import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.RawRes;
+import android.annotation.RequiresPermission;
import android.annotation.SdkConstant;
import android.annotation.SystemApi;
+import android.annotation.SystemService;
import android.annotation.SdkConstant.SdkConstantType;
import android.content.ComponentName;
import android.content.ContentResolver;
@@ -80,13 +82,13 @@ import java.util.concurrent.TimeUnit;
/**
* Provides access to the system wallpaper. With WallpaperManager, you can
* get the current wallpaper, get the desired dimensions for the wallpaper, set
- * the wallpaper, and more. Get an instance of WallpaperManager with
- * {@link #getInstance(android.content.Context) getInstance()}.
+ * the wallpaper, and more.
*
* <p> An app can check whether wallpapers are supported for the current user, by calling
* {@link #isWallpaperSupported()}, and whether setting of wallpapers is allowed, by calling
* {@link #isSetWallpaperAllowed()}.
*/
+@SystemService(Context.WALLPAPER_SERVICE)
public class WallpaperManager {
private static String TAG = "WallpaperManager";
private static boolean DEBUG = false;
@@ -1485,6 +1487,7 @@ public class WallpaperManager {
* @hide
*/
@SystemApi
+ @RequiresPermission(android.Manifest.permission.SET_WALLPAPER_HINTS)
public void setDisplayPadding(Rect padding) {
try {
if (sGlobals.mService == null) {
@@ -1525,6 +1528,7 @@ public class WallpaperManager {
* @hide
*/
@SystemApi
+ @RequiresPermission(android.Manifest.permission.SET_WALLPAPER)
public void clearWallpaper() {
clearWallpaper(FLAG_LOCK, mContext.getUserId());
clearWallpaper(FLAG_SYSTEM, mContext.getUserId());
@@ -1537,6 +1541,7 @@ public class WallpaperManager {
* @hide
*/
@SystemApi
+ @RequiresPermission(android.Manifest.permission.SET_WALLPAPER)
public void clearWallpaper(@SetWallpaperFlags int which, int userId) {
if (sGlobals.mService == null) {
Log.w(TAG, "WallpaperService not running");
@@ -1552,12 +1557,10 @@ public class WallpaperManager {
/**
* Set the live wallpaper.
*
- * This can only be called by packages with android.permission.SET_WALLPAPER_COMPONENT
- * permission.
- *
* @hide
*/
@SystemApi
+ @RequiresPermission(android.Manifest.permission.SET_WALLPAPER_COMPONENT)
public boolean setWallpaperComponent(ComponentName name) {
return setWallpaperComponent(name, UserHandle.myUserId());
}
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 9e0d4e7b23c7..ff9425ebd155 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -20,9 +20,12 @@ import android.annotation.ColorInt;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
+import android.annotation.SuppressLint;
import android.annotation.SystemApi;
+import android.annotation.SystemService;
import android.annotation.TestApi;
import android.annotation.UserIdInt;
import android.annotation.WorkerThread;
@@ -98,6 +101,7 @@ import java.util.Set;
* "{@docRoot}guide/topics/admin/device-admin.html">Device Administration</a> developer
* guide. </div>
*/
+@SystemService(Context.DEVICE_POLICY_SERVICE)
public class DevicePolicyManager {
private static String TAG = "DevicePolicyManager";
@@ -1621,6 +1625,7 @@ public class DevicePolicyManager {
* @hide
*/
@SystemApi
+ @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL)
public boolean packageHasActiveAdmins(String packageName) {
return packageHasActiveAdmins(packageName, myUserId());
}
@@ -4532,11 +4537,10 @@ public class DevicePolicyManager {
/**
* @return device owner component name, even if it's running on a different user.
*
- * <p>Requires the MANAGE_USERS permission.
- *
* @hide
*/
@SystemApi
+ @RequiresPermission(android.Manifest.permission.MANAGE_USERS)
public ComponentName getDeviceOwnerComponentOnAnyUser() {
return getDeviceOwnerComponentInner(/* callingUserOnly =*/ false);
}
@@ -4620,6 +4624,7 @@ public class DevicePolicyManager {
* @hide
*/
@SystemApi
+ @RequiresPermission(android.Manifest.permission.MANAGE_USERS)
public @Nullable String getDeviceOwner() {
throwIfParentInstance("getDeviceOwner");
final ComponentName name = getDeviceOwnerComponentOnCallingUser();
@@ -4637,6 +4642,7 @@ public class DevicePolicyManager {
*/
@SystemApi
@TestApi
+ @SuppressLint("Doclava125")
public boolean isDeviceManaged() {
try {
return mService.hasDeviceOwner();
@@ -4649,11 +4655,10 @@ public class DevicePolicyManager {
* Returns the device owner name. Note this method *will* return the device owner
* name when it's running on a different user.
*
- * <p>Requires the MANAGE_USERS permission.
- *
* @hide
*/
@SystemApi
+ @RequiresPermission(android.Manifest.permission.MANAGE_USERS)
public String getDeviceOwnerNameOnAnyUser() {
throwIfParentInstance("getDeviceOwnerNameOnAnyUser");
if (mService != null) {
@@ -4673,6 +4678,7 @@ public class DevicePolicyManager {
*/
@Deprecated
@SystemApi
+ @SuppressLint("Doclava125")
public @Nullable String getDeviceInitializerApp() {
return null;
}
@@ -4684,6 +4690,7 @@ public class DevicePolicyManager {
*/
@Deprecated
@SystemApi
+ @SuppressLint("Doclava125")
public @Nullable ComponentName getDeviceInitializerComponent() {
return null;
}
@@ -4706,6 +4713,7 @@ public class DevicePolicyManager {
*/
@Deprecated
@SystemApi
+ @RequiresPermission(android.Manifest.permission.MANAGE_DEVICE_ADMINS)
public boolean setActiveProfileOwner(@NonNull ComponentName admin, @Deprecated String ownerName)
throws IllegalArgumentException {
throwIfParentInstance("setActiveProfileOwner");
@@ -5023,6 +5031,7 @@ public class DevicePolicyManager {
* @throws IllegalArgumentException if the userId is invalid.
*/
@SystemApi
+ @RequiresPermission(android.Manifest.permission.MANAGE_USERS)
public @Nullable String getProfileOwnerNameAsUser(int userId) throws IllegalArgumentException {
throwIfParentInstance("getProfileOwnerNameAsUser");
if (mService != null) {
@@ -6793,8 +6802,7 @@ public class DevicePolicyManager {
* Called by the system update service to notify device and profile owners of pending system
* updates.
*
- * The caller must hold {@link android.Manifest.permission#NOTIFY_PENDING_SYSTEM_UPDATE}
- * permission. This method should only be used when it is unknown whether the pending system
+ * This method should only be used when it is unknown whether the pending system
* update is a security patch. Otherwise, use
* {@link #notifyPendingSystemUpdate(long, boolean)}.
*
@@ -6805,6 +6813,7 @@ public class DevicePolicyManager {
* @hide
*/
@SystemApi
+ @RequiresPermission(android.Manifest.permission.NOTIFY_PENDING_SYSTEM_UPDATE)
public void notifyPendingSystemUpdate(long updateReceivedTime) {
throwIfParentInstance("notifyPendingSystemUpdate");
if (mService != null) {
@@ -6820,8 +6829,7 @@ public class DevicePolicyManager {
* Called by the system update service to notify device and profile owners of pending system
* updates.
*
- * The caller must hold {@link android.Manifest.permission#NOTIFY_PENDING_SYSTEM_UPDATE}
- * permission. This method should be used instead of {@link #notifyPendingSystemUpdate(long)}
+ * This method should be used instead of {@link #notifyPendingSystemUpdate(long)}
* when it is known whether the pending system update is a security patch.
*
* @param updateReceivedTime The time as given by {@link System#currentTimeMillis()}
@@ -6833,6 +6841,7 @@ public class DevicePolicyManager {
* @hide
*/
@SystemApi
+ @RequiresPermission(android.Manifest.permission.NOTIFY_PENDING_SYSTEM_UPDATE)
public void notifyPendingSystemUpdate(long updateReceivedTime, boolean isSecurityPatch) {
throwIfParentInstance("notifyPendingSystemUpdate");
if (mService != null) {
@@ -7541,6 +7550,7 @@ public class DevicePolicyManager {
*/
@SystemApi
@TestApi
+ @SuppressLint("Doclava125")
public @Nullable CharSequence getDeviceOwnerOrganizationName() {
try {
return mService.getDeviceOwnerOrganizationName();
@@ -7731,6 +7741,7 @@ public class DevicePolicyManager {
* @hide
*/
@SystemApi
+ @RequiresPermission(android.Manifest.permission.MANAGE_USERS)
public void setDeviceProvisioningConfigApplied() {
try {
mService.setDeviceProvisioningConfigApplied();
@@ -7751,6 +7762,7 @@ public class DevicePolicyManager {
* @hide
*/
@SystemApi
+ @RequiresPermission(android.Manifest.permission.MANAGE_USERS)
public boolean isDeviceProvisioningConfigApplied() {
try {
return mService.isDeviceProvisioningConfigApplied();
diff --git a/core/java/android/app/backup/BackupManager.java b/core/java/android/app/backup/BackupManager.java
index 9d02f53b13bd..9f9b217069d8 100644
--- a/core/java/android/app/backup/BackupManager.java
+++ b/core/java/android/app/backup/BackupManager.java
@@ -16,6 +16,7 @@
package android.app.backup;
+import android.annotation.RequiresPermission;
import android.annotation.SystemApi;
import android.content.ComponentName;
import android.content.Context;
@@ -324,6 +325,7 @@ public class BackupManager {
* @hide
*/
@SystemApi
+ @RequiresPermission(android.Manifest.permission.BACKUP)
public RestoreSession beginRestoreSession() {
RestoreSession session = null;
checkServiceBinder();
@@ -348,11 +350,10 @@ public class BackupManager {
* mechanism was disabled will still be backed up properly if it is enabled
* at some point in the future.
*
- * <p>Callers must hold the android.permission.BACKUP permission to use this method.
- *
* @hide
*/
@SystemApi
+ @RequiresPermission(android.Manifest.permission.BACKUP)
public void setBackupEnabled(boolean isEnabled) {
checkServiceBinder();
if (sService != null) {
@@ -367,11 +368,10 @@ public class BackupManager {
/**
* Report whether the backup mechanism is currently enabled.
*
- * <p>Callers must hold the android.permission.BACKUP permission to use this method.
- *
* @hide
*/
@SystemApi
+ @RequiresPermission(android.Manifest.permission.BACKUP)
public boolean isBackupEnabled() {
checkServiceBinder();
if (sService != null) {
@@ -390,11 +390,10 @@ public class BackupManager {
* the archival restore dataset (if any). When disabled, no such attempt will
* be made.
*
- * <p>Callers must hold the android.permission.BACKUP permission to use this method.
- *
* @hide
*/
@SystemApi
+ @RequiresPermission(android.Manifest.permission.BACKUP)
public void setAutoRestore(boolean isEnabled) {
checkServiceBinder();
if (sService != null) {
@@ -407,14 +406,14 @@ public class BackupManager {
}
/**
- * Identify the currently selected transport. Callers must hold the
- * android.permission.BACKUP permission to use this method.
+ * Identify the currently selected transport.
* @return The name of the currently active backup transport. In case of
* failure or if no transport is currently active, this method returns {@code null}.
*
* @hide
*/
@SystemApi
+ @RequiresPermission(android.Manifest.permission.BACKUP)
public String getCurrentTransport() {
checkServiceBinder();
if (sService != null) {
@@ -428,12 +427,12 @@ public class BackupManager {
}
/**
- * Request a list of all available backup transports' names. Callers must
- * hold the android.permission.BACKUP permission to use this method.
+ * Request a list of all available backup transports' names.
*
* @hide
*/
@SystemApi
+ @RequiresPermission(android.Manifest.permission.BACKUP)
public String[] listAllTransports() {
checkServiceBinder();
if (sService != null) {
@@ -449,8 +448,6 @@ public class BackupManager {
/**
* Specify the current backup transport.
*
- * <p> Callers must hold the android.permission.BACKUP permission to use this method.
- *
* @param transport The name of the transport to select. This should be one
* of the names returned by {@link #listAllTransports()}. This is the String returned by
* {@link BackupTransport#name()} for the particular transport.
@@ -462,6 +459,7 @@ public class BackupManager {
*/
@Deprecated
@SystemApi
+ @RequiresPermission(android.Manifest.permission.BACKUP)
public String selectBackupTransport(String transport) {
checkServiceBinder();
if (sService != null) {
@@ -479,8 +477,6 @@ public class BackupManager {
* This method is async because BackupManager might need to bind to the specified transport
* which is in a separate process.
*
- * <p>Callers must hold the android.permission.BACKUP permission to use this method.
- *
* @param transport ComponentName of the service hosting the transport. This is different from
* the transport's name that is returned by {@link BackupTransport#name()}.
* @param listener A listener object to get a callback on the transport being selected.
@@ -488,6 +484,7 @@ public class BackupManager {
* @hide
*/
@SystemApi
+ @RequiresPermission(android.Manifest.permission.BACKUP)
public void selectBackupTransport(ComponentName transport,
SelectBackupTransportCallback listener) {
checkServiceBinder();
@@ -510,11 +507,10 @@ public class BackupManager {
* transport will still be asked to confirm via the usual requestBackupTime()
* method.
*
- * <p>Callers must hold the android.permission.BACKUP permission to use this method.
- *
* @hide
*/
@SystemApi
+ @RequiresPermission(android.Manifest.permission.BACKUP)
public void backupNow() {
checkServiceBinder();
if (sService != null) {
@@ -530,8 +526,6 @@ public class BackupManager {
* Ask the framework which dataset, if any, the given package's data would be
* restored from if we were to install it right now.
*
- * <p>Callers must hold the android.permission.BACKUP permission to use this method.
- *
* @param packageName The name of the package whose most-suitable dataset we
* wish to look up
* @return The dataset token from which a restore should be attempted, or zero if
@@ -540,6 +534,7 @@ public class BackupManager {
* @hide
*/
@SystemApi
+ @RequiresPermission(android.Manifest.permission.BACKUP)
public long getAvailableRestoreToken(String packageName) {
checkServiceBinder();
if (sService != null) {
@@ -555,14 +550,13 @@ public class BackupManager {
/**
* Ask the framework whether this app is eligible for backup.
*
- * <p>Callers must hold the android.permission.BACKUP permission to use this method.
- *
* @param packageName The name of the package.
* @return Whether this app is eligible for backup.
*
* @hide
*/
@SystemApi
+ @RequiresPermission(android.Manifest.permission.BACKUP)
public boolean isAppEligibleForBackup(String packageName) {
checkServiceBinder();
if (sService != null) {
@@ -592,6 +586,7 @@ public class BackupManager {
* @hide
*/
@SystemApi
+ @RequiresPermission(android.Manifest.permission.BACKUP)
public int requestBackup(String[] packages, BackupObserver observer) {
return requestBackup(packages, observer, null, 0);
}
@@ -615,6 +610,7 @@ public class BackupManager {
* @hide
*/
@SystemApi
+ @RequiresPermission(android.Manifest.permission.BACKUP)
public int requestBackup(String[] packages, BackupObserver observer,
BackupManagerMonitor monitor, int flags) {
checkServiceBinder();
@@ -638,11 +634,10 @@ public class BackupManager {
* Cancel all running backups. After this call returns, no currently running backups will
* interact with the selected transport.
*
- * <p>Callers must hold the android.permission.BACKUP permission to use this method.
- *
* @hide
*/
@SystemApi
+ @RequiresPermission(android.Manifest.permission.BACKUP)
public void cancelBackups() {
checkServiceBinder();
if (sService != null) {
diff --git a/core/java/android/app/job/JobScheduler.java b/core/java/android/app/job/JobScheduler.java
index 1768828eb76c..3868439f092f 100644
--- a/core/java/android/app/job/JobScheduler.java
+++ b/core/java/android/app/job/JobScheduler.java
@@ -19,8 +19,11 @@ package android.app.job;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
import android.annotation.SystemApi;
+import android.annotation.SystemService;
import android.content.ClipData;
+import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.os.PersistableBundle;
@@ -53,6 +56,7 @@ import java.util.List;
* {@link android.content.Context#getSystemService
* Context.getSystemService(Context.JOB_SCHEDULER_SERVICE)}.
*/
+@SystemService(Context.JOB_SCHEDULER_SERVICE)
public abstract class JobScheduler {
/** @hide */
@IntDef(prefix = { "RESULT_" }, value = {
@@ -132,6 +136,7 @@ public abstract class JobScheduler {
* @hide
*/
@SystemApi
+ @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS)
public abstract @Result int scheduleAsPackage(@NonNull JobInfo job, @NonNull String packageName,
int userId, String tag);
diff --git a/core/java/android/app/trust/TrustManager.java b/core/java/android/app/trust/TrustManager.java
index 3c681f26f5c6..852cb8e09ddb 100644
--- a/core/java/android/app/trust/TrustManager.java
+++ b/core/java/android/app/trust/TrustManager.java
@@ -18,6 +18,8 @@ package android.app.trust;
import android.Manifest;
import android.annotation.RequiresPermission;
+import android.annotation.SystemService;
+import android.content.Context;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
@@ -29,6 +31,7 @@ import android.util.ArrayMap;
* See {@link com.android.server.trust.TrustManagerService}
* @hide
*/
+@SystemService(Context.TRUST_SERVICE)
public class TrustManager {
private static final int MSG_TRUST_CHANGED = 1;
diff --git a/core/java/android/app/usage/NetworkStatsManager.java b/core/java/android/app/usage/NetworkStatsManager.java
index 6cd4e92383b2..ef262e046021 100644
--- a/core/java/android/app/usage/NetworkStatsManager.java
+++ b/core/java/android/app/usage/NetworkStatsManager.java
@@ -19,6 +19,7 @@ package android.app.usage;
import static com.android.internal.util.Preconditions.checkNotNull;
import android.annotation.Nullable;
+import android.annotation.SystemService;
import android.app.usage.NetworkStats.Bucket;
import android.content.Context;
import android.net.ConnectivityManager;
@@ -82,6 +83,7 @@ import android.util.Log;
* the above permission, even to access an app's own data usage, and carrier-privileged apps were
* not included.
*/
+@SystemService(Context.NETWORK_STATS_SERVICE)
public class NetworkStatsManager {
private static final String TAG = "NetworkStatsManager";
private static final boolean DBG = false;
diff --git a/core/java/android/app/usage/StorageStatsManager.java b/core/java/android/app/usage/StorageStatsManager.java
index 0b2b1900c4e0..7c680794d140 100644
--- a/core/java/android/app/usage/StorageStatsManager.java
+++ b/core/java/android/app/usage/StorageStatsManager.java
@@ -20,6 +20,7 @@ import static android.os.storage.StorageManager.convert;
import android.annotation.BytesLong;
import android.annotation.NonNull;
+import android.annotation.SystemService;
import android.annotation.TestApi;
import android.annotation.WorkerThread;
import android.content.Context;
@@ -50,6 +51,7 @@ import java.util.UUID;
* application.
* </p>
*/
+@SystemService(Context.STORAGE_STATS_SERVICE)
public class StorageStatsManager {
private final Context mContext;
private final IStorageStatsManager mService;
diff --git a/core/java/android/app/usage/UsageStatsManager.java b/core/java/android/app/usage/UsageStatsManager.java
index 75a4a535186e..1f939f996c68 100644
--- a/core/java/android/app/usage/UsageStatsManager.java
+++ b/core/java/android/app/usage/UsageStatsManager.java
@@ -16,7 +16,9 @@
package android.app.usage;
+import android.annotation.RequiresPermission;
import android.annotation.SystemApi;
+import android.annotation.SystemService;
import android.content.Context;
import android.content.pm.ParceledListSlice;
import android.os.RemoteException;
@@ -51,6 +53,7 @@ import java.util.Map;
* the permission implies intention to use the API and the user of the device can grant permission
* through the Settings application.
*/
+@SystemService(Context.USAGE_STATS_SERVICE)
public final class UsageStatsManager {
/**
@@ -252,7 +255,6 @@ public final class UsageStatsManager {
* Temporarily whitelist the specified app for a short duration. This is to allow an app
* receiving a high priority message to be able to access the network and acquire wakelocks
* even if the device is in power-save mode or the app is currently considered inactive.
- * The caller must hold the CHANGE_DEVICE_IDLE_TEMP_WHITELIST permission.
* @param packageName The package name of the app to whitelist.
* @param duration Duration to whitelist the app for, in milliseconds. It is recommended that
* this be limited to 10s of seconds. Requested duration will be clamped to a few minutes.
@@ -261,6 +263,7 @@ public final class UsageStatsManager {
* @see #isAppInactive(String)
*/
@SystemApi
+ @RequiresPermission(android.Manifest.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST)
public void whitelistAppTemporarily(String packageName, long duration, UserHandle user) {
try {
mService.whitelistAppTemporarily(packageName, duration, user.getIdentifier());
diff --git a/core/java/android/appwidget/AppWidgetManager.java b/core/java/android/appwidget/AppWidgetManager.java
index 6327f34ebd5e..969b19ee48ac 100644
--- a/core/java/android/appwidget/AppWidgetManager.java
+++ b/core/java/android/appwidget/AppWidgetManager.java
@@ -20,6 +20,7 @@ import android.annotation.BroadcastBehavior;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SdkConstant;
+import android.annotation.SystemService;
import android.annotation.SdkConstant.SdkConstantType;
import android.app.PendingIntent;
import android.content.ComponentName;
@@ -51,6 +52,7 @@ import java.util.List;
* <a href="{@docRoot}guide/topics/appwidgets/index.html">App Widgets</a> developer guide.</p>
* </div>
*/
+@SystemService(Context.APPWIDGET_SERVICE)
public class AppWidgetManager {
/**
diff --git a/core/java/android/bluetooth/BluetoothManager.java b/core/java/android/bluetooth/BluetoothManager.java
index c7191ba2638b..e2fa38a9309f 100644
--- a/core/java/android/bluetooth/BluetoothManager.java
+++ b/core/java/android/bluetooth/BluetoothManager.java
@@ -18,6 +18,7 @@ package android.bluetooth;
import android.Manifest;
import android.annotation.RequiresPermission;
+import android.annotation.SystemService;
import android.content.Context;
import android.os.RemoteException;
import android.util.Log;
@@ -48,6 +49,7 @@ import java.util.List;
* @see Context#getSystemService
* @see BluetoothAdapter#getDefaultAdapter()
*/
+@SystemService(Context.BLUETOOTH_SERVICE)
public final class BluetoothManager {
private static final String TAG = "BluetoothManager";
private static final boolean DBG = true;
diff --git a/core/java/android/companion/CompanionDeviceManager.java b/core/java/android/companion/CompanionDeviceManager.java
index 4e70e3fe8ce5..dabe608c038f 100644
--- a/core/java/android/companion/CompanionDeviceManager.java
+++ b/core/java/android/companion/CompanionDeviceManager.java
@@ -21,6 +21,7 @@ import static com.android.internal.util.Preconditions.checkNotNull;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.SystemService;
import android.app.Activity;
import android.app.Application;
import android.app.PendingIntent;
@@ -47,6 +48,7 @@ import java.util.List;
*
* @see AssociationRequest
*/
+@SystemService(Context.COMPANION_DEVICE_SERVICE)
public final class CompanionDeviceManager {
private static final boolean DEBUG = false;
diff --git a/core/java/android/content/ClipboardManager.java b/core/java/android/content/ClipboardManager.java
index f1c2f342eb3e..718e465bf0de 100644
--- a/core/java/android/content/ClipboardManager.java
+++ b/core/java/android/content/ClipboardManager.java
@@ -16,6 +16,7 @@
package android.content;
+import android.annotation.SystemService;
import android.os.Handler;
import android.os.Message;
import android.os.RemoteException;
@@ -29,10 +30,6 @@ import java.util.ArrayList;
* the global clipboard.
*
* <p>
- * You do not instantiate this class directly; instead, retrieve it through
- * {@link android.content.Context#getSystemService}.
- *
- * <p>
* The ClipboardManager API itself is very simple: it consists of methods
* to atomically get and set the current primary clipboard data. That data
* is expressed as a {@link ClipData} object, which defines the protocol
@@ -44,9 +41,8 @@ import java.util.ArrayList;
* <a href="{@docRoot}guide/topics/clipboard/copy-paste.html">Copy and Paste</a>
* developer guide.</p>
* </div>
- *
- * @see android.content.Context#getSystemService
*/
+@SystemService(Context.CLIPBOARD_SERVICE)
public class ClipboardManager extends android.text.ClipboardManager {
private final Context mContext;
private final IClipboard mService;
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 9ad33ee0379c..2f795385b2e5 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -1632,13 +1632,13 @@ public abstract class Context {
/**
* Version of {@link #startActivity(Intent)} that allows you to specify the
* user the activity will be started for. This is not available to applications
- * that are not pre-installed on the system image. Using it requires holding
- * the INTERACT_ACROSS_USERS_FULL permission.
+ * that are not pre-installed on the system image.
* @param intent The description of the activity to start.
* @param user The UserHandle of the user to start this activity for.
* @throws ActivityNotFoundException &nbsp;
* @hide
*/
+ @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL)
public void startActivityAsUser(@RequiresPermission Intent intent, UserHandle user) {
throw new RuntimeException("Not implemented. Must override in a subclass.");
}
@@ -1674,8 +1674,7 @@ public abstract class Context {
/**
* Version of {@link #startActivity(Intent, Bundle)} that allows you to specify the
* user the activity will be started for. This is not available to applications
- * that are not pre-installed on the system image. Using it requires holding
- * the INTERACT_ACROSS_USERS_FULL permission.
+ * that are not pre-installed on the system image.
* @param intent The description of the activity to start.
* @param options Additional options for how the Activity should be started.
* May be null if there are no options. See {@link android.app.ActivityOptions}
@@ -1685,6 +1684,7 @@ public abstract class Context {
* @throws ActivityNotFoundException &nbsp;
* @hide
*/
+ @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL)
public void startActivityAsUser(@RequiresPermission Intent intent, @Nullable Bundle options,
UserHandle userId) {
throw new RuntimeException("Not implemented. Must override in a subclass.");
@@ -1783,6 +1783,7 @@ public abstract class Context {
* @see #startActivities(Intent[])
* @see PackageManager#resolveActivity
*/
+ @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL)
public void startActivitiesAsUser(Intent[] intents, Bundle options, UserHandle userHandle) {
throw new RuntimeException("Not implemented. Must override in a subclass.");
}
@@ -2083,20 +2084,19 @@ public abstract class Context {
/**
* Version of {@link #sendBroadcast(Intent)} that allows you to specify the
* user the broadcast will be sent to. This is not available to applications
- * that are not pre-installed on the system image. Using it requires holding
- * the INTERACT_ACROSS_USERS permission.
+ * that are not pre-installed on the system image.
* @param intent The intent to broadcast
* @param user UserHandle to send the intent to.
* @see #sendBroadcast(Intent)
*/
+ @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS)
public abstract void sendBroadcastAsUser(@RequiresPermission Intent intent,
UserHandle user);
/**
* Version of {@link #sendBroadcast(Intent, String)} that allows you to specify the
* user the broadcast will be sent to. This is not available to applications
- * that are not pre-installed on the system image. Using it requires holding
- * the INTERACT_ACROSS_USERS permission.
+ * that are not pre-installed on the system image.
*
* @param intent The Intent to broadcast; all receivers matching this
* Intent will receive the broadcast.
@@ -2107,14 +2107,14 @@ public abstract class Context {
*
* @see #sendBroadcast(Intent, String)
*/
+ @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS)
public abstract void sendBroadcastAsUser(@RequiresPermission Intent intent,
UserHandle user, @Nullable String receiverPermission);
/**
* Version of {@link #sendBroadcast(Intent, String, Bundle)} that allows you to specify the
* user the broadcast will be sent to. This is not available to applications
- * that are not pre-installed on the system image. Using it requires holding
- * the INTERACT_ACROSS_USERS permission.
+ * that are not pre-installed on the system image.
*
* @param intent The Intent to broadcast; all receivers matching this
* Intent will receive the broadcast.
@@ -2129,14 +2129,14 @@ public abstract class Context {
* @hide
*/
@SystemApi
+ @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS)
public abstract void sendBroadcastAsUser(@RequiresPermission Intent intent,
UserHandle user, @Nullable String receiverPermission, @Nullable Bundle options);
/**
* Version of {@link #sendBroadcast(Intent, String)} that allows you to specify the
* user the broadcast will be sent to. This is not available to applications
- * that are not pre-installed on the system image. Using it requires holding
- * the INTERACT_ACROSS_USERS permission.
+ * that are not pre-installed on the system image.
*
* @param intent The Intent to broadcast; all receivers matching this
* Intent will receive the broadcast.
@@ -2150,6 +2150,7 @@ public abstract class Context {
*
* @hide
*/
+ @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS)
public abstract void sendBroadcastAsUser(@RequiresPermission Intent intent,
UserHandle user, @Nullable String receiverPermission, int appOp);
@@ -2158,8 +2159,7 @@ public abstract class Context {
* {@link #sendOrderedBroadcast(Intent, String, BroadcastReceiver, Handler, int, String, Bundle)}
* that allows you to specify the
* user the broadcast will be sent to. This is not available to applications
- * that are not pre-installed on the system image. Using it requires holding
- * the INTERACT_ACROSS_USERS permission.
+ * that are not pre-installed on the system image.
*
* <p>See {@link BroadcastReceiver} for more information on Intent broadcasts.
*
@@ -2183,6 +2183,7 @@ public abstract class Context {
*
* @see #sendOrderedBroadcast(Intent, String, BroadcastReceiver, Handler, int, String, Bundle)
*/
+ @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS)
public abstract void sendOrderedBroadcastAsUser(@RequiresPermission Intent intent,
UserHandle user, @Nullable String receiverPermission, BroadcastReceiver resultReceiver,
@Nullable Handler scheduler, int initialCode, @Nullable String initialData,
@@ -2194,6 +2195,7 @@ public abstract class Context {
* BroadcastReceiver, Handler, int, String, Bundle)
* @hide
*/
+ @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS)
public abstract void sendOrderedBroadcastAsUser(Intent intent, UserHandle user,
@Nullable String receiverPermission, int appOp, BroadcastReceiver resultReceiver,
@Nullable Handler scheduler, int initialCode, @Nullable String initialData,
@@ -2205,6 +2207,7 @@ public abstract class Context {
* BroadcastReceiver, Handler, int, String, Bundle)
* @hide
*/
+ @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS)
public abstract void sendOrderedBroadcastAsUser(Intent intent, UserHandle user,
@Nullable String receiverPermission, int appOp, @Nullable Bundle options,
BroadcastReceiver resultReceiver, @Nullable Handler scheduler, int initialCode,
@@ -2309,8 +2312,7 @@ public abstract class Context {
/**
* <p>Version of {@link #sendStickyBroadcast(Intent)} that allows you to specify the
* user the broadcast will be sent to. This is not available to applications
- * that are not pre-installed on the system image. Using it requires holding
- * the INTERACT_ACROSS_USERS permission.
+ * that are not pre-installed on the system image.
*
* @deprecated Sticky broadcasts should not be used. They provide no security (anyone
* can access them), no protection (anyone can modify them), and many other problems.
@@ -2326,6 +2328,10 @@ public abstract class Context {
* @see #sendBroadcast(Intent)
*/
@Deprecated
+ @RequiresPermission(allOf = {
+ android.Manifest.permission.INTERACT_ACROSS_USERS,
+ android.Manifest.permission.BROADCAST_STICKY
+ })
public abstract void sendStickyBroadcastAsUser(@RequiresPermission Intent intent,
UserHandle user);
@@ -2334,6 +2340,10 @@ public abstract class Context {
* This is just here for sending CONNECTIVITY_ACTION.
*/
@Deprecated
+ @RequiresPermission(allOf = {
+ android.Manifest.permission.INTERACT_ACROSS_USERS,
+ android.Manifest.permission.BROADCAST_STICKY
+ })
public abstract void sendStickyBroadcastAsUser(@RequiresPermission Intent intent,
UserHandle user, Bundle options);
@@ -2342,8 +2352,7 @@ public abstract class Context {
* {@link #sendStickyOrderedBroadcast(Intent, BroadcastReceiver, Handler, int, String, Bundle)}
* that allows you to specify the
* user the broadcast will be sent to. This is not available to applications
- * that are not pre-installed on the system image. Using it requires holding
- * the INTERACT_ACROSS_USERS permission.
+ * that are not pre-installed on the system image.
*
* <p>See {@link BroadcastReceiver} for more information on Intent broadcasts.
*
@@ -2371,6 +2380,10 @@ public abstract class Context {
* @see #sendStickyOrderedBroadcast(Intent, BroadcastReceiver, Handler, int, String, Bundle)
*/
@Deprecated
+ @RequiresPermission(allOf = {
+ android.Manifest.permission.INTERACT_ACROSS_USERS,
+ android.Manifest.permission.BROADCAST_STICKY
+ })
public abstract void sendStickyOrderedBroadcastAsUser(@RequiresPermission Intent intent,
UserHandle user, BroadcastReceiver resultReceiver,
@Nullable Handler scheduler, int initialCode, @Nullable String initialData,
@@ -2379,8 +2392,7 @@ public abstract class Context {
/**
* <p>Version of {@link #removeStickyBroadcast(Intent)} that allows you to specify the
* user the broadcast will be sent to. This is not available to applications
- * that are not pre-installed on the system image. Using it requires holding
- * the INTERACT_ACROSS_USERS permission.
+ * that are not pre-installed on the system image.
*
* <p>You must hold the {@link android.Manifest.permission#BROADCAST_STICKY}
* permission in order to use this API. If you do not hold that
@@ -2398,6 +2410,10 @@ public abstract class Context {
* @see #sendStickyBroadcastAsUser
*/
@Deprecated
+ @RequiresPermission(allOf = {
+ android.Manifest.permission.INTERACT_ACROSS_USERS,
+ android.Manifest.permission.BROADCAST_STICKY
+ })
public abstract void removeStickyBroadcastAsUser(@RequiresPermission Intent intent,
UserHandle user);
@@ -2564,9 +2580,7 @@ public abstract class Context {
* @hide
* Same as {@link #registerReceiver(BroadcastReceiver, IntentFilter, String, Handler)
* but for a specific user. This receiver will receiver broadcasts that
- * are sent to the requested user. It
- * requires holding the {@link android.Manifest.permission#INTERACT_ACROSS_USERS_FULL}
- * permission.
+ * are sent to the requested user.
*
* @param receiver The BroadcastReceiver to handle the broadcast.
* @param user UserHandle to send the intent to.
@@ -2585,6 +2599,7 @@ public abstract class Context {
* @see #unregisterReceiver
*/
@Nullable
+ @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL)
public abstract Intent registerReceiverAsUser(BroadcastReceiver receiver,
UserHandle user, IntentFilter filter, @Nullable String broadcastPermission,
@Nullable Handler scheduler);
@@ -2693,6 +2708,7 @@ public abstract class Context {
* @hide like {@link #startForegroundService(Intent)} but for a specific user.
*/
@Nullable
+ @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS)
public abstract ComponentName startForegroundServiceAsUser(Intent service, UserHandle user);
/**
@@ -2730,11 +2746,13 @@ public abstract class Context {
* @hide like {@link #startService(Intent)} but for a specific user.
*/
@Nullable
+ @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS)
public abstract ComponentName startServiceAsUser(Intent service, UserHandle user);
/**
* @hide like {@link #stopService(Intent)} but for a specific user.
*/
+ @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS)
public abstract boolean stopServiceAsUser(Intent service, UserHandle user);
/**
@@ -2794,6 +2812,7 @@ public abstract class Context {
*/
@SystemApi
@SuppressWarnings("unused")
+ @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS)
public boolean bindServiceAsUser(@RequiresPermission Intent service, ServiceConnection conn,
int flags, UserHandle user) {
throw new RuntimeException("Not implemented. Must override in a subclass.");
@@ -2805,6 +2824,7 @@ public abstract class Context {
*
* @hide
*/
+ @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS)
public boolean bindServiceAsUser(Intent service, ServiceConnection conn, int flags,
Handler handler, UserHandle user) {
throw new RuntimeException("Not implemented. Must override in a subclass.");
diff --git a/core/java/android/content/RestrictionsManager.java b/core/java/android/content/RestrictionsManager.java
index 88aae6655428..b463ec6277e7 100644
--- a/core/java/android/content/RestrictionsManager.java
+++ b/core/java/android/content/RestrictionsManager.java
@@ -16,6 +16,7 @@
package android.content;
+import android.annotation.SystemService;
import android.app.Activity;
import android.app.admin.DevicePolicyManager;
import android.content.pm.ApplicationInfo;
@@ -120,6 +121,7 @@ import java.util.List;
* @see DevicePolicyManager#setRestrictionsProvider(ComponentName, ComponentName)
* @see DevicePolicyManager#setApplicationRestrictions(ComponentName, String, Bundle)
*/
+@SystemService(Context.RESTRICTIONS_SERVICE)
public class RestrictionsManager {
private static final String TAG = "RestrictionsManager";
diff --git a/core/java/android/content/pm/LauncherApps.java b/core/java/android/content/pm/LauncherApps.java
index 8ead0ec612f8..ed41e79e2c6c 100644
--- a/core/java/android/content/pm/LauncherApps.java
+++ b/core/java/android/content/pm/LauncherApps.java
@@ -20,6 +20,7 @@ import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SdkConstant;
+import android.annotation.SystemService;
import android.annotation.SdkConstant.SdkConstantType;
import android.annotation.TestApi;
import android.app.PendingIntent;
@@ -79,6 +80,7 @@ import java.util.List;
* Note as of Android O, apps on a managed profile are no longer allowed to access apps on the
* main profile. Apps can only access profiles returned by {@link #getProfiles()}.
*/
+@SystemService(Context.LAUNCHER_APPS_SERVICE)
public class LauncherApps {
static final String TAG = "LauncherApps";
diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java
index 4e112331a1ed..7f3f35ffd4f3 100644
--- a/core/java/android/content/pm/PackageInstaller.java
+++ b/core/java/android/content/pm/PackageInstaller.java
@@ -473,6 +473,7 @@ public class PackageInstaller {
/** {@hide} */
@SystemApi
+ @RequiresPermission(android.Manifest.permission.INSTALL_PACKAGES)
public void setPermissionsResult(int sessionId, boolean accepted) {
try {
mInstaller.setPermissionsResult(sessionId, accepted);
@@ -1156,6 +1157,7 @@ public class PackageInstaller {
/** {@hide} */
@SystemApi
+ @RequiresPermission(android.Manifest.permission.ALLOCATE_AGGRESSIVE)
public void setAllocateAggressive(boolean allocateAggressive) {
if (allocateAggressive) {
installFlags |= PackageManager.INSTALL_ALLOCATE_AGGRESSIVE;
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index c98c59fe9408..6bc7d42a14b2 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -3243,8 +3243,7 @@ public abstract class PackageManager {
/**
* Return a List of all packages that are installed on the device, for a
- * specific user. Requesting a list of installed packages for another user
- * will require the permission INTERACT_ACROSS_USERS_FULL.
+ * specific user.
*
* @param flags Additional option flags to modify the data returned.
* @param userId The user for whom the installed packages are to be listed
@@ -3259,6 +3258,7 @@ public abstract class PackageManager {
* @hide
*/
@SystemApi
+ @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL)
public abstract List<PackageInfo> getInstalledPackagesAsUser(@PackageInfoFlags int flags,
@UserIdInt int userId);
@@ -3400,6 +3400,7 @@ public abstract class PackageManager {
* @hide
*/
@SystemApi
+ @RequiresPermission(android.Manifest.permission.GRANT_RUNTIME_PERMISSIONS)
public abstract void grantRuntimePermission(@NonNull String packageName,
@NonNull String permissionName, @NonNull UserHandle user);
@@ -3425,6 +3426,7 @@ public abstract class PackageManager {
* @hide
*/
@SystemApi
+ @RequiresPermission(android.Manifest.permission.REVOKE_RUNTIME_PERMISSIONS)
public abstract void revokeRuntimePermission(@NonNull String packageName,
@NonNull String permissionName, @NonNull UserHandle user);
@@ -3439,6 +3441,10 @@ public abstract class PackageManager {
* @hide
*/
@SystemApi
+ @RequiresPermission(anyOf = {
+ android.Manifest.permission.GRANT_RUNTIME_PERMISSIONS,
+ android.Manifest.permission.REVOKE_RUNTIME_PERMISSIONS
+ })
public abstract @PermissionFlags int getPermissionFlags(String permissionName,
String packageName, @NonNull UserHandle user);
@@ -3455,6 +3461,10 @@ public abstract class PackageManager {
* @hide
*/
@SystemApi
+ @RequiresPermission(anyOf = {
+ android.Manifest.permission.GRANT_RUNTIME_PERMISSIONS,
+ android.Manifest.permission.REVOKE_RUNTIME_PERMISSIONS
+ })
public abstract void updatePermissionFlags(String permissionName,
String packageName, @PermissionFlags int flagMask, @PermissionFlags int flagValues,
@NonNull UserHandle user);
@@ -4754,6 +4764,7 @@ public abstract class PackageManager {
* @hide
*/
@SystemApi
+ @RequiresPermission(android.Manifest.permission.INTENT_FILTER_VERIFICATION_AGENT)
public abstract void verifyIntentFilter(int verificationId, int verificationCode,
List<String> failedDomains);
@@ -4801,6 +4812,7 @@ public abstract class PackageManager {
* @hide
*/
@SystemApi
+ @RequiresPermission(android.Manifest.permission.SET_PREFERRED_APPLICATIONS)
public abstract boolean updateIntentVerificationStatusAsUser(String packageName, int status,
@UserIdInt int userId);
@@ -4861,6 +4873,7 @@ public abstract class PackageManager {
* @hide
*/
@SystemApi
+ @RequiresPermission(android.Manifest.permission.SET_PREFERRED_APPLICATIONS)
public abstract boolean setDefaultBrowserPackageNameAsUser(String packageName,
@UserIdInt int userId);
@@ -5324,6 +5337,7 @@ public abstract class PackageManager {
* @hide
*/
@SystemApi
+ @RequiresPermission(Manifest.permission.OBSERVE_GRANT_REVOKE_PERMISSIONS)
public abstract void removeOnPermissionsChangeListener(OnPermissionsChangedListener listener);
/**
diff --git a/core/java/android/content/pm/ShortcutManager.java b/core/java/android/content/pm/ShortcutManager.java
index f779aeb879e2..c0b82b4dfee3 100644
--- a/core/java/android/content/pm/ShortcutManager.java
+++ b/core/java/android/content/pm/ShortcutManager.java
@@ -17,6 +17,7 @@ package android.content.pm;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.SystemService;
import android.annotation.TestApi;
import android.annotation.UserIdInt;
import android.app.Activity;
@@ -24,6 +25,7 @@ import android.app.usage.UsageStatsManager;
import android.content.Context;
import android.content.Intent;
import android.content.IntentSender;
+import android.graphics.drawable.AdaptiveIconDrawable;
import android.os.Build.VERSION_CODES;
import android.os.RemoteException;
import android.os.ServiceManager;
@@ -335,6 +337,14 @@ import java.util.List;
* {@link #isRequestPinShortcutSupported()}. Based on this return value, you might decide to hide
* the option in your app that allows users to pin a shortcut.
*
+ * <p class="note"><strong>Note:</strong> See also the support library APIs
+ * {@link android.support.v4.content.pm.ShortcutManagerCompat#isRequestPinShortcutSupported(
+ * Context)} and
+ * {@link android.support.v4.content.pm.ShortcutManagerCompat#requestPinShortcut(
+ * Context, ShortcutInfoCompat, IntentSender)}, which works on Android versions lower than
+ * {@link VERSION_CODES#O} by falling back to the deprecated private intent
+ * {@code com.android.launcher.action.INSTALL_SHORTCUT}.
+ *
* <h4>Custom Activity for Pinning Shortcuts</h4>
*
* <p>You can also create a specialized activity that helps users create shortcuts, complete with
@@ -569,6 +579,7 @@ import java.util.List;
* All shortcut information is stored in credential encrypted storage, so no shortcuts can be
* accessed when the user is locked.
*/
+@SystemService(Context.SHORTCUT_SERVICE)
public class ShortcutManager {
private static final String TAG = "ShortcutManager";
@@ -889,7 +900,7 @@ public class ShortcutManager {
*
* <p> Note that this method returns max width of icon's visible part. Hence, it does not take
* into account the inset introduced by {@link AdaptiveIconDrawable}. To calculate bitmap image
- * to function as {@link AcaptiveIconDrawable}, multiply
+ * to function as {@link AdaptiveIconDrawable}, multiply
* 1 + 2 * {@link AdaptiveIconDrawable#getExtraInsetFraction()} to the returned size.
*/
public int getIconMaxWidth() {
@@ -938,8 +949,15 @@ public class ShortcutManager {
* Return {@code TRUE} if the app is running on a device whose default launcher supports
* {@link #requestPinShortcut(ShortcutInfo, IntentSender)}.
*
- * <p><b>Note:</b> The return value may change in subsequent calls, if the user changes
- * the default launcher app.
+ * <p>The return value may change in subsequent calls if the user changes the default launcher
+ * app.
+ *
+ * <p><b>Note:</b> See also the support library counterpart
+ * {@link android.support.v4.content.pm.ShortcutManagerCompat#isRequestPinShortcutSupported(
+ * Context)}, which supports Android versions lower than {@link VERSION_CODES#O} using the
+ * legacy private intent {@code com.android.launcher.action.INSTALL_SHORTCUT}.
+ *
+ * @see #requestPinShortcut(ShortcutInfo, IntentSender)
*/
public boolean isRequestPinShortcutSupported() {
try {
@@ -963,6 +981,12 @@ public class ShortcutManager {
* package calls this API multiple times in a row. One possible strategy is to ignore any
* previous requests.
*
+ * <p><b>Note:</b> See also the support library counterpart
+ * {@link android.support.v4.content.pm.ShortcutManagerCompat#requestPinShortcut(
+ * Context, ShortcutInfoCompat, IntentSender)},
+ * which supports Android versions lower than {@link VERSION_CODES#O} using the
+ * legacy private intent {@code com.android.launcher.action.INSTALL_SHORTCUT}.
+ *
* @param shortcut Shortcut to pin. If an app wants to pin an existing (either static
* or dynamic) shortcut, then it only needs to have an ID. Although other fields don't have
* to be set, the target shortcut must be enabled.
diff --git a/core/java/android/content/res/Configuration.java b/core/java/android/content/res/Configuration.java
index 88c1627f955b..417a95fbc417 100644
--- a/core/java/android/content/res/Configuration.java
+++ b/core/java/android/content/res/Configuration.java
@@ -16,10 +16,7 @@
package android.content.res;
-import android.graphics.Point;
import android.graphics.Rect;
-import android.util.DisplayMetrics;
-import android.view.Display;
import android.view.DisplayInfo;
import com.android.internal.util.XmlUtils;
@@ -45,6 +42,12 @@ import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.Locale;
+import static android.view.Surface.ROTATION_UNDEFINED;
+import static android.view.Surface.ROTATION_0;
+import static android.view.Surface.ROTATION_90;
+import static android.view.Surface.ROTATION_180;
+import static android.view.Surface.ROTATION_270;
+
/**
* This class describes all device configuration information that can
* impact the resources the application retrieves. This includes both
@@ -600,6 +603,13 @@ public final class Configuration implements Parcelable, Comparable<Configuration
*/
public int orientation;
+ /**
+ * The rotation used at the time orientation was determined.
+ * TODO(b/36812336): Move rotation out of {@link Configuration}.
+ * {@hide}
+ */
+ private int rotation;
+
/** Constant for {@link #uiMode}: bits that encode the mode type. */
public static final int UI_MODE_TYPE_MASK = 0x0f;
/** Constant for {@link #uiMode}: a {@link #UI_MODE_TYPE_MASK}
@@ -887,6 +897,7 @@ public final class Configuration implements Parcelable, Comparable<Configuration
navigation = o.navigation;
navigationHidden = o.navigationHidden;
orientation = o.orientation;
+ rotation = o.rotation;
screenLayout = o.screenLayout;
colorMode = o.colorMode;
uiMode = o.uiMode;
@@ -990,6 +1001,14 @@ public final class Configuration implements Parcelable, Comparable<Configuration
case ORIENTATION_PORTRAIT: sb.append(" port"); break;
default: sb.append(" orien="); sb.append(orientation); break;
}
+ switch (rotation) {
+ case ROTATION_UNDEFINED: sb.append(" ?rotation"); break;
+ case ROTATION_0: sb.append(" rot0"); break;
+ case ROTATION_90: sb.append(" rot90"); break;
+ case ROTATION_180: sb.append(" rot180"); break;
+ case ROTATION_270: sb.append(" rot270"); break;
+ default: sb.append(" rot="); sb.append(rotation); break;
+ }
switch ((uiMode&UI_MODE_TYPE_MASK)) {
case UI_MODE_TYPE_UNDEFINED: sb.append(" ?uimode"); break;
case UI_MODE_TYPE_NORMAL: /* normal is not interesting to print */ break;
@@ -1077,6 +1096,7 @@ public final class Configuration implements Parcelable, Comparable<Configuration
navigation = NAVIGATION_UNDEFINED;
navigationHidden = NAVIGATIONHIDDEN_UNDEFINED;
orientation = ORIENTATION_UNDEFINED;
+ rotation = ROTATION_UNDEFINED;
screenLayout = SCREENLAYOUT_UNDEFINED;
colorMode = COLOR_MODE_UNDEFINED;
uiMode = UI_MODE_TYPE_UNDEFINED;
@@ -1185,6 +1205,11 @@ public final class Configuration implements Parcelable, Comparable<Configuration
changed |= ActivityInfo.CONFIG_ORIENTATION;
orientation = delta.orientation;
}
+ if (delta.rotation != ROTATION_UNDEFINED
+ && rotation != delta.rotation) {
+ changed |= ActivityInfo.CONFIG_ORIENTATION;
+ rotation = delta.rotation;
+ }
if (((delta.screenLayout & SCREENLAYOUT_SIZE_MASK) != SCREENLAYOUT_SIZE_UNDEFINED)
&& (delta.screenLayout & SCREENLAYOUT_SIZE_MASK)
@@ -1379,6 +1404,10 @@ public final class Configuration implements Parcelable, Comparable<Configuration
&& orientation != delta.orientation) {
changed |= ActivityInfo.CONFIG_ORIENTATION;
}
+ if ((compareUndefined || delta.rotation != ROTATION_UNDEFINED)
+ && rotation != delta.rotation) {
+ changed |= ActivityInfo.CONFIG_ORIENTATION;
+ }
if ((compareUndefined || getScreenLayoutNoDirection(delta.screenLayout) !=
(SCREENLAYOUT_SIZE_UNDEFINED | SCREENLAYOUT_LONG_UNDEFINED))
&& getScreenLayoutNoDirection(screenLayout) !=
@@ -1515,6 +1544,7 @@ public final class Configuration implements Parcelable, Comparable<Configuration
dest.writeInt(navigation);
dest.writeInt(navigationHidden);
dest.writeInt(orientation);
+ dest.writeInt(rotation);
dest.writeInt(screenLayout);
dest.writeInt(colorMode);
dest.writeInt(uiMode);
@@ -1551,6 +1581,7 @@ public final class Configuration implements Parcelable, Comparable<Configuration
navigation = source.readInt();
navigationHidden = source.readInt();
orientation = source.readInt();
+ rotation = source.readInt();
screenLayout = source.readInt();
colorMode = source.readInt();
uiMode = source.readInt();
@@ -1635,6 +1666,8 @@ public final class Configuration implements Parcelable, Comparable<Configuration
if (n != 0) return n;
n = this.orientation - that.orientation;
if (n != 0) return n;
+ n = this.rotation - that.rotation;
+ if (n != 0) return n;
n = this.colorMode - that.colorMode;
if (n != 0) return n;
n = this.screenLayout - that.screenLayout;
@@ -1766,6 +1799,24 @@ public final class Configuration implements Parcelable, Comparable<Configuration
/**
* @hide
*
+ * Setter for orientation converts from {@link Surface} values to internal representation.
+ */
+ public void setRotation(int rotation) {
+ this.rotation = rotation;
+ }
+
+ /**
+ * @hide
+ *
+ * Getter for orientation. Converts from internal representation to {@link Surface} values.
+ */
+ public int getRotation() {
+ return rotation != ROTATION_UNDEFINED ? rotation : ROTATION_0;
+ }
+
+ /**
+ * @hide
+ *
* Clears the locale without changing layout direction.
*/
public void clearLocales() {
@@ -2000,6 +2051,23 @@ public final class Configuration implements Parcelable, Comparable<Configuration
break;
}
+ switch (config.rotation) {
+ case ROTATION_0:
+ parts.add("rot0");
+ break;
+ case ROTATION_90:
+ parts.add("rot90");
+ break;
+ case ROTATION_180:
+ parts.add("rot180");
+ break;
+ case ROTATION_270:
+ parts.add("rot270");
+ break;
+ default:
+ break;
+ }
+
switch (config.uiMode & Configuration.UI_MODE_TYPE_MASK) {
case Configuration.UI_MODE_TYPE_APPLIANCE:
parts.add("appliance");
@@ -2194,6 +2262,10 @@ public final class Configuration implements Parcelable, Comparable<Configuration
delta.orientation = change.orientation;
}
+ if (base.rotation != change.rotation) {
+ base.rotation = change.rotation;
+ }
+
if ((base.screenLayout & SCREENLAYOUT_SIZE_MASK) !=
(change.screenLayout & SCREENLAYOUT_SIZE_MASK)) {
delta.screenLayout |= change.screenLayout & SCREENLAYOUT_SIZE_MASK;
@@ -2265,6 +2337,7 @@ public final class Configuration implements Parcelable, Comparable<Configuration
private static final String XML_ATTR_NAVIGATION = "nav";
private static final String XML_ATTR_NAVIGATION_HIDDEN = "navHid";
private static final String XML_ATTR_ORIENTATION = "ori";
+ private static final String XML_ATTR_ROTATION = "rot";
private static final String XML_ATTR_SCREEN_LAYOUT = "scrLay";
private static final String XML_ATTR_COLOR_MODE = "clrMod";
private static final String XML_ATTR_UI_MODE = "ui";
@@ -2324,6 +2397,8 @@ public final class Configuration implements Parcelable, Comparable<Configuration
DENSITY_DPI_UNDEFINED);
configOut.appBounds =
Rect.unflattenFromString(XmlUtils.readStringAttribute(parser, XML_ATTR_APP_BOUNDS));
+ configOut.rotation = XmlUtils.readIntAttribute(parser, XML_ATTR_ROTATION,
+ ROTATION_UNDEFINED);
// For persistence, we don't care about assetsSeq, so do not read it out.
}
@@ -2400,6 +2475,10 @@ public final class Configuration implements Parcelable, Comparable<Configuration
config.appBounds.flattenToString());
}
+ if (config.rotation != ROTATION_UNDEFINED) {
+ XmlUtils.writeIntAttribute(xml, XML_ATTR_ROTATION, config.rotation);
+ }
+
// For persistence, we do not care about assetsSeq, so do not write it out.
}
}
diff --git a/core/java/android/hardware/ConsumerIrManager.java b/core/java/android/hardware/ConsumerIrManager.java
index b221e1604949..c7a33ffa1b0f 100644
--- a/core/java/android/hardware/ConsumerIrManager.java
+++ b/core/java/android/hardware/ConsumerIrManager.java
@@ -16,6 +16,7 @@
package android.hardware;
+import android.annotation.SystemService;
import android.content.Context;
import android.os.RemoteException;
import android.os.ServiceManager;
@@ -24,14 +25,8 @@ import android.util.Log;
/**
* Class that operates consumer infrared on the device.
- *
- * <p>
- * To obtain an instance of the system infrared transmitter, call
- * {@link android.content.Context#getSystemService(java.lang.String)
- * Context.getSystemService()} with
- * {@link android.content.Context#CONSUMER_IR_SERVICE} as the argument.
- * </p>
*/
+@SystemService(Context.CONSUMER_IR_SERVICE)
public final class ConsumerIrManager {
private static final String TAG = "ConsumerIr";
diff --git a/core/java/android/hardware/SensorManager.java b/core/java/android/hardware/SensorManager.java
index ed563914a46e..4bc62b1d04d3 100644
--- a/core/java/android/hardware/SensorManager.java
+++ b/core/java/android/hardware/SensorManager.java
@@ -17,6 +17,8 @@
package android.hardware;
import android.annotation.SystemApi;
+import android.annotation.SystemService;
+import android.content.Context;
import android.os.Build;
import android.os.Handler;
import android.os.MemoryFile;
@@ -30,10 +32,7 @@ import java.util.List;
/**
* <p>
* SensorManager lets you access the device's {@link android.hardware.Sensor
- * sensors}. Get an instance of this class by calling
- * {@link android.content.Context#getSystemService(java.lang.String)
- * Context.getSystemService()} with the argument
- * {@link android.content.Context#SENSOR_SERVICE}.
+ * sensors}.
* </p>
* <p>
* Always make sure to disable sensors you don't need, especially when your
@@ -79,6 +78,7 @@ import java.util.List;
* @see Sensor
*
*/
+@SystemService(Context.SENSOR_SERVICE)
public abstract class SensorManager {
/** @hide */
protected static final String TAG = "SensorManager";
diff --git a/core/java/android/hardware/SerialManager.java b/core/java/android/hardware/SerialManager.java
index 83f7649ff326..610f6a587e51 100644
--- a/core/java/android/hardware/SerialManager.java
+++ b/core/java/android/hardware/SerialManager.java
@@ -16,6 +16,7 @@
package android.hardware;
+import android.annotation.SystemService;
import android.content.Context;
import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
@@ -25,6 +26,7 @@ import java.io.IOException;
/**
* @hide
*/
+@SystemService(Context.SERIAL_SERVICE)
public class SerialManager {
private static final String TAG = "SerialManager";
diff --git a/core/java/android/hardware/camera2/CameraManager.java b/core/java/android/hardware/camera2/CameraManager.java
index f61032ef8250..1b150bfca63a 100644
--- a/core/java/android/hardware/camera2/CameraManager.java
+++ b/core/java/android/hardware/camera2/CameraManager.java
@@ -17,6 +17,7 @@
package android.hardware.camera2;
import android.annotation.RequiresPermission;
+import android.annotation.SystemService;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.Context;
@@ -44,15 +45,11 @@ import java.util.ArrayList;
* <p>A system service manager for detecting, characterizing, and connecting to
* {@link CameraDevice CameraDevices}.</p>
*
- * <p>You can get an instance of this class by calling
- * {@link android.content.Context#getSystemService(String) Context.getSystemService()}.</p>
- *
- * <pre>CameraManager manager = (CameraManager) getSystemService(Context.CAMERA_SERVICE);</pre>
- *
* <p>For more details about communicating with camera devices, read the Camera
* developer guide or the {@link android.hardware.camera2 camera2}
* package documentation.</p>
*/
+@SystemService(Context.CAMERA_SERVICE)
public final class CameraManager {
private static final String TAG = "CameraManager";
diff --git a/core/java/android/hardware/display/DisplayManager.java b/core/java/android/hardware/display/DisplayManager.java
index 266be9a1dd0f..6a02b6b2e6e7 100644
--- a/core/java/android/hardware/display/DisplayManager.java
+++ b/core/java/android/hardware/display/DisplayManager.java
@@ -18,6 +18,7 @@ package android.hardware.display;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.SystemService;
import android.content.Context;
import android.media.projection.MediaProjection;
import android.os.Handler;
@@ -29,13 +30,8 @@ import java.util.ArrayList;
/**
* Manages the properties of attached displays.
- * <p>
- * Get an instance of this class by calling
- * {@link android.content.Context#getSystemService(java.lang.String)
- * Context.getSystemService()} with the argument
- * {@link android.content.Context#DISPLAY_SERVICE}.
- * </p>
*/
+@SystemService(Context.DISPLAY_SERVICE)
public final class DisplayManager {
private static final String TAG = "DisplayManager";
private static final boolean DEBUG = false;
diff --git a/core/java/android/hardware/fingerprint/FingerprintManager.java b/core/java/android/hardware/fingerprint/FingerprintManager.java
index 324a08ca9e1b..b51a7919e3bf 100644
--- a/core/java/android/hardware/fingerprint/FingerprintManager.java
+++ b/core/java/android/hardware/fingerprint/FingerprintManager.java
@@ -19,6 +19,7 @@ package android.hardware.fingerprint;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
+import android.annotation.SystemService;
import android.app.ActivityManager;
import android.content.Context;
import android.os.Binder;
@@ -47,12 +48,8 @@ import static android.Manifest.permission.USE_FINGERPRINT;
/**
* A class that coordinates access to the fingerprint hardware.
- * <p>
- * Use {@link android.content.Context#getSystemService(java.lang.String)}
- * with argument {@link android.content.Context#FINGERPRINT_SERVICE} to get
- * an instance of this class.
*/
-
+@SystemService(Context.FINGERPRINT_SERVICE)
public class FingerprintManager {
private static final String TAG = "FingerprintManager";
private static final boolean DEBUG = true;
diff --git a/core/java/android/hardware/hdmi/HdmiControlManager.java b/core/java/android/hardware/hdmi/HdmiControlManager.java
index 27e2a5072287..a772cbe43196 100644
--- a/core/java/android/hardware/hdmi/HdmiControlManager.java
+++ b/core/java/android/hardware/hdmi/HdmiControlManager.java
@@ -17,9 +17,13 @@
package android.hardware.hdmi;
import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
+import android.annotation.SuppressLint;
+import android.content.Context;
import android.annotation.SystemApi;
+import android.annotation.SystemService;
import android.os.RemoteException;
import android.util.ArrayMap;
import android.util.Log;
@@ -37,6 +41,7 @@ import android.util.Log;
* @hide
*/
@SystemApi
+@SystemService(Context.HDMI_CONTROL_SERVICE)
public final class HdmiControlManager {
private static final String TAG = "HdmiControlManager";
@@ -295,6 +300,7 @@ public final class HdmiControlManager {
* See {@link HdmiDeviceInfo#DEVICE_TV}
*/
@Nullable
+ @SuppressLint("Doclava125")
public HdmiClient getClient(int type) {
if (mService == null) {
return null;
@@ -319,6 +325,7 @@ public final class HdmiControlManager {
* @return {@link HdmiPlaybackClient} instance. {@code null} on failure.
*/
@Nullable
+ @SuppressLint("Doclava125")
public HdmiPlaybackClient getPlaybackClient() {
return (HdmiPlaybackClient) getClient(HdmiDeviceInfo.DEVICE_PLAYBACK);
}
@@ -333,6 +340,7 @@ public final class HdmiControlManager {
* @return {@link HdmiTvClient} instance. {@code null} on failure.
*/
@Nullable
+ @SuppressLint("Doclava125")
public HdmiTvClient getTvClient() {
return (HdmiTvClient) getClient(HdmiDeviceInfo.DEVICE_TV);
}
@@ -343,6 +351,7 @@ public final class HdmiControlManager {
*
* @param isStandbyModeOn target status of the system's standby mode
*/
+ @RequiresPermission(android.Manifest.permission.HDMI_CEC)
public void setStandbyMode(boolean isStandbyModeOn) {
try {
mService.setStandbyMode(isStandbyModeOn);
@@ -403,6 +412,7 @@ public final class HdmiControlManager {
* @param listener {@link HotplugEventListener} instance
* @see HdmiControlManager#removeHotplugEventListener(HotplugEventListener)
*/
+ @RequiresPermission(android.Manifest.permission.HDMI_CEC)
public void addHotplugEventListener(HotplugEventListener listener) {
if (mService == null) {
Log.e(TAG, "HdmiControlService is not available");
@@ -426,6 +436,7 @@ public final class HdmiControlManager {
*
* @param listener {@link HotplugEventListener} instance to be removed
*/
+ @RequiresPermission(android.Manifest.permission.HDMI_CEC)
public void removeHotplugEventListener(HotplugEventListener listener) {
if (mService == null) {
Log.e(TAG, "HdmiControlService is not available");
diff --git a/core/java/android/hardware/input/InputManager.java b/core/java/android/hardware/input/InputManager.java
index 22b3638bdbb1..4898c1a0802f 100644
--- a/core/java/android/hardware/input/InputManager.java
+++ b/core/java/android/hardware/input/InputManager.java
@@ -19,6 +19,7 @@ package android.hardware.input;
import android.annotation.IntDef;
import android.annotation.Nullable;
import android.annotation.SdkConstant;
+import android.annotation.SystemService;
import android.annotation.SdkConstant.SdkConstantType;
import android.content.Context;
import android.media.AudioAttributes;
@@ -53,13 +54,8 @@ import java.util.List;
/**
* Provides information about input devices and available key layouts.
- * <p>
- * Get an instance of this class by calling
- * {@link android.content.Context#getSystemService(java.lang.String)
- * Context.getSystemService()} with the argument
- * {@link android.content.Context#INPUT_SERVICE}.
- * </p>
*/
+@SystemService(Context.INPUT_SERVICE)
public final class InputManager {
private static final String TAG = "InputManager";
private static final boolean DEBUG = false;
diff --git a/core/java/android/hardware/location/ContextHubManager.java b/core/java/android/hardware/location/ContextHubManager.java
index 7c4df473a9da..60500463d82e 100644
--- a/core/java/android/hardware/location/ContextHubManager.java
+++ b/core/java/android/hardware/location/ContextHubManager.java
@@ -15,7 +15,10 @@
*/
package android.hardware.location;
+import android.annotation.RequiresPermission;
+import android.annotation.SuppressLint;
import android.annotation.SystemApi;
+import android.annotation.SystemService;
import android.content.Context;
import android.os.Handler;
import android.os.Looper;
@@ -33,6 +36,7 @@ import android.util.Log;
* @hide
*/
@SystemApi
+@SystemService(Context.CONTEXTHUB_SERVICE)
public final class ContextHubManager {
private static final String TAG = "ContextHubManager";
@@ -91,6 +95,7 @@ public final class ContextHubManager {
* Get a handle to all the context hubs in the system
* @return array of context hub handles
*/
+ @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE)
public int[] getContextHubHandles() {
try {
return mService.getContextHubHandles();
@@ -107,6 +112,7 @@ public final class ContextHubManager {
*
* @see ContextHubInfo
*/
+ @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE)
public ContextHubInfo getContextHubInfo(int hubHandle) {
try {
return mService.getContextHubInfo(hubHandle);
@@ -134,6 +140,7 @@ public final class ContextHubManager {
*
* @see NanoApp
*/
+ @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE)
public int loadNanoApp(int hubHandle, NanoApp app) {
try {
return mService.loadNanoApp(hubHandle, app);
@@ -157,6 +164,7 @@ public final class ContextHubManager {
* @return 0 if the command for unloading was sent to the context hub;
* -1 otherwise
*/
+ @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE)
public int unloadNanoApp(int nanoAppHandle) {
try {
return mService.unloadNanoApp(nanoAppHandle);
@@ -191,6 +199,7 @@ public final class ContextHubManager {
*
* @see NanoAppInstanceInfo
*/
+ @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE)
public NanoAppInstanceInfo getNanoAppInstanceInfo(int nanoAppHandle) {
try {
return mService.getNanoAppInstanceInfo(nanoAppHandle);
@@ -209,6 +218,7 @@ public final class ContextHubManager {
*
* @return int[] Array of handles to any found nano apps
*/
+ @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE)
public int[] findNanoAppOnHub(int hubHandle, NanoAppFilter filter) {
try {
return mService.findNanoAppOnHub(hubHandle, filter);
@@ -236,6 +246,7 @@ public final class ContextHubManager {
*
* @return int 0 on success, -1 otherwise
*/
+ @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE)
public int sendMessage(int hubHandle, int nanoAppHandle, ContextHubMessage message) {
try {
return mService.sendMessage(hubHandle, nanoAppHandle, message);
@@ -253,6 +264,7 @@ public final class ContextHubManager {
*
* @return int 0 on success, -1 otherwise
*/
+ @SuppressLint("Doclava125")
public int registerCallback(Callback callback) {
return registerCallback(callback, null);
}
@@ -281,6 +293,7 @@ public final class ContextHubManager {
*
* @return int 0 on success, -1 otherwise
*/
+ @SuppressLint("Doclava125")
public int registerCallback(Callback callback, Handler handler) {
synchronized(this) {
if (mCallback != null) {
@@ -302,6 +315,7 @@ public final class ContextHubManager {
*
* @return int 0 on success, -1 otherwise
*/
+ @SuppressLint("Doclava125")
public int unregisterCallback(Callback callback) {
synchronized(this) {
if (callback != mCallback) {
diff --git a/core/java/android/hardware/radio/RadioManager.java b/core/java/android/hardware/radio/RadioManager.java
index e659a3ecdc41..20292f7e7e48 100644
--- a/core/java/android/hardware/radio/RadioManager.java
+++ b/core/java/android/hardware/radio/RadioManager.java
@@ -19,6 +19,7 @@ package android.hardware.radio;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemApi;
+import android.annotation.SystemService;
import android.content.Context;
import android.os.Handler;
import android.os.Parcel;
@@ -41,6 +42,7 @@ import java.util.Arrays;
* @hide
*/
@SystemApi
+@SystemService(Context.RADIO_SERVICE)
public class RadioManager {
private static final String TAG = "RadioManager";
diff --git a/core/java/android/hardware/usb/UsbManager.java b/core/java/android/hardware/usb/UsbManager.java
index a0fb82c64e4c..004530837206 100644
--- a/core/java/android/hardware/usb/UsbManager.java
+++ b/core/java/android/hardware/usb/UsbManager.java
@@ -19,6 +19,7 @@ package android.hardware.usb;
import android.annotation.Nullable;
import android.annotation.SdkConstant;
+import android.annotation.SystemService;
import android.annotation.SdkConstant.SdkConstantType;
import android.app.PendingIntent;
import android.content.ComponentName;
@@ -38,18 +39,13 @@ import java.util.HashMap;
* This class allows you to access the state of USB and communicate with USB devices.
* Currently only host mode is supported in the public API.
*
- * <p>You can obtain an instance of this class by calling
- * {@link android.content.Context#getSystemService(java.lang.String) Context.getSystemService()}.
- *
- * {@samplecode
- * UsbManager manager = (UsbManager) getSystemService(Context.USB_SERVICE);}
- *
* <div class="special reference">
* <h3>Developer Guides</h3>
* <p>For more information about communicating with USB hardware, read the
* <a href="{@docRoot}guide/topics/connectivity/usb/index.html">USB developer guide</a>.</p>
* </div>
*/
+@SystemService(Context.USB_SERVICE)
public class UsbManager {
private static final String TAG = "UsbManager";
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index d2636ebb913e..fcb99b167d1e 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -21,6 +21,7 @@ import android.annotation.RequiresPermission;
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
import android.annotation.SystemApi;
+import android.annotation.SystemService;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
@@ -64,9 +65,7 @@ import java.util.Map;
/**
* Class that answers queries about the state of network connectivity. It also
- * notifies applications when network connectivity changes. Get an instance
- * of this class by calling
- * {@link android.content.Context#getSystemService(String) Context.getSystemService(Context.CONNECTIVITY_SERVICE)}.
+ * notifies applications when network connectivity changes.
* <p>
* The primary responsibilities of this class are to:
* <ol>
@@ -80,6 +79,7 @@ import java.util.Map;
* traffic</li>
* </ol>
*/
+@SystemService(Context.CONNECTIVITY_SERVICE)
public class ConnectivityManager {
private static final String TAG = "ConnectivityManager";
@@ -2110,6 +2110,7 @@ public class ConnectivityManager {
* @hide
*/
@SystemApi
+ @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED)
public void startTethering(int type, boolean showProvisioningUi,
final OnStartTetheringCallback callback, Handler handler) {
Preconditions.checkNotNull(callback, "OnStartTetheringCallback cannot be null.");
@@ -2146,6 +2147,7 @@ public class ConnectivityManager {
* @hide
*/
@SystemApi
+ @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED)
public void stopTethering(int type) {
try {
String pkgName = mContext.getOpPackageName();
diff --git a/core/java/android/net/EthernetManager.java b/core/java/android/net/EthernetManager.java
index 664b7b408975..31a30968cbcd 100644
--- a/core/java/android/net/EthernetManager.java
+++ b/core/java/android/net/EthernetManager.java
@@ -16,6 +16,7 @@
package android.net;
+import android.annotation.SystemService;
import android.content.Context;
import android.net.IEthernetManager;
import android.net.IEthernetServiceListener;
@@ -31,6 +32,7 @@ import java.util.ArrayList;
*
* @hide
*/
+@SystemService(Context.ETHERNET_SERVICE)
public class EthernetManager {
private static final String TAG = "EthernetManager";
private static final int MSG_AVAILABILITY_CHANGED = 1000;
diff --git a/core/java/android/net/IpSecManager.java b/core/java/android/net/IpSecManager.java
index 0240cf15095e..2f791e151b08 100644
--- a/core/java/android/net/IpSecManager.java
+++ b/core/java/android/net/IpSecManager.java
@@ -18,6 +18,8 @@ package android.net;
import static com.android.internal.util.Preconditions.checkNotNull;
import android.annotation.NonNull;
+import android.annotation.SystemService;
+import android.content.Context;
import android.os.Binder;
import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
@@ -34,12 +36,9 @@ import java.net.Socket;
* This class contains methods for managing IPsec sessions, which will perform kernel-space
* encryption and decryption of socket or Network traffic.
*
- * <p>An IpSecManager may be obtained by calling {@link
- * android.content.Context#getSystemService(String) Context#getSystemService(String)} with {@link
- * android.content.Context#IPSEC_SERVICE Context#IPSEC_SERVICE}
- *
* @hide
*/
+@SystemService(Context.IPSEC_SERVICE)
public final class IpSecManager {
private static final String TAG = "IpSecManager";
diff --git a/core/java/android/net/NetworkCapabilities.java b/core/java/android/net/NetworkCapabilities.java
index bf7207ca5bbb..2dd7f757aea3 100644
--- a/core/java/android/net/NetworkCapabilities.java
+++ b/core/java/android/net/NetworkCapabilities.java
@@ -418,10 +418,16 @@ public final class NetworkCapabilities implements Parcelable {
*/
public static final int TRANSPORT_WIFI_AWARE = 5;
+ /**
+ * Indicates this network uses a LoWPAN transport.
+ * @hide
+ */
+ public static final int TRANSPORT_LOWPAN = 6;
+
/** @hide */
public static final int MIN_TRANSPORT = TRANSPORT_CELLULAR;
/** @hide */
- public static final int MAX_TRANSPORT = TRANSPORT_WIFI_AWARE;
+ public static final int MAX_TRANSPORT = TRANSPORT_LOWPAN;
private static final String[] TRANSPORT_NAMES = {
"CELLULAR",
@@ -429,7 +435,8 @@ public final class NetworkCapabilities implements Parcelable {
"BLUETOOTH",
"ETHERNET",
"VPN",
- "WIFI_AWARE"
+ "WIFI_AWARE",
+ "LOWPAN"
};
/**
diff --git a/core/java/android/net/NetworkPolicyManager.java b/core/java/android/net/NetworkPolicyManager.java
index 43fab037f254..4d94a55cd0c4 100644
--- a/core/java/android/net/NetworkPolicyManager.java
+++ b/core/java/android/net/NetworkPolicyManager.java
@@ -19,6 +19,7 @@ package android.net;
import static android.content.pm.PackageManager.GET_SIGNATURES;
import static android.net.NetworkPolicy.CYCLE_NONE;
+import android.annotation.SystemService;
import android.app.ActivityManager;
import android.content.Context;
import android.content.Intent;
@@ -40,6 +41,7 @@ import java.util.TimeZone;
*
* {@hide}
*/
+@SystemService(Context.NETWORK_POLICY_SERVICE)
public class NetworkPolicyManager {
/* POLICY_* are masks and can be ORed, although currently they are not.*/
diff --git a/core/java/android/net/NetworkScoreManager.java b/core/java/android/net/NetworkScoreManager.java
index 9f6e45ca6fb5..7e0c9ce33b82 100644
--- a/core/java/android/net/NetworkScoreManager.java
+++ b/core/java/android/net/NetworkScoreManager.java
@@ -19,9 +19,11 @@ package android.net;
import android.Manifest.permission;
import android.annotation.IntDef;
import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
import android.annotation.SystemApi;
+import android.annotation.SystemService;
import android.content.Context;
import android.os.RemoteException;
import android.os.ServiceManager;
@@ -34,12 +36,6 @@ import java.util.List;
/**
* Class that manages communication between network subsystems and a network scorer.
*
- * <p>You can get an instance of this class by calling
- * {@link android.content.Context#getSystemService(String)}:
- *
- * <pre>NetworkScoreManager manager =
- * (NetworkScoreManager) getSystemService(Context.NETWORK_SCORE_SERVICE)</pre>
- *
* <p>A network scorer is any application which:
* <ul>
* <li>Declares the {@link permission#SCORE_NETWORKS} permission.
@@ -51,6 +47,7 @@ import java.util.List;
* @hide
*/
@SystemApi
+@SystemService(Context.NETWORK_SCORE_SERVICE)
public class NetworkScoreManager {
/**
* Activity action: ask the user to change the active network scorer. This will show a dialog
@@ -243,6 +240,7 @@ public class NetworkScoreManager {
* @hide
*/
@Nullable
+ @RequiresPermission(android.Manifest.permission.REQUEST_NETWORK_SCORES)
public NetworkScorerAppData getActiveScorer() {
try {
return mService.getActiveScorer();
@@ -276,6 +274,7 @@ public class NetworkScoreManager {
* @return whether the update was successful.
* @throws SecurityException if the caller is not the active scorer.
*/
+ @RequiresPermission(android.Manifest.permission.SCORE_NETWORKS)
public boolean updateScores(ScoredNetwork[] networks) throws SecurityException {
try {
return mService.updateScores(networks);
@@ -296,6 +295,7 @@ public class NetworkScoreManager {
* @return whether the clear was successful.
* @throws SecurityException if the caller is not the active scorer or privileged.
*/
+ @RequiresPermission(android.Manifest.permission.REQUEST_NETWORK_SCORES)
public boolean clearScores() throws SecurityException {
try {
return mService.clearScores();
@@ -316,6 +316,7 @@ public class NetworkScoreManager {
* @hide
*/
@SystemApi
+ @RequiresPermission(android.Manifest.permission.SCORE_NETWORKS)
public boolean setActiveScorer(String packageName) throws SecurityException {
try {
return mService.setActiveScorer(packageName);
@@ -331,6 +332,7 @@ public class NetworkScoreManager {
*
* @throws SecurityException if the caller is neither the active scorer nor the system.
*/
+ @RequiresPermission(android.Manifest.permission.REQUEST_NETWORK_SCORES)
public void disableScoring() throws SecurityException {
try {
mService.disableScoring();
diff --git a/core/java/android/net/TrafficStats.java b/core/java/android/net/TrafficStats.java
index fc66395bcd00..f9346165df3b 100644
--- a/core/java/android/net/TrafficStats.java
+++ b/core/java/android/net/TrafficStats.java
@@ -16,6 +16,7 @@
package android.net;
+import android.annotation.RequiresPermission;
import android.annotation.SystemApi;
import android.app.DownloadManager;
import android.app.backup.BackupManager;
@@ -243,6 +244,7 @@ public class TrafficStats {
* @hide
*/
@SystemApi
+ @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS)
public static void setThreadStatsUid(int uid) {
NetworkManagementSocketTagger.setThreadSocketStatsUid(uid);
}
@@ -255,6 +257,7 @@ public class TrafficStats {
* @hide
*/
@SystemApi
+ @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS)
public static void clearThreadStatsUid() {
NetworkManagementSocketTagger.setThreadSocketStatsUid(-1);
}
diff --git a/core/java/android/net/VpnService.java b/core/java/android/net/VpnService.java
index c6daa15e3d62..2d9860cf0e40 100644
--- a/core/java/android/net/VpnService.java
+++ b/core/java/android/net/VpnService.java
@@ -19,6 +19,7 @@ package android.net;
import static android.system.OsConstants.AF_INET;
import static android.system.OsConstants.AF_INET6;
+import android.annotation.RequiresPermission;
import android.annotation.SystemApi;
import android.app.Activity;
import android.app.PendingIntent;
@@ -177,6 +178,7 @@ public class VpnService extends Service {
* @hide
*/
@SystemApi
+ @RequiresPermission(android.Manifest.permission.CONTROL_VPN)
public static void prepareAndAuthorize(Context context) {
IConnectivityManager cm = getService();
String packageName = context.getPackageName();
diff --git a/core/java/android/net/nsd/NsdManager.java b/core/java/android/net/nsd/NsdManager.java
index 22bda77195c0..ace37486647c 100644
--- a/core/java/android/net/nsd/NsdManager.java
+++ b/core/java/android/net/nsd/NsdManager.java
@@ -17,6 +17,7 @@
package android.net.nsd;
import android.annotation.SdkConstant;
+import android.annotation.SystemService;
import android.annotation.SdkConstant.SdkConstantType;
import android.content.Context;
import android.os.Handler;
@@ -114,11 +115,9 @@ import com.android.internal.util.Protocol;
* http://www.iana.org/form/ports-service. Existing services can be found at
* http://www.iana.org/assignments/service-names-port-numbers/service-names-port-numbers.xml
*
- * Get an instance of this class by calling {@link android.content.Context#getSystemService(String)
- * Context.getSystemService(Context.NSD_SERVICE)}.
- *
* {@see NsdServiceInfo}
*/
+@SystemService(Context.NSD_SERVICE)
public final class NsdManager {
private static final String TAG = NsdManager.class.getSimpleName();
private static final boolean DBG = false;
diff --git a/core/java/android/nfc/NfcAdapter.java b/core/java/android/nfc/NfcAdapter.java
index 783c25aa4d08..48869c71b685 100644
--- a/core/java/android/nfc/NfcAdapter.java
+++ b/core/java/android/nfc/NfcAdapter.java
@@ -18,6 +18,7 @@ package android.nfc;
import java.util.HashMap;
+import android.annotation.RequiresPermission;
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
import android.annotation.SystemApi;
@@ -725,6 +726,7 @@ public final class NfcAdapter {
* @hide
*/
@SystemApi
+ @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)
public boolean enable() {
try {
return sService.enable();
@@ -753,6 +755,7 @@ public final class NfcAdapter {
* @hide
*/
@SystemApi
+ @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)
public boolean disable() {
try {
return sService.disable(true);
@@ -767,6 +770,7 @@ public final class NfcAdapter {
* @hide
*/
@SystemApi
+ @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)
public boolean disable(boolean persist) {
try {
return sService.disable(persist);
@@ -1552,6 +1556,7 @@ public final class NfcAdapter {
* @hide
*/
@SystemApi
+ @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)
public boolean enableNdefPush() {
if (!sHasNfcFeature) {
throw new UnsupportedOperationException();
@@ -1570,6 +1575,7 @@ public final class NfcAdapter {
* @hide
*/
@SystemApi
+ @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)
public boolean disableNdefPush() {
synchronized (NfcAdapter.class) {
if (!sHasNfcFeature) {
@@ -1736,6 +1742,7 @@ public final class NfcAdapter {
* @hide
*/
@SystemApi
+ @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)
public boolean addNfcUnlockHandler(final NfcUnlockHandler unlockHandler,
String[] tagTechnologies) {
synchronized (NfcAdapter.class) {
@@ -1785,6 +1792,7 @@ public final class NfcAdapter {
* @hide
*/
@SystemApi
+ @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)
public boolean removeNfcUnlockHandler(NfcUnlockHandler unlockHandler) {
synchronized (NfcAdapter.class) {
if (!sHasNfcFeature) {
diff --git a/core/java/android/nfc/NfcManager.java b/core/java/android/nfc/NfcManager.java
index ea080140e3ac..50d674570c14 100644
--- a/core/java/android/nfc/NfcManager.java
+++ b/core/java/android/nfc/NfcManager.java
@@ -16,6 +16,7 @@
package android.nfc;
+import android.annotation.SystemService;
import android.content.Context;
/**
@@ -34,9 +35,9 @@ import android.content.Context;
* <a href="{@docRoot}guide/topics/nfc/index.html">Near Field Communication</a> developer guide.</p>
* </div>
*
- * @see Context#getSystemService
* @see NfcAdapter#getDefaultAdapter(android.content.Context)
*/
+@SystemService(Context.NFC_SERVICE)
public final class NfcManager {
private final NfcAdapter mAdapter;
diff --git a/core/java/android/os/BatteryManager.java b/core/java/android/os/BatteryManager.java
index 734d89eb72af..f715f507f6c9 100644
--- a/core/java/android/os/BatteryManager.java
+++ b/core/java/android/os/BatteryManager.java
@@ -16,6 +16,8 @@
package android.os;
+import android.annotation.SystemService;
+import android.content.Context;
import android.hardware.health.V1_0.Constants;
import com.android.internal.app.IBatteryStats;
@@ -24,6 +26,7 @@ import com.android.internal.app.IBatteryStats;
* in the {@link android.content.Intent#ACTION_BATTERY_CHANGED} Intent, and
* provides a method for querying battery and charging properties.
*/
+@SystemService(Context.BATTERY_SERVICE)
public class BatteryManager {
/**
* Extra for {@link android.content.Intent#ACTION_BATTERY_CHANGED}:
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index ecc4dec47af7..162dddb1f797 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -1219,6 +1219,7 @@ public abstract class BatteryStats implements Parcelable {
// Platform-level low power state stats
public String statPlatformIdleState;
+ public String statSubsystemPowerState;
public HistoryStepDetails() {
clear();
@@ -1250,6 +1251,7 @@ public abstract class BatteryStats implements Parcelable {
out.writeInt(statSoftIrqTime);
out.writeInt(statIdlTime);
out.writeString(statPlatformIdleState);
+ out.writeString(statSubsystemPowerState);
}
public void readFromParcel(Parcel in) {
@@ -1271,6 +1273,7 @@ public abstract class BatteryStats implements Parcelable {
statSoftIrqTime = in.readInt();
statIdlTime = in.readInt();
statPlatformIdleState = in.readString();
+ statSubsystemPowerState = in.readString();
}
}
@@ -5543,6 +5546,10 @@ public abstract class BatteryStats implements Parcelable {
pw.print(", PlatformIdleStat ");
pw.print(rec.stepDetails.statPlatformIdleState);
pw.println();
+
+ pw.print(", SubsystemPowerState ");
+ pw.print(rec.stepDetails.statSubsystemPowerState);
+ pw.println();
} else {
pw.print(BATTERY_STATS_CHECKIN_VERSION); pw.print(',');
pw.print(HISTORY_DATA); pw.print(",0,Dcpu=");
@@ -5580,6 +5587,11 @@ public abstract class BatteryStats implements Parcelable {
pw.print(rec.stepDetails.statPlatformIdleState);
}
pw.println();
+
+ if (rec.stepDetails.statSubsystemPowerState != null) {
+ pw.print(rec.stepDetails.statSubsystemPowerState);
+ }
+ pw.println();
}
}
oldState = rec.states;
diff --git a/core/java/android/os/DropBoxManager.java b/core/java/android/os/DropBoxManager.java
index db84b6fbf3c5..97f0e0cf31e9 100644
--- a/core/java/android/os/DropBoxManager.java
+++ b/core/java/android/os/DropBoxManager.java
@@ -17,6 +17,7 @@
package android.os;
import android.annotation.SdkConstant;
+import android.annotation.SystemService;
import android.annotation.SdkConstant.SdkConstantType;
import android.content.Context;
import android.util.Log;
@@ -36,13 +37,10 @@ import java.util.zip.GZIPInputStream;
* enqueued data exceeds the maximum size. You can think of this as a
* persistent, system-wide, blob-oriented "logcat".
*
- * <p>You can obtain an instance of this class by calling
- * {@link android.content.Context#getSystemService}
- * with {@link android.content.Context#DROPBOX_SERVICE}.
- *
* <p>DropBoxManager entries are not sent anywhere directly, but other system
* services and debugging tools may scan and upload entries for processing.
*/
+@SystemService(Context.DROPBOX_SERVICE)
public class DropBoxManager {
private static final String TAG = "DropBoxManager";
diff --git a/core/java/android/os/HardwarePropertiesManager.java b/core/java/android/os/HardwarePropertiesManager.java
index 67edefc16bd0..aad202e77710 100644
--- a/core/java/android/os/HardwarePropertiesManager.java
+++ b/core/java/android/os/HardwarePropertiesManager.java
@@ -17,6 +17,7 @@ package android.os;
import android.annotation.IntDef;
import android.annotation.NonNull;
+import android.annotation.SystemService;
import android.content.Context;
import android.hardware.thermal.V1_0.Constants;
import android.util.Log;
@@ -28,6 +29,7 @@ import java.lang.annotation.RetentionPolicy;
* The HardwarePropertiesManager class provides a mechanism of accessing hardware state of a
* device: CPU, GPU and battery temperatures, CPU usage per core, fan speed, etc.
*/
+@SystemService(Context.HARDWARE_PROPERTIES_SERVICE)
public class HardwarePropertiesManager {
private static final String TAG = HardwarePropertiesManager.class.getSimpleName();
diff --git a/core/java/android/os/IncidentManager.java b/core/java/android/os/IncidentManager.java
index 976d59472e69..bc8e2e470c55 100644
--- a/core/java/android/os/IncidentManager.java
+++ b/core/java/android/os/IncidentManager.java
@@ -16,7 +16,9 @@
package android.os;
+import android.annotation.RequiresPermission;
import android.annotation.SystemApi;
+import android.annotation.SystemService;
import android.annotation.TestApi;
import android.content.Context;
import android.os.IIncidentManager;
@@ -31,6 +33,7 @@ import android.util.Slog;
*/
@SystemApi
@TestApi
+@SystemService(Context.INCIDENT_SERVICE)
public class IncidentManager {
private static final String TAG = "incident";
@@ -46,6 +49,10 @@ public class IncidentManager {
/**
* Take an incident report and put it in dropbox.
*/
+ @RequiresPermission(allOf = {
+ android.Manifest.permission.DUMP,
+ android.Manifest.permission.PACKAGE_USAGE_STATS
+ })
public void reportIncident(IncidentReportArgs args) {
final IIncidentManager service = IIncidentManager.Stub.asInterface(
ServiceManager.getService("incident"));
@@ -76,6 +83,10 @@ public class IncidentManager {
* {@link android.util.proto.ProtoOutputStream#bytes bytes()} method to retrieve
* the encoded data for the header.
*/
+ @RequiresPermission(allOf = {
+ android.Manifest.permission.DUMP,
+ android.Manifest.permission.PACKAGE_USAGE_STATS
+ })
public void reportIncident(String settingName, byte[] headerProto) {
// Sections
String setting = Settings.System.getString(mContext.getContentResolver(), settingName);
diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java
index 7d1369fe1b69..a85ed9c0ce34 100644
--- a/core/java/android/os/PowerManager.java
+++ b/core/java/android/os/PowerManager.java
@@ -17,8 +17,10 @@
package android.os;
import android.annotation.IntDef;
+import android.annotation.RequiresPermission;
import android.annotation.SdkConstant;
import android.annotation.SystemApi;
+import android.annotation.SystemService;
import android.content.Context;
import android.util.Log;
import java.lang.annotation.Retention;
@@ -32,9 +34,6 @@ import java.lang.annotation.RetentionPolicy;
* Do not acquire {@link WakeLock}s unless you really need them, use the minimum levels
* possible, and be sure to release them as soon as possible.
* </p><p>
- * You can obtain an instance of this class by calling
- * {@link android.content.Context#getSystemService(java.lang.String) Context.getSystemService()}.
- * </p><p>
* The primary API you'll use is {@link #newWakeLock(int, String) newWakeLock()}.
* This will create a {@link PowerManager.WakeLock} object. You can then use methods
* on the wake lock object to control the power state of the device.
@@ -102,6 +101,7 @@ import java.lang.annotation.RetentionPolicy;
* permission in an {@code <uses-permission>} element of the application's manifest.
* </p>
*/
+@SystemService(Context.POWER_SERVICE)
public final class PowerManager {
private static final String TAG = "PowerManager";
@@ -689,6 +689,10 @@ public final class PowerManager {
* @hide Requires signature or system permission.
*/
@SystemApi
+ @RequiresPermission(anyOf = {
+ android.Manifest.permission.DEVICE_POWER,
+ android.Manifest.permission.USER_ACTIVITY
+ })
public void userActivity(long when, int event, int flags) {
try {
mService.userActivity(when, event, flags);
diff --git a/core/java/android/os/RecoverySystem.java b/core/java/android/os/RecoverySystem.java
index cf8f3eb96621..db9f28b77288 100644
--- a/core/java/android/os/RecoverySystem.java
+++ b/core/java/android/os/RecoverySystem.java
@@ -18,7 +18,10 @@ package android.os;
import static java.nio.charset.StandardCharsets.UTF_8;
+import android.annotation.RequiresPermission;
+import android.annotation.SuppressLint;
import android.annotation.SystemApi;
+import android.annotation.SystemService;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
@@ -67,6 +70,7 @@ import sun.security.pkcs.SignerInfo;
* recovery system (the separate partition that can be used to install
* system updates, wipe user data, etc.)
*/
+@SystemService(Context.RECOVERY_SERVICE)
public class RecoverySystem {
private static final String TAG = "RecoverySystem";
@@ -387,6 +391,7 @@ public class RecoverySystem {
* {@hide}
*/
@SystemApi
+ @SuppressLint("Doclava125")
public static boolean verifyPackageCompatibility(File compatibilityFile) throws IOException {
try (InputStream inputStream = new FileInputStream(compatibilityFile)) {
return verifyPackageCompatibility(inputStream);
@@ -409,6 +414,7 @@ public class RecoverySystem {
* @hide
*/
@SystemApi
+ @RequiresPermission(android.Manifest.permission.RECOVERY)
public static void processPackage(Context context,
File packageFile,
final ProgressListener listener,
@@ -469,6 +475,7 @@ public class RecoverySystem {
* @hide
*/
@SystemApi
+ @RequiresPermission(android.Manifest.permission.RECOVERY)
public static void processPackage(Context context,
File packageFile,
final ProgressListener listener)
@@ -490,6 +497,7 @@ public class RecoverySystem {
* @throws IOException if writing the recovery command file
* fails, or if the reboot itself fails.
*/
+ @RequiresPermission(android.Manifest.permission.RECOVERY)
public static void installPackage(Context context, File packageFile)
throws IOException {
installPackage(context, packageFile, false);
@@ -511,6 +519,7 @@ public class RecoverySystem {
* @hide
*/
@SystemApi
+ @RequiresPermission(android.Manifest.permission.RECOVERY)
public static void installPackage(Context context, File packageFile, boolean processed)
throws IOException {
synchronized (sRequestLock) {
@@ -602,6 +611,7 @@ public class RecoverySystem {
* @hide
*/
@SystemApi
+ @RequiresPermission(android.Manifest.permission.RECOVERY)
public static void scheduleUpdateOnBoot(Context context, File packageFile)
throws IOException {
String filename = packageFile.getCanonicalPath();
@@ -639,6 +649,7 @@ public class RecoverySystem {
* @hide
*/
@SystemApi
+ @RequiresPermission(android.Manifest.permission.RECOVERY)
public static void cancelScheduledUpdate(Context context)
throws IOException {
RecoverySystem rs = (RecoverySystem) context.getSystemService(Context.RECOVERY_SERVICE);
@@ -777,6 +788,10 @@ public class RecoverySystem {
* @hide
*/
@SystemApi
+ @RequiresPermission(allOf = {
+ android.Manifest.permission.RECOVERY,
+ android.Manifest.permission.REBOOT
+ })
public static void rebootWipeAb(Context context, File packageFile, String reason)
throws IOException {
String reasonArg = null;
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index 7e03e425a3db..3337def4c4e1 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -23,6 +23,7 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
import android.annotation.SystemApi;
+import android.annotation.SystemService;
import android.annotation.TestApi;
import android.annotation.UserIdInt;
import android.annotation.WorkerThread;
@@ -63,6 +64,7 @@ import java.util.List;
* <p>
* See {@link DevicePolicyManager#ACTION_PROVISION_MANAGED_PROFILE} for more on managed profiles.
*/
+@SystemService(Context.USER_SERVICE)
public class UserManager {
private static final String TAG = "UserManager";
@@ -1035,12 +1037,12 @@ public class UserManager {
/**
* Checks if the calling app is running in a managed profile.
- * Requires {@link android.Manifest.permission#MANAGE_USERS} permission.
*
* @return whether the caller is in a managed profile.
* @hide
*/
@SystemApi
+ @RequiresPermission(android.Manifest.permission.MANAGE_USERS)
public boolean isManagedProfile() {
// No need for synchronization. Once it becomes non-null, it'll be non-null forever.
// Worst case we might end up calling the AIDL method multiple times but that's fine.
@@ -1064,6 +1066,7 @@ public class UserManager {
* @hide
*/
@SystemApi
+ @RequiresPermission(android.Manifest.permission.MANAGE_USERS)
public boolean isManagedProfile(@UserIdInt int userId) {
if (userId == UserHandle.myUserId()) {
return isManagedProfile();
@@ -1249,7 +1252,6 @@ public class UserManager {
* @hide
*
* Returns who set a user restriction on a user.
- * Requires {@link android.Manifest.permission#MANAGE_USERS} permission.
* @param restrictionKey the string key representing the restriction
* @param userHandle the UserHandle of the user for whom to retrieve the restrictions.
* @return The source of user restriction. Any combination of {@link #RESTRICTION_NOT_SET},
@@ -1260,6 +1262,7 @@ public class UserManager {
@Deprecated
@SystemApi
@UserRestrictionSource
+ @RequiresPermission(android.Manifest.permission.MANAGE_USERS)
public int getUserRestrictionSource(String restrictionKey, UserHandle userHandle) {
try {
return mService.getUserRestrictionSource(restrictionKey, userHandle.getIdentifier());
@@ -1272,12 +1275,12 @@ public class UserManager {
* @hide
*
* Returns a list of users who set a user restriction on a given user.
- * Requires {@link android.Manifest.permission#MANAGE_USERS} permission.
* @param restrictionKey the string key representing the restriction
* @param userHandle the UserHandle of the user for whom to retrieve the restrictions.
* @return a list of user ids enforcing this restriction.
*/
@SystemApi
+ @RequiresPermission(android.Manifest.permission.MANAGE_USERS)
public List<EnforcingUser> getUserRestrictionSources(
String restrictionKey, UserHandle userHandle) {
try {
@@ -1619,9 +1622,10 @@ public class UserManager {
/**
* @hide
*
- * Returns the preferred account name for user creation. Requires MANAGE_USERS permission.
+ * Returns the preferred account name for user creation.
*/
@SystemApi
+ @RequiresPermission(android.Manifest.permission.MANAGE_USERS)
public String getSeedAccountName() {
try {
return mService.getSeedAccountName();
@@ -1633,9 +1637,10 @@ public class UserManager {
/**
* @hide
*
- * Returns the preferred account type for user creation. Requires MANAGE_USERS permission.
+ * Returns the preferred account type for user creation.
*/
@SystemApi
+ @RequiresPermission(android.Manifest.permission.MANAGE_USERS)
public String getSeedAccountType() {
try {
return mService.getSeedAccountType();
@@ -1647,11 +1652,11 @@ public class UserManager {
/**
* @hide
*
- * Returns the preferred account's options bundle for user creation. Requires MANAGE_USERS
- * permission.
+ * Returns the preferred account's options bundle for user creation.
* @return Any options set by the requestor that created the user.
*/
@SystemApi
+ @RequiresPermission(android.Manifest.permission.MANAGE_USERS)
public PersistableBundle getSeedAccountOptions() {
try {
return mService.getSeedAccountOptions();
@@ -1683,9 +1688,10 @@ public class UserManager {
/**
* @hide
- * Clears the seed information used to create this user. Requires MANAGE_USERS permission.
+ * Clears the seed information used to create this user.
*/
@SystemApi
+ @RequiresPermission(android.Manifest.permission.MANAGE_USERS)
public void clearSeedAccountData() {
try {
mService.clearSeedAccountData();
@@ -1768,13 +1774,13 @@ public class UserManager {
/**
* Returns serial numbers of all users on this device.
- * Requires {@link android.Manifest.permission#MANAGE_USERS} permission.
*
* @param excludeDying specify if the list should exclude users being removed.
* @return the list of serial numbers of users that exist on the device.
* @hide
*/
@SystemApi
+ @RequiresPermission(android.Manifest.permission.MANAGE_USERS)
public long[] getSerialNumbersOfUsers(boolean excludeDying) {
try {
List<UserInfo> users = mService.getUsers(excludeDying);
diff --git a/core/java/android/os/Vibrator.java b/core/java/android/os/Vibrator.java
index 2f0eecae2c96..8078fb87eb27 100644
--- a/core/java/android/os/Vibrator.java
+++ b/core/java/android/os/Vibrator.java
@@ -17,6 +17,7 @@
package android.os;
import android.annotation.RequiresPermission;
+import android.annotation.SystemService;
import android.app.ActivityThread;
import android.content.Context;
import android.media.AudioAttributes;
@@ -27,10 +28,8 @@ import android.util.Log;
* <p>
* If your process exits, any vibration you started will stop.
* </p>
- *
- * To obtain an instance of the system vibrator, call
- * {@link Context#getSystemService} with {@link Context#VIBRATOR_SERVICE} as the argument.
*/
+@SystemService(Context.VIBRATOR_SERVICE)
public abstract class Vibrator {
private static final String TAG = "Vibrator";
diff --git a/core/java/android/os/health/SystemHealthManager.java b/core/java/android/os/health/SystemHealthManager.java
index 7c0af2508a93..bba4cd1fb8e4 100644
--- a/core/java/android/os/health/SystemHealthManager.java
+++ b/core/java/android/os/health/SystemHealthManager.java
@@ -16,6 +16,7 @@
package android.os.health;
+import android.annotation.SystemService;
import android.content.Context;
import android.os.BatteryStats;
import android.os.Process;
@@ -40,6 +41,7 @@ import com.android.internal.app.IBatteryStats;
* JobScheduler}), and while that can affect charging rates, it is still preferable
* to actually draining the battery.
*/
+@SystemService(Context.SYSTEM_HEALTH_SERVICE)
public class SystemHealthManager {
private final IBatteryStats mBatteryStats;
diff --git a/core/java/android/os/storage/StorageManager.java b/core/java/android/os/storage/StorageManager.java
index d81ee4ef9843..a6cdb03c8b67 100644
--- a/core/java/android/os/storage/StorageManager.java
+++ b/core/java/android/os/storage/StorageManager.java
@@ -25,7 +25,9 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
import android.annotation.SdkConstant;
+import android.annotation.SuppressLint;
import android.annotation.SystemApi;
+import android.annotation.SystemService;
import android.annotation.WorkerThread;
import android.app.ActivityThread;
import android.content.ContentResolver;
@@ -98,11 +100,8 @@ import java.util.concurrent.atomic.AtomicInteger;
* guarantee the security of the OBB file itself: if any program modifies the
* OBB, there is no guarantee that a read from that OBB will produce the
* expected output.
- * <p>
- * Get an instance of this class by calling
- * {@link android.content.Context#getSystemService(java.lang.String)} with an
- * argument of {@link android.content.Context#STORAGE_SERVICE}.
*/
+@SystemService(Context.STORAGE_SERVICE)
public class StorageManager {
private static final String TAG = "StorageManager";
@@ -1701,8 +1700,9 @@ public class StorageManager {
/** @hide */
@SystemApi
- public long getAllocatableBytes(@NonNull UUID storageUuid, @AllocateFlags int flags)
- throws IOException {
+ @SuppressLint("Doclava125")
+ public long getAllocatableBytes(@NonNull UUID storageUuid,
+ @RequiresPermission @AllocateFlags int flags) throws IOException {
try {
return mStorageManager.getAllocatableBytes(convert(storageUuid), flags);
} catch (ParcelableException e) {
@@ -1715,8 +1715,9 @@ public class StorageManager {
/** @removed */
@Deprecated
- public long getAllocatableBytes(@NonNull File path, @AllocateFlags int flags)
- throws IOException {
+ @SuppressLint("Doclava125")
+ public long getAllocatableBytes(@NonNull File path,
+ @RequiresPermission @AllocateFlags int flags) throws IOException {
return getAllocatableBytes(getUuidForPath(path), flags);
}
@@ -1749,8 +1750,9 @@ public class StorageManager {
/** @hide */
@SystemApi
+ @SuppressLint("Doclava125")
public void allocateBytes(@NonNull UUID storageUuid, @BytesLong long bytes,
- @AllocateFlags int flags) throws IOException {
+ @RequiresPermission @AllocateFlags int flags) throws IOException {
try {
mStorageManager.allocateBytes(convert(storageUuid), bytes, flags);
} catch (ParcelableException e) {
@@ -1762,8 +1764,9 @@ public class StorageManager {
/** @removed */
@Deprecated
- public void allocateBytes(@NonNull File path, @BytesLong long bytes, @AllocateFlags int flags)
- throws IOException {
+ @SuppressLint("Doclava125")
+ public void allocateBytes(@NonNull File path, @BytesLong long bytes,
+ @RequiresPermission @AllocateFlags int flags) throws IOException {
allocateBytes(getUuidForPath(path), bytes, flags);
}
@@ -1798,8 +1801,9 @@ public class StorageManager {
/** @hide */
@SystemApi
- public void allocateBytes(FileDescriptor fd, @BytesLong long bytes, @AllocateFlags int flags)
- throws IOException {
+ @SuppressLint("Doclava125")
+ public void allocateBytes(FileDescriptor fd, @BytesLong long bytes,
+ @RequiresPermission @AllocateFlags int flags) throws IOException {
final File file = ParcelFileDescriptor.getFile(fd);
for (int i = 0; i < 3; i++) {
try {
diff --git a/core/java/android/print/PrintManager.java b/core/java/android/print/PrintManager.java
index 8ee05177f186..e8ff2e2cee98 100644
--- a/core/java/android/print/PrintManager.java
+++ b/core/java/android/print/PrintManager.java
@@ -19,6 +19,7 @@ package android.print;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemApi;
+import android.annotation.SystemService;
import android.app.Activity;
import android.app.Application.ActivityLifecycleCallbacks;
import android.content.ComponentName;
@@ -57,14 +58,6 @@ import java.util.Map;
/**
* System level service for accessing the printing capabilities of the platform.
- * <p>
- * To obtain a handle to the print manager do the following:
- * </p>
- *
- * <pre>
- * PrintManager printManager =
- * (PrintManager) context.getSystemService(Context.PRINT_SERVICE);
- * </pre>
*
* <h3>Print mechanics</h3>
* <p>
@@ -109,6 +102,7 @@ import java.util.Map;
* @see PrintJob
* @see PrintJobInfo
*/
+@SystemService(Context.PRINT_SERVICE)
public final class PrintManager {
private static final String LOG_TAG = "PrintManager";
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 172ba89bb3bf..e0abfb56c1b0 100755
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -6781,6 +6781,13 @@ public final class Settings {
public static final String CAMERA_LIFT_TRIGGER_ENABLED = "camera_lift_trigger_enabled";
/**
+ * The default enable state of the camera lift trigger.
+ *
+ * @hide
+ */
+ public static final int CAMERA_LIFT_TRIGGER_ENABLED_DEFAULT = 1;
+
+ /**
* Whether the assist gesture should be enabled.
*
* @hide
diff --git a/core/java/android/service/autofill/FillContext.java b/core/java/android/service/autofill/FillContext.java
index 251d346efb42..6956c8ac7135 100644
--- a/core/java/android/service/autofill/FillContext.java
+++ b/core/java/android/service/autofill/FillContext.java
@@ -114,7 +114,7 @@ public final class FillContext implements Parcelable {
*
* @hide
*/
- @NonNull public ViewNode[] findViewNodesByAutofillIds(@NonNull AutofillId[] ids) {
+ @NonNull public ViewNode[] findViewNodesByAutofillIds(@NonNull AutofillId... ids) {
final LinkedList<ViewNode> nodesToProcess = new LinkedList<>();
final ViewNode[] foundNodes = new AssistStructure.ViewNode[ids.length];
diff --git a/core/java/android/service/oemlock/OemLockManager.java b/core/java/android/service/oemlock/OemLockManager.java
index 644ca6c43506..3a56d9f1bf4f 100644
--- a/core/java/android/service/oemlock/OemLockManager.java
+++ b/core/java/android/service/oemlock/OemLockManager.java
@@ -17,7 +17,10 @@
package android.service.oemlock;
import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
import android.annotation.SystemApi;
+import android.annotation.SystemService;
+import android.content.Context;
import android.os.RemoteException;
/**
@@ -31,6 +34,7 @@ import android.os.RemoteException;
* @hide
*/
@SystemApi
+@SystemService(Context.OEM_LOCK_SERVICE)
public class OemLockManager {
private IOemLockService mService;
@@ -55,6 +59,7 @@ public class OemLockManager {
*
* @see #isOemUnlockAllowedByCarrier()
*/
+ @RequiresPermission(android.Manifest.permission.MANAGE_CARRIER_OEM_UNLOCK_STATE)
public void setOemUnlockAllowedByCarrier(boolean allowed, @Nullable byte[] signature) {
try {
mService.setOemUnlockAllowedByCarrier(allowed, signature);
@@ -69,6 +74,7 @@ public class OemLockManager {
*
* @see #setOemUnlockAllowedByCarrier(boolean, byte[])
*/
+ @RequiresPermission(android.Manifest.permission.MANAGE_CARRIER_OEM_UNLOCK_STATE)
public boolean isOemUnlockAllowedByCarrier() {
try {
return mService.isOemUnlockAllowedByCarrier();
@@ -87,6 +93,7 @@ public class OemLockManager {
*
* @see #isOemUnlockAllowedByUser()
*/
+ @RequiresPermission(android.Manifest.permission.MANAGE_USER_OEM_UNLOCK_STATE)
public void setOemUnlockAllowedByUser(boolean allowed) {
try {
mService.setOemUnlockAllowedByUser(allowed);
@@ -101,6 +108,7 @@ public class OemLockManager {
*
* @see #setOemUnlockAllowedByUser(boolean)
*/
+ @RequiresPermission(android.Manifest.permission.MANAGE_USER_OEM_UNLOCK_STATE)
public boolean isOemUnlockAllowedByUser() {
try {
return mService.isOemUnlockAllowedByUser();
diff --git a/core/java/android/service/persistentdata/PersistentDataBlockManager.java b/core/java/android/service/persistentdata/PersistentDataBlockManager.java
index 326796afb3ad..fa75ad33d250 100644
--- a/core/java/android/service/persistentdata/PersistentDataBlockManager.java
+++ b/core/java/android/service/persistentdata/PersistentDataBlockManager.java
@@ -16,10 +16,14 @@
package android.service.persistentdata;
-import android.annotation.SystemApi;
import android.annotation.IntDef;
+import android.annotation.RequiresPermission;
+import android.annotation.SuppressLint;
+import android.annotation.SystemApi;
+import android.annotation.SystemService;
+import android.content.Context;
import android.os.RemoteException;
-import android.util.Slog;
+import android.service.oemlock.OemLockManager;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -43,6 +47,7 @@ import java.lang.annotation.RetentionPolicy;
* @hide
*/
@SystemApi
+@SystemService(Context.PERSISTENT_DATA_BLOCK_SERVICE)
public class PersistentDataBlockManager {
private static final String TAG = PersistentDataBlockManager.class.getSimpleName();
private IPersistentDataBlockService sService;
@@ -85,6 +90,7 @@ public class PersistentDataBlockManager {
*
* @param data the data to write
*/
+ @SuppressLint("Doclava125")
public int write(byte[] data) {
try {
return sService.write(data);
@@ -96,6 +102,7 @@ public class PersistentDataBlockManager {
/**
* Returns the data block stored on the persistent partition.
*/
+ @SuppressLint("Doclava125")
public byte[] read() {
try {
return sService.read();
@@ -109,6 +116,7 @@ public class PersistentDataBlockManager {
*
* Return -1 on error.
*/
+ @RequiresPermission(android.Manifest.permission.ACCESS_PDB_STATE)
public int getDataBlockSize() {
try {
return sService.getDataBlockSize();
@@ -136,6 +144,7 @@ public class PersistentDataBlockManager {
* It will also prevent any further {@link #write} operation until reboot,
* in order to prevent a potential race condition. See b/30352311.
*/
+ @RequiresPermission(android.Manifest.permission.OEM_UNLOCK_STATE)
public void wipe() {
try {
sService.wipe();
@@ -149,6 +158,7 @@ public class PersistentDataBlockManager {
*
* @deprecated use {@link OemLockManager#setOemUnlockAllowedByUser(boolean)} instead.
*/
+ @RequiresPermission(android.Manifest.permission.OEM_UNLOCK_STATE)
public void setOemUnlockEnabled(boolean enabled) {
try {
sService.setOemUnlockEnabled(enabled);
@@ -162,6 +172,10 @@ public class PersistentDataBlockManager {
*
* @deprecated use {@link OemLockManager#isOemUnlockAllowedByUser()} instead.
*/
+ @RequiresPermission(anyOf = {
+ android.Manifest.permission.READ_OEM_UNLOCK_STATE,
+ android.Manifest.permission.OEM_UNLOCK_STATE
+ })
public boolean getOemUnlockEnabled() {
try {
return sService.getOemUnlockEnabled();
@@ -177,6 +191,10 @@ public class PersistentDataBlockManager {
* {@link #FLASH_LOCK_UNLOCKED} if device bootloader is unlocked, or {@link #FLASH_LOCK_UNKNOWN}
* if this information cannot be ascertained on this device.
*/
+ @RequiresPermission(anyOf = {
+ android.Manifest.permission.READ_OEM_UNLOCK_STATE,
+ android.Manifest.permission.OEM_UNLOCK_STATE
+ })
@FlashLockState
public int getFlashLockState() {
try {
diff --git a/core/java/android/view/HapticFeedbackConstants.java b/core/java/android/view/HapticFeedbackConstants.java
index 2f87d2e815cb..31cece49c79d 100644
--- a/core/java/android/view/HapticFeedbackConstants.java
+++ b/core/java/android/view/HapticFeedbackConstants.java
@@ -29,12 +29,12 @@ public class HapticFeedbackConstants {
* in an action being performed.
*/
public static final int LONG_PRESS = 0;
-
+
/**
* The user has pressed on a virtual on-screen key.
*/
public static final int VIRTUAL_KEY = 1;
-
+
/**
* The user has pressed a soft keyboard key.
*/
@@ -57,24 +57,29 @@ public class HapticFeedbackConstants {
public static final int CONTEXT_CLICK = 6;
/**
+ * The user has released a virtual or software keyboard key.
+ */
+ public static final int VIRTUAL_KEY_RELEASE = 7;
+
+ /**
* This is a private constant. Feel free to renumber as desired.
* @hide
*/
public static final int SAFE_MODE_DISABLED = 10000;
-
+
/**
* This is a private constant. Feel free to renumber as desired.
* @hide
*/
public static final int SAFE_MODE_ENABLED = 10001;
-
+
/**
* Flag for {@link View#performHapticFeedback(int, int)
* View.performHapticFeedback(int, int)}: Ignore the setting in the
* view for whether to perform haptic feedback, do it always.
*/
public static final int FLAG_IGNORE_VIEW_SETTING = 0x0001;
-
+
/**
* Flag for {@link View#performHapticFeedback(int, int)
* View.performHapticFeedback(int, int)}: Ignore the global setting
diff --git a/core/java/android/view/IWindowSession.aidl b/core/java/android/view/IWindowSession.aidl
index 51d65144f260..286e79055448 100644
--- a/core/java/android/view/IWindowSession.aidl
+++ b/core/java/android/view/IWindowSession.aidl
@@ -96,7 +96,7 @@ interface IWindowSession {
int flags, out Rect outFrame, out Rect outOverscanInsets,
out Rect outContentInsets, out Rect outVisibleInsets, out Rect outStableInsets,
out Rect outOutsets, out Rect outBackdropFrame,
- out MergedConfiguration outMergedConfiguration, out Surface outSurface);
+ inout MergedConfiguration mergedConfiguration, out Surface outSurface);
/*
* Notify the window manager that an application is relaunching and
diff --git a/core/java/android/view/LayoutInflater.java b/core/java/android/view/LayoutInflater.java
index ad46d07d61c9..47b8d921da2e 100644
--- a/core/java/android/view/LayoutInflater.java
+++ b/core/java/android/view/LayoutInflater.java
@@ -18,6 +18,7 @@ package android.view;
import android.annotation.LayoutRes;
import android.annotation.Nullable;
+import android.annotation.SystemService;
import android.content.Context;
import android.content.res.Resources;
import android.content.res.TypedArray;
@@ -47,10 +48,7 @@ import java.util.HashMap;
* {@link android.app.Activity#getLayoutInflater()} or
* {@link Context#getSystemService} to retrieve a standard LayoutInflater instance
* that is already hooked up to the current context and correctly configured
- * for the device you are running on. For example:
- *
- * <pre>LayoutInflater inflater = (LayoutInflater)context.getSystemService
- * (Context.LAYOUT_INFLATER_SERVICE);</pre>
+ * for the device you are running on.
*
* <p>
* To create a new LayoutInflater with an additional {@link Factory} for your
@@ -64,9 +62,8 @@ import java.util.HashMap;
* to use LayoutInflater with an XmlPullParser over a plain XML file at runtime;
* it only works with an XmlPullParser returned from a compiled resource
* (R.<em>something</em> file.)
- *
- * @see Context#getSystemService
*/
+@SystemService(Context.LAYOUT_INFLATER_SERVICE)
public abstract class LayoutInflater {
private static final String TAG = LayoutInflater.class.getSimpleName();
diff --git a/core/java/android/view/Surface.java b/core/java/android/view/Surface.java
index 8bb3fa988a45..0ad591be2cf8 100644
--- a/core/java/android/view/Surface.java
+++ b/core/java/android/view/Surface.java
@@ -129,11 +129,17 @@ public class Surface implements Parcelable {
public static final int SCALING_MODE_NO_SCALE_CROP = 3;
/** @hide */
- @IntDef({ROTATION_0, ROTATION_90, ROTATION_180, ROTATION_270})
+ @IntDef({ROTATION_UNDEFINED, ROTATION_0, ROTATION_90, ROTATION_180, ROTATION_270})
@Retention(RetentionPolicy.SOURCE)
public @interface Rotation {}
/**
+ * Rotation constant: undefined
+ * @hide
+ */
+ public static final int ROTATION_UNDEFINED = -1;
+
+ /**
* Rotation constant: 0 degree rotation (natural orientation)
*/
public static final int ROTATION_0 = 0;
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index b57ac66e10cc..ef78559e2b53 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -31,6 +31,7 @@ import android.graphics.Rect;
import android.graphics.Region;
import android.os.Build;
import android.os.Handler;
+import android.os.IBinder;
import android.os.Looper;
import android.os.SystemClock;
import android.util.AttributeSet;
@@ -452,6 +453,14 @@ public class SurfaceView extends View implements ViewRootImpl.WindowStoppedCallb
}
}
+ private void updateOpaqueFlag() {
+ if (!PixelFormat.formatHasAlpha(mRequestedFormat)) {
+ mSurfaceFlags |= SurfaceControl.OPAQUE;
+ } else {
+ mSurfaceFlags &= ~SurfaceControl.OPAQUE;
+ }
+ }
+
private Rect getParentSurfaceInsets() {
final ViewRootImpl root = getViewRootImpl();
if (root == null) {
@@ -522,7 +531,9 @@ public class SurfaceView extends View implements ViewRootImpl.WindowStoppedCallb
if (creating) {
mSurfaceSession = new SurfaceSession(viewRoot.mSurface);
mDeferredDestroySurfaceControl = mSurfaceControl;
- mSurfaceControl = new SurfaceControl(mSurfaceSession,
+
+ updateOpaqueFlag();
+ mSurfaceControl = new SurfaceControlWithBackground(mSurfaceSession,
"SurfaceView - " + viewRoot.getTitle().toString(),
mSurfaceWidth, mSurfaceHeight, mFormat,
mSurfaceFlags);
@@ -1071,4 +1082,126 @@ public class SurfaceView extends View implements ViewRootImpl.WindowStoppedCallb
return mSurfaceFrame;
}
};
+
+ class SurfaceControlWithBackground extends SurfaceControl {
+ private SurfaceControl mBackgroundControl;
+ private boolean mOpaque = true;
+ public boolean mVisible = false;
+
+ public SurfaceControlWithBackground(SurfaceSession s,
+ String name, int w, int h, int format, int flags)
+ throws Exception {
+ super(s, name, w, h, format, flags);
+ mBackgroundControl = new SurfaceControl(s, "Background for - " + name, w, h,
+ PixelFormat.OPAQUE, flags | SurfaceControl.FX_SURFACE_DIM);
+ mOpaque = (flags & SurfaceControl.OPAQUE) != 0;
+ }
+
+ @Override
+ public void setAlpha(float alpha) {
+ super.setAlpha(alpha);
+ mBackgroundControl.setAlpha(alpha);
+ }
+
+ @Override
+ public void setLayer(int zorder) {
+ super.setLayer(zorder);
+ // -3 is below all other child layers as SurfaceView never goes below -2
+ mBackgroundControl.setLayer(-3);
+ }
+
+ @Override
+ public void setPosition(float x, float y) {
+ super.setPosition(x, y);
+ mBackgroundControl.setPosition(x, y);
+ }
+
+ @Override
+ public void setSize(int w, int h) {
+ super.setSize(w, h);
+ mBackgroundControl.setSize(w, h);
+ }
+
+ @Override
+ public void setWindowCrop(Rect crop) {
+ super.setWindowCrop(crop);
+ mBackgroundControl.setWindowCrop(crop);
+ }
+
+ @Override
+ public void setFinalCrop(Rect crop) {
+ super.setFinalCrop(crop);
+ mBackgroundControl.setFinalCrop(crop);
+ }
+
+ @Override
+ public void setLayerStack(int layerStack) {
+ super.setLayerStack(layerStack);
+ mBackgroundControl.setLayerStack(layerStack);
+ }
+
+ @Override
+ public void setOpaque(boolean isOpaque) {
+ super.setOpaque(isOpaque);
+ mOpaque = isOpaque;
+ updateBackgroundVisibility();
+ }
+
+ @Override
+ public void setSecure(boolean isSecure) {
+ super.setSecure(isSecure);
+ }
+
+ @Override
+ public void setMatrix(float dsdx, float dtdx, float dsdy, float dtdy) {
+ super.setMatrix(dsdx, dtdx, dsdy, dtdy);
+ mBackgroundControl.setMatrix(dsdx, dtdx, dsdy, dtdy);
+ }
+
+ @Override
+ public void hide() {
+ super.hide();
+ mVisible = false;
+ updateBackgroundVisibility();
+ }
+
+ @Override
+ public void show() {
+ super.show();
+ mVisible = true;
+ updateBackgroundVisibility();
+ }
+
+ @Override
+ public void destroy() {
+ super.destroy();
+ mBackgroundControl.destroy();
+ }
+
+ @Override
+ public void release() {
+ super.release();
+ mBackgroundControl.release();
+ }
+
+ @Override
+ public void setTransparentRegionHint(Region region) {
+ super.setTransparentRegionHint(region);
+ mBackgroundControl.setTransparentRegionHint(region);
+ }
+
+ @Override
+ public void deferTransactionUntil(IBinder handle, long frame) {
+ super.deferTransactionUntil(handle, frame);
+ mBackgroundControl.deferTransactionUntil(handle, frame);
+ }
+
+ void updateBackgroundVisibility() {
+ if (mOpaque && mVisible) {
+ mBackgroundControl.show();
+ } else {
+ mBackgroundControl.hide();
+ }
+ }
+ }
}
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index 10de5831de6f..2e817eb91cc4 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -4937,9 +4937,6 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
needGlobalAttributesUpdate(true);
}
ai.mKeepScreenOn = lastKeepOn;
- if (!childHasFocus && child.hasFocusable()) {
- focusableViewAvailable(child);
- }
}
if (child.isLayoutDirectionInherited()) {
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 4a231efcdd07..be0bd840c8fa 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -1850,8 +1850,12 @@ public final class ViewRootImpl implements ViewParent,
final boolean isViewVisible = viewVisibility == View.VISIBLE;
final boolean windowRelayoutWasForced = mForceNextWindowRelayout;
- if (mFirst || windowShouldResize || insetsChanged ||
- viewVisibilityChanged || params != null || mForceNextWindowRelayout) {
+ final int contextConfigSeq = mContext.getResources().getConfiguration().seq;
+ final int lastConfigSeq = mLastReportedMergedConfiguration.getMergedConfiguration().seq;
+ final boolean staleConfig = lastConfigSeq != 0 && contextConfigSeq != lastConfigSeq;
+
+ if (mFirst || windowShouldResize || insetsChanged || staleConfig || viewVisibilityChanged
+ || params != null || mForceNextWindowRelayout) {
mForceNextWindowRelayout = false;
if (isViewVisible) {
@@ -6088,7 +6092,13 @@ public final class ViewRootImpl implements ViewParent,
if (params != null) {
if (DBG) Log.d(mTag, "WindowLayout in layoutWindow:" + params);
}
- mPendingMergedConfiguration.getMergedConfiguration().seq = 0;
+
+ if (mPendingMergedConfiguration.getMergedConfiguration().seq == 0) {
+ mPendingMergedConfiguration.setTo(mLastReportedMergedConfiguration);
+ }
+
+ int initialConfigSeq = mPendingMergedConfiguration.getMergedConfiguration().seq;
+
//Log.d(mTag, ">>>>>> CALLING relayout");
if (params != null && mOrigWindowType != params.type) {
// For compatibility with old apps, don't crash here.
@@ -6107,6 +6117,10 @@ public final class ViewRootImpl implements ViewParent,
mPendingStableInsets, mPendingOutsets, mPendingBackDropFrame,
mPendingMergedConfiguration, mSurface);
+ if (initialConfigSeq == mPendingMergedConfiguration.getMergedConfiguration().seq) {
+ mPendingMergedConfiguration.getMergedConfiguration().seq = 0;
+ }
+
mPendingAlwaysConsumeNavBar =
(relayoutResult & WindowManagerGlobal.RELAYOUT_RES_CONSUME_ALWAYS_NAV_BAR) != 0;
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index 12ff21788da5..dfbf9620c82c 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -19,6 +19,7 @@ package android.view;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.SystemApi;
+import android.annotation.SystemService;
import android.annotation.TestApi;
import android.app.KeyguardManager;
import android.app.Presentation;
@@ -39,8 +40,6 @@ import java.util.Objects;
/**
* The interface that apps use to talk to the window manager.
- * <p>
- * Use <code>Context.getSystemService(Context.WINDOW_SERVICE)</code> to get one of these.
* </p><p>
* Each window manager instance is bound to a particular {@link Display}.
* To obtain a {@link WindowManager} for a different display, use
@@ -52,10 +51,8 @@ import java.util.Objects;
* {@link Presentation}. The presentation will automatically obtain a
* {@link WindowManager} and {@link Context} for that display.
* </p>
- *
- * @see android.content.Context#getSystemService
- * @see android.content.Context#WINDOW_SERVICE
*/
+@SystemService(Context.WINDOW_SERVICE)
public interface WindowManager extends ViewManager {
/** @hide */
diff --git a/core/java/android/view/accessibility/AccessibilityManager.java b/core/java/android/view/accessibility/AccessibilityManager.java
index c8f297ae9c1f..8fc586eba21d 100644
--- a/core/java/android/view/accessibility/AccessibilityManager.java
+++ b/core/java/android/view/accessibility/AccessibilityManager.java
@@ -24,6 +24,7 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SdkConstant;
import android.annotation.SystemApi;
+import android.annotation.SystemService;
import android.content.ComponentName;
import android.content.Context;
import android.content.pm.PackageManager;
@@ -60,15 +61,6 @@ import java.util.List;
* {@link android.view.View} changes etc. Parties interested in handling accessibility
* events implement and register an accessibility service which extends
* {@link android.accessibilityservice.AccessibilityService}.
- * <p>
- * To obtain a handle to the accessibility manager do the following:
- * </p>
- * <p>
- * <code>
- * <pre>AccessibilityManager accessibilityManager =
- * (AccessibilityManager) context.getSystemService(Context.ACCESSIBILITY_SERVICE);</pre>
- * </code>
- * </p>
*
* @see AccessibilityEvent
* @see AccessibilityNodeInfo
@@ -76,6 +68,7 @@ import java.util.List;
* @see Context#getSystemService
* @see Context#ACCESSIBILITY_SERVICE
*/
+@SystemService(Context.ACCESSIBILITY_SERVICE)
public final class AccessibilityManager {
private static final boolean DEBUG = false;
diff --git a/core/java/android/view/accessibility/CaptioningManager.java b/core/java/android/view/accessibility/CaptioningManager.java
index 14f0b0a06218..d6455e7270a9 100644
--- a/core/java/android/view/accessibility/CaptioningManager.java
+++ b/core/java/android/view/accessibility/CaptioningManager.java
@@ -18,6 +18,7 @@ package android.view.accessibility;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.SystemService;
import android.content.ContentResolver;
import android.content.Context;
import android.database.ContentObserver;
@@ -34,14 +35,8 @@ import java.util.Locale;
/**
* Contains methods for accessing and monitoring preferred video captioning state and visual
* properties.
- * <p>
- * To obtain a handle to the captioning manager, do the following:
- * <p>
- * <code>
- * <pre>CaptioningManager captioningManager =
- * (CaptioningManager) context.getSystemService(Context.CAPTIONING_SERVICE);</pre>
- * </code>
*/
+@SystemService(Context.CAPTIONING_SERVICE)
public class CaptioningManager {
/** Default captioning enabled value. */
private static final int DEFAULT_ENABLED = 0;
diff --git a/core/java/android/view/autofill/AutofillManager.java b/core/java/android/view/autofill/AutofillManager.java
index 02ecc501ea39..310ec1c938d0 100644
--- a/core/java/android/view/autofill/AutofillManager.java
+++ b/core/java/android/view/autofill/AutofillManager.java
@@ -23,6 +23,7 @@ import static android.view.autofill.Helper.sVerbose;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.SystemService;
import android.content.Context;
import android.content.Intent;
import android.content.IntentSender;
@@ -55,6 +56,7 @@ import java.util.Objects;
*
* <p>It is safe to call into this from any thread.
*/
+@SystemService(Context.AUTOFILL_MANAGER_SERVICE)
public final class AutofillManager {
private static final String TAG = "AutofillManager";
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index da9316c300b3..e2f7979c61d9 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -21,6 +21,7 @@ import static android.Manifest.permission.WRITE_SECURE_SETTINGS;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
+import android.annotation.SystemService;
import android.content.Context;
import android.graphics.Rect;
import android.net.Uri;
@@ -73,8 +74,6 @@ import java.util.concurrent.TimeUnit;
/**
* Central system API to the overall input method framework (IMF) architecture,
* which arbitrates interaction between applications and the current input method.
- * You can retrieve an instance of this interface with
- * {@link Context#getSystemService(String) Context.getSystemService()}.
*
* <p>Topics covered here:
* <ol>
@@ -211,6 +210,7 @@ import java.util.concurrent.TimeUnit;
* and want to make it available for use.</p>
* </ul>
*/
+@SystemService(Context.INPUT_METHOD_SERVICE)
public final class InputMethodManager {
static final boolean DEBUG = false;
static final String TAG = "InputMethodManager";
diff --git a/core/java/android/view/textclassifier/TextClassificationManager.java b/core/java/android/view/textclassifier/TextClassificationManager.java
index 6b641dbfef8e..efc88e23fa67 100644
--- a/core/java/android/view/textclassifier/TextClassificationManager.java
+++ b/core/java/android/view/textclassifier/TextClassificationManager.java
@@ -18,6 +18,7 @@ package android.view.textclassifier;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.SystemService;
import android.content.Context;
import android.os.ParcelFileDescriptor;
import android.util.Log;
@@ -33,10 +34,8 @@ import java.util.Locale;
/**
* Interface to the text classification service.
- *
- * <p>You do not instantiate this class directly; instead, retrieve it through
- * {@link android.content.Context#getSystemService}.
*/
+@SystemService(Context.TEXT_CLASSIFICATION_SERVICE)
public final class TextClassificationManager {
private static final String LOG_TAG = "TextClassificationManager";
diff --git a/core/java/android/view/textservice/TextServicesManager.java b/core/java/android/view/textservice/TextServicesManager.java
index b4e6c5699007..d9bfade33539 100644
--- a/core/java/android/view/textservice/TextServicesManager.java
+++ b/core/java/android/view/textservice/TextServicesManager.java
@@ -16,6 +16,7 @@
package android.view.textservice;
+import android.annotation.SystemService;
import android.content.Context;
import android.os.Bundle;
import android.os.RemoteException;
@@ -30,8 +31,7 @@ import java.util.Locale;
/**
* System API to the overall text services, which arbitrates interaction between applications
- * and text services. You can retrieve an instance of this interface with
- * {@link Context#getSystemService(String) Context.getSystemService()}.
+ * and text services.
*
* The user can change the current text services in Settings. And also applications can specify
* the target text services.
@@ -61,6 +61,7 @@ import java.util.Locale;
* </ul>
*
*/
+@SystemService(Context.TEXT_SERVICES_MANAGER_SERVICE)
public final class TextServicesManager {
private static final String TAG = TextServicesManager.class.getSimpleName();
private static final boolean DBG = false;
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index 1fef7cbd1953..c19ee56e7636 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -3842,11 +3842,12 @@ public class Editor {
}
if (mTextView.canRequestAutofill()) {
- final int mode = mTextView.getText().length() <= 0
- ? MenuItem.SHOW_AS_ACTION_IF_ROOM : MenuItem.SHOW_AS_ACTION_NEVER;
- menu.add(Menu.NONE, TextView.ID_AUTOFILL, MENU_ITEM_ORDER_AUTOFILL,
- com.android.internal.R.string.autofill)
- .setShowAsAction(mode);
+ final String selected = mTextView.getSelectedText();
+ if (selected == null || selected.isEmpty()) {
+ menu.add(Menu.NONE, TextView.ID_AUTOFILL, MENU_ITEM_ORDER_AUTOFILL,
+ com.android.internal.R.string.autofill)
+ .setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
+ }
}
if (mTextView.canPasteAsPlainText()) {
diff --git a/core/java/com/android/internal/notification/SystemNotificationChannels.java b/core/java/com/android/internal/notification/SystemNotificationChannels.java
index 797cf2b6de56..d327180c6e9d 100644
--- a/core/java/com/android/internal/notification/SystemNotificationChannels.java
+++ b/core/java/com/android/internal/notification/SystemNotificationChannels.java
@@ -135,7 +135,7 @@ public class SystemNotificationChannels {
channelsList.add(new NotificationChannel(
FOREGROUND_SERVICE,
context.getString(R.string.notification_channel_foreground_service),
- NotificationManager.IMPORTANCE_MIN));
+ NotificationManager.IMPORTANCE_LOW));
nm.createNotificationChannels(channelsList);
}
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 1b0d3323b3d0..cbe4c15cf790 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -171,6 +171,7 @@ public class BatteryStatsImpl extends BatteryStats {
public interface PlatformIdleStateCallback {
public String getPlatformLowPowerStats();
+ public String getSubsystemLowPowerStats();
}
private final PlatformIdleStateCallback mPlatformIdleStateCallback;
@@ -2878,6 +2879,12 @@ public class BatteryStatsImpl extends BatteryStats {
mPlatformIdleStateCallback.getPlatformLowPowerStats();
if (DEBUG) Slog.i(TAG, "WRITE PlatformIdleState:" +
mCurHistoryStepDetails.statPlatformIdleState);
+
+ mCurHistoryStepDetails.statSubsystemPowerState =
+ mPlatformIdleStateCallback.getSubsystemLowPowerStats();
+ if (DEBUG) Slog.i(TAG, "WRITE SubsystemPowerState:" +
+ mCurHistoryStepDetails.statSubsystemPowerState);
+
}
computeHistoryStepDetails(mCurHistoryStepDetails, mLastHistoryStepDetails);
if (includeStepDetails != 0) {
@@ -10175,7 +10182,16 @@ public class BatteryStatsImpl extends BatteryStats {
new KernelUidCpuTimeReader.Callback() {
@Override
public void onUidCpuTime(int uid, long userTimeUs, long systemTimeUs) {
- final Uid u = getUidStatsLocked(mapUid(uid));
+ uid = mapUid(uid);
+ if (Process.isIsolated(uid)) {
+ // This could happen if the isolated uid mapping was removed before
+ // that process was actually killed.
+ mKernelUidCpuTimeReader.removeUid(uid);
+ Slog.d(TAG, "Got readings for an isolated uid with"
+ + " no mapping to owning uid: " + uid);
+ return;
+ }
+ final Uid u = getUidStatsLocked(uid);
// Accumulate the total system and user time.
mTempTotalCpuUserTimeUs += userTimeUs;
@@ -10340,7 +10356,11 @@ public class BatteryStatsImpl extends BatteryStats {
@Override
public void onUidCpuFreqTime(int uid, long[] cpuFreqTimeMs) {
- final Uid u = getUidStatsLocked(mapUid(uid));
+ uid = mapUid(uid);
+ if (Process.isIsolated(uid)) {
+ return;
+ }
+ final Uid u = getUidStatsLocked(uid);
if (u.mCpuFreqTimeMs == null) {
u.mCpuFreqTimeMs = new LongSamplingCounterArray(mOnBatteryTimeBase);
}
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 46bdafab9700..ae7355f77cd0 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -1322,6 +1322,27 @@
<permission android:name="android.permission.NETWORK_SETTINGS"
android:protectionLevel="signature" />
+ <!-- #SystemApi @hide Allows applications to access information about LoWPAN interfaces.
+ <p>Not for use by third-party applications. -->
+ <permission android:name="android.permission.ACCESS_LOWPAN_STATE"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- #SystemApi @hide Allows applications to change LoWPAN connectivity state.
+ <p>Not for use by third-party applications. -->
+ <permission android:name="android.permission.CHANGE_LOWPAN_STATE"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- #SystemApi @hide Allows applications to read LoWPAN credential.
+ <p>Not for use by third-party applications. -->
+ <permission android:name="android.permission.READ_LOWPAN_CREDENTIAL"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- #SystemApi @hide Allows a service to register or unregister
+ new LoWPAN interfaces.
+ <p>Not for use by third-party applications. -->
+ <permission android:name="android.permission.MANAGE_LOWPAN_INTERFACES"
+ android:protectionLevel="signature|privileged" />
+
<!-- ======================================= -->
<!-- Permissions for short range, peripheral networks -->
<!-- ======================================= -->
diff --git a/core/res/res/drawable/stat_sys_vitals.xml b/core/res/res/drawable/stat_sys_vitals.xml
new file mode 100644
index 000000000000..213dd5fbed6e
--- /dev/null
+++ b/core/res/res/drawable/stat_sys_vitals.xml
@@ -0,0 +1,29 @@
+<!--
+Copyright (C) 2017 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<!-- "system vitals", as represented by an EKG trace -->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M19.5608645,12.0797103 L17.15,5.15 L15.25,5.15 L11.95,15.95 L9.75,11.5 L7.95,11.55 L7.2,13.3
+ L6.65,14.6 L3.25,14.6 L3.25,16.6 L7.35,16.6 L8,16.6 L8.25,16 L8.9,14.3 L11.2,18.85 L13.15,18.85 L16.25,8.8
+ L17.5310733,12.642689 C17.2014325,12.9992627 17,13.4761078 17,14 C17,15.1045695 17.8954305,16 19,16
+ C20.1045695,16 21,15.1045695 21,14 C21,13.0901368 20.3924276,12.3221796 19.5608645,12.0797103 Z M21,3
+ C22,3 23,4 23,5 L23,19 C23,20 22,21 21,21 L3,21 C1.9,21 1,20.1 1,19 L1,5 C1,4 2,3 3,3 L21,3 Z" />
+</vector>
diff --git a/core/res/res/values-mcc310-mnc004/config.xml b/core/res/res/values-mcc310-mnc004/config.xml
index 304948893a8d..a328c49cbc71 100755
--- a/core/res/res/values-mcc310-mnc004/config.xml
+++ b/core/res/res/values-mcc310-mnc004/config.xml
@@ -23,6 +23,7 @@
<string-array translatable="false" name="config_cdma_home_system">
<item>64</item>
<item>65</item>
+ <item>66</item>
<item>76</item>
<item>77</item>
<item>78</item>
diff --git a/core/res/res/values-mcc311-mnc480/config.xml b/core/res/res/values-mcc311-mnc480/config.xml
index 6f85081bb704..04f182e1a92c 100755
--- a/core/res/res/values-mcc311-mnc480/config.xml
+++ b/core/res/res/values-mcc311-mnc480/config.xml
@@ -23,6 +23,7 @@
<string-array translatable="false" name="config_cdma_home_system">
<item>64</item>
<item>65</item>
+ <item>66</item>
<item>76</item>
<item>77</item>
<item>78</item>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index e085697628f5..8e7b81740728 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -1091,6 +1091,11 @@
that can be set by the user. -->
<integer name="config_screenBrightnessDoze">1</integer>
+ <!-- Whether or not to skip the initial brightness ramps when the display transitions to
+ STATE_ON. Setting this to true will skip the brightness ramp to the last stored active
+ brightness value and will repeat for the following ramp if autobrightness is enabled. -->
+ <bool name="config_skipScreenOnBrightnessRamp">false</bool>
+
<!-- Allow automatic adjusting of the screen brightness while dozing in low power state. -->
<bool name="config_allowAutoBrightnessWhileDozing">false</bool>
@@ -2953,4 +2958,10 @@
<!-- The OEM specified sensor string type for the gesture to launch camera app, this value
must match the value of config_cameraLiftTriggerSensorType in OEM's HAL -->
<string translatable="false" name="config_cameraLiftTriggerSensorStringType"></string>
+
+ <!-- Default number of days to retain for the automatic storage manager. -->
+ <integer translatable="false" name="config_storageManagerDaystoRetainDefault">90</integer>
+
+ <!-- Name of a font family to use for headlines. If empty, falls back to platform default -->
+ <string name="config_headlineFontFamily" translatable="false"></string>
</resources>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 80b72fa46605..5ffa48cb87db 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -1762,6 +1762,7 @@
<java-symbol type="bool" name="config_sf_limitedAlpha" />
<java-symbol type="bool" name="config_unplugTurnsOnScreen" />
<java-symbol type="bool" name="config_usbChargingMessage" />
+ <java-symbol type="bool" name="config_skipScreenOnBrightnessRamp" />
<java-symbol type="bool" name="config_allowAutoBrightnessWhileDozing" />
<java-symbol type="bool" name="config_allowTheaterModeWakeFromUnplug" />
<java-symbol type="bool" name="config_allowTheaterModeWakeFromGesture" />
@@ -3038,8 +3039,10 @@
<java-symbol type="array" name="config_allowedSecureInstantAppSettings" />
<java-symbol type="bool" name="config_handleVolumeKeysInWindowManager" />
-
<java-symbol type="integer" name="config_inCallNotificationVolumeRelative" />
-
<java-symbol type="bool" name="config_dozeAlwaysOnDisplayAvailable" />
+ <java-symbol type="integer" name="config_storageManagerDaystoRetainDefault" />
+ <java-symbol type="string" name="config_headlineFontFamily" />
+
+ <java-symbol type="drawable" name="stat_sys_vitals" />
</resources>
diff --git a/core/tests/coretests/src/android/text/DynamicLayoutTest.java b/core/tests/coretests/src/android/text/DynamicLayoutTest.java
index da6dc7edbb5e..811bf2c43320 100644
--- a/core/tests/coretests/src/android/text/DynamicLayoutTest.java
+++ b/core/tests/coretests/src/android/text/DynamicLayoutTest.java
@@ -17,15 +17,14 @@
package android.text;
import static android.text.Layout.Alignment.ALIGN_NORMAL;
+
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
-import static org.mockito.Matchers.any;
-import static org.mockito.Mockito.doNothing;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
+import android.graphics.Canvas;
+import android.graphics.Paint;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
import android.text.style.ReplacementSpan;
@@ -54,6 +53,16 @@ public class DynamicLayoutTest {
assertNull(layout.getBlocksAlwaysNeedToBeRedrawn());
}
+ private class MockReplacementSpan extends ReplacementSpan {
+ public int getSize(Paint paint, CharSequence text, int start, int end,
+ Paint.FontMetricsInt fm) {
+ return 10;
+ }
+
+ public void draw(Canvas canvas, CharSequence text, int start, int end, float x, int top,
+ int y, int bottom, Paint paint) { }
+ }
+
@Test
public void testGetBlocksAlwaysNeedToBeRedrawn_replacementSpan() {
final SpannableStringBuilder builder = new SpannableStringBuilder();
@@ -66,17 +75,11 @@ public class DynamicLayoutTest {
builder.append("hijk lmn\n");
assertNull(layout.getBlocksAlwaysNeedToBeRedrawn());
- ReplacementSpan mockReplacementSpan = mock(ReplacementSpan.class);
- when(mockReplacementSpan.getSize(any(), any(), any(), any(), any()))
- .thenReturn(10);
- doNothing().when(mockReplacementSpan)
- .draw(any(), any(), any(), any(), any(), any(), any(), any(), any());
-
- builder.setSpan(mockReplacementSpan, 0, 4, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
+ builder.setSpan(new MockReplacementSpan(), 0, 4, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
assertNotNull(layout.getBlocksAlwaysNeedToBeRedrawn());
assertTrue(layout.getBlocksAlwaysNeedToBeRedrawn().contains(0));
- builder.setSpan(mockReplacementSpan, 9, 13, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
+ builder.setSpan(new MockReplacementSpan(), 9, 13, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
assertTrue(layout.getBlocksAlwaysNeedToBeRedrawn().contains(0));
assertTrue(layout.getBlocksAlwaysNeedToBeRedrawn().contains(1));
diff --git a/core/tests/coretests/src/com/android/internal/widget/ActionBarContainerTest.java b/core/tests/coretests/src/com/android/internal/widget/ActionBarContainerTest.java
index 1471796553a6..912b7ec02b15 100644
--- a/core/tests/coretests/src/com/android/internal/widget/ActionBarContainerTest.java
+++ b/core/tests/coretests/src/com/android/internal/widget/ActionBarContainerTest.java
@@ -60,11 +60,9 @@ public class ActionBarContainerTest extends AndroidTestCase {
TestViewGroup viewGroup = new TestViewGroup(mContext);
viewGroup.addView(mActionBarContainer);
- ActionMode mode = mActionBarContainer.startActionModeForChild(
- null, null, ActionMode.TYPE_FLOATING);
+ mActionBarContainer.startActionModeForChild(null, null, ActionMode.TYPE_FLOATING);
// Should bubble up.
- assertNotNull(mode);
assertTrue(viewGroup.isStartActionModeForChildTypedCalled);
}
diff --git a/drm/java/android/drm/DrmUtils.java b/drm/java/android/drm/DrmUtils.java
index 2a86996ef46a..60ee6d94949f 100644
--- a/drm/java/android/drm/DrmUtils.java
+++ b/drm/java/android/drm/DrmUtils.java
@@ -17,6 +17,7 @@
package android.drm;
import java.io.BufferedInputStream;
+import java.io.Closeable;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
@@ -79,26 +80,16 @@ public class DrmUtils {
file.delete();
}
- private static void quietlyDispose(InputStream stream) {
+ private static void quietlyDispose(Closeable closable) {
try {
- if (null != stream) {
- stream.close();
+ if (null != closable) {
+ closable.close();
}
} catch (IOException e) {
// no need to care, at least as of now
}
}
- private static void quietlyDispose(OutputStream stream) {
- try {
- if (null != stream) {
- stream.close();
- }
- } catch (IOException e) {
- // no need to care
- }
- }
-
/**
* Gets an instance of {@link DrmUtils.ExtendedMetadataParser}, which can be used to parse
* extended metadata embedded in DRM constraint information.
diff --git a/libs/hwui/Android.bp b/libs/hwui/Android.bp
index 4cfb9d88c716..303d05f084aa 100644
--- a/libs/hwui/Android.bp
+++ b/libs/hwui/Android.bp
@@ -141,6 +141,7 @@ cc_defaults {
"renderstate/Scissor.cpp",
"renderstate/Stencil.cpp",
"renderstate/TextureState.cpp",
+ "renderthread/CacheManager.cpp",
"renderthread/CanvasContext.cpp",
"renderthread/OpenGLPipeline.cpp",
"renderthread/DrawFrameTask.cpp",
@@ -300,6 +301,7 @@ cc_test {
"tests/unit/BakedOpRendererTests.cpp",
"tests/unit/BakedOpStateTests.cpp",
"tests/unit/BitmapTests.cpp",
+ "tests/unit/CacheManagerTests.cpp",
"tests/unit/CanvasContextTests.cpp",
"tests/unit/CanvasStateTests.cpp",
"tests/unit/ClipAreaTests.cpp",
diff --git a/libs/hwui/pipeline/skia/SkiaPipeline.cpp b/libs/hwui/pipeline/skia/SkiaPipeline.cpp
index 88293db193f8..bbbbd5ce51b2 100644
--- a/libs/hwui/pipeline/skia/SkiaPipeline.cpp
+++ b/libs/hwui/pipeline/skia/SkiaPipeline.cpp
@@ -50,8 +50,7 @@ TaskManager* SkiaPipeline::getTaskManager() {
}
void SkiaPipeline::onDestroyHardwareResources() {
- // No need to flush the caches here. There is a timer
- // which will flush temporary resources over time.
+ mRenderThread.cacheManager().trimStaleResources();
}
bool SkiaPipeline::pinImages(std::vector<SkImage*>& mutableImages) {
diff --git a/libs/hwui/renderstate/RenderState.h b/libs/hwui/renderstate/RenderState.h
index 787946f79f6b..4b7a86580621 100644
--- a/libs/hwui/renderstate/RenderState.h
+++ b/libs/hwui/renderstate/RenderState.h
@@ -45,6 +45,7 @@ class Layer;
class DeferredLayerUpdater;
namespace renderthread {
+class CacheManager;
class CanvasContext;
class RenderThread;
}
@@ -55,6 +56,7 @@ class RenderState {
PREVENT_COPY_AND_ASSIGN(RenderState);
friend class renderthread::RenderThread;
friend class Caches;
+ friend class renderthread::CacheManager;
public:
void onGLContextCreated();
void onGLContextDestroyed();
diff --git a/libs/hwui/renderthread/CacheManager.cpp b/libs/hwui/renderthread/CacheManager.cpp
new file mode 100644
index 000000000000..f0d6b3860938
--- /dev/null
+++ b/libs/hwui/renderthread/CacheManager.cpp
@@ -0,0 +1,187 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "CacheManager.h"
+
+#include "Layer.h"
+#include "RenderThread.h"
+#include "renderstate/RenderState.h"
+
+#include <gui/Surface.h>
+#include <GrContextOptions.h>
+#include <math.h>
+#include <set>
+
+namespace android {
+namespace uirenderer {
+namespace renderthread {
+
+// This multiplier was selected based on historical review of cache sizes relative
+// to the screen resolution. This is meant to be a conservative default based on
+// that analysis. The 4.0f is used because the default pixel format is assumed to
+// be ARGB_8888.
+#define SURFACE_SIZE_MULTIPLIER (12.0f * 4.0f)
+#define BACKGROUND_RETENTION_PERCENTAGE (0.5f)
+
+// for super large fonts we will draw them as paths so no need to keep linearly
+// increasing the font cache size.
+#define FONT_CACHE_MIN_MB (0.5f)
+#define FONT_CACHE_MAX_MB (4.0f)
+
+CacheManager::CacheManager(const DisplayInfo& display)
+ : mMaxSurfaceArea(display.w * display.h) {
+ mVectorDrawableAtlas.reset(new VectorDrawableAtlas);
+}
+
+void CacheManager::reset(GrContext* context) {
+ if (context != mGrContext.get()) {
+ destroy();
+ }
+
+ if (context) {
+ mGrContext = sk_ref_sp(context);
+ mGrContext->getResourceCacheLimits(&mMaxResources, nullptr);
+ updateContextCacheSizes();
+ }
+}
+
+void CacheManager::destroy() {
+ // cleanup any caches here as the GrContext is about to go away...
+ mGrContext.reset(nullptr);
+ mVectorDrawableAtlas.reset(new VectorDrawableAtlas);
+}
+
+void CacheManager::updateContextCacheSizes() {
+ mMaxResourceBytes = mMaxSurfaceArea * SURFACE_SIZE_MULTIPLIER;
+ mBackgroundResourceBytes = mMaxResourceBytes * BACKGROUND_RETENTION_PERCENTAGE;
+
+ mGrContext->setResourceCacheLimits(mMaxResources, mMaxResourceBytes);
+}
+
+void CacheManager::configureContext(GrContextOptions* contextOptions) {
+ contextOptions->fAllowPathMaskCaching = true;
+
+ float screenMP = mMaxSurfaceArea / 1024.0f / 1024.0f;
+ float fontCacheMB = 0;
+ float decimalVal = std::modf(screenMP, &fontCacheMB);
+
+ // This is a basic heuristic to size the cache to a multiple of 512 KB
+ if (decimalVal > 0.8f) {
+ fontCacheMB += 1.0f;
+ } else if (decimalVal > 0.5f) {
+ fontCacheMB += 0.5f;
+ }
+
+ // set limits on min/max size of the cache
+ fontCacheMB = std::max(FONT_CACHE_MIN_MB, std::min(FONT_CACHE_MAX_MB, fontCacheMB));
+
+ // We must currently set the size of the text cache based on the size of the
+ // display even though we like to be dynamicallysizing it to the size of the window.
+ // Skia's implementation doesn't provide a mechanism to resize the font cache due to
+ // the potential cost of recreating the glyphs.
+ contextOptions->fGlyphCacheTextureMaximumBytes = fontCacheMB * 1024 * 1024;
+}
+
+void CacheManager::trimMemory(TrimMemoryMode mode) {
+ if (!mGrContext) {
+ return;
+ }
+
+ mGrContext->flush();
+
+ switch (mode) {
+ case TrimMemoryMode::Complete:
+ mVectorDrawableAtlas.reset(new VectorDrawableAtlas);
+ mGrContext->freeGpuResources();
+ break;
+ case TrimMemoryMode::UiHidden:
+ mGrContext->purgeUnlockedResources(mMaxResourceBytes - mBackgroundResourceBytes, true);
+ break;
+ }
+}
+
+void CacheManager::trimStaleResources() {
+ if (!mGrContext) {
+ return;
+ }
+ mGrContext->flush();
+ mGrContext->purgeResourcesNotUsedInMs(std::chrono::seconds(30));
+}
+
+VectorDrawableAtlas* CacheManager::acquireVectorDrawableAtlas() {
+ LOG_ALWAYS_FATAL_IF(mVectorDrawableAtlas.get() == nullptr);
+ LOG_ALWAYS_FATAL_IF(mGrContext == nullptr);
+
+ /**
+ * TODO LIST:
+ * 1) compute the atlas based on the surfaceArea surface
+ * 2) identify a way to reuse cache entries
+ * 3) add ability to repack the cache?
+ * 4) define memory conditions where we clear the cache (e.g. surface->reset())
+ */
+
+ return mVectorDrawableAtlas.release();
+}
+void CacheManager::releaseVectorDrawableAtlas(VectorDrawableAtlas* atlas) {
+ LOG_ALWAYS_FATAL_IF(mVectorDrawableAtlas.get() != nullptr);
+ mVectorDrawableAtlas.reset(atlas);
+ mVectorDrawableAtlas->isNewAtlas = false;
+}
+
+void CacheManager::dumpMemoryUsage(String8& log, const RenderState* renderState) {
+ if (!mGrContext) {
+ log.appendFormat("No valid cache instance.\n");
+ return;
+ }
+
+ size_t bytesCached;
+ mGrContext->getResourceCacheUsage(nullptr, &bytesCached);
+
+ log.appendFormat("Caches:\n");
+ log.appendFormat(" Current / Maximum\n");
+ log.appendFormat(" VectorDrawableAtlas %6.2f kB / %6.2f kB (entries = %zu)\n",
+ 0.0f, 0.0f, (size_t)0);
+
+ if (renderState) {
+ if (renderState->mActiveLayers.size() > 0) {
+ log.appendFormat(" Layer Info:\n");
+ }
+
+ size_t layerMemoryTotal = 0;
+ for (std::set<Layer*>::iterator it = renderState->mActiveLayers.begin();
+ it != renderState->mActiveLayers.end(); it++) {
+ const Layer* layer = *it;
+ const char* layerType = layer->getApi() == Layer::Api::OpenGL ? "GlLayer" : "VkLayer";
+ log.appendFormat(" %s size %dx%d\n", layerType,
+ layer->getWidth(), layer->getHeight());
+ layerMemoryTotal += layer->getWidth() * layer->getHeight() * 4;
+ }
+ log.appendFormat(" Layers Total %6.2f kB (numLayers = %zu)\n",
+ layerMemoryTotal / 1024.0f, renderState->mActiveLayers.size());
+ }
+
+
+ log.appendFormat("Total memory usage:\n");
+ log.appendFormat(" %zu bytes, %.2f MB (%.2f MB is purgeable)\n",
+ bytesCached, bytesCached / 1024.0f / 1024.0f,
+ mGrContext->getResourceCachePurgeableBytes() / 1024.0f / 1024.0f);
+
+
+}
+
+} /* namespace renderthread */
+} /* namespace uirenderer */
+} /* namespace android */
diff --git a/libs/hwui/renderthread/CacheManager.h b/libs/hwui/renderthread/CacheManager.h
new file mode 100644
index 000000000000..43d58f2d58a8
--- /dev/null
+++ b/libs/hwui/renderthread/CacheManager.h
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef CACHEMANAGER_H
+#define CACHEMANAGER_H
+
+#include <GrContext.h>
+#include <SkSurface.h>
+#include <ui/DisplayInfo.h>
+#include <utils/String8.h>
+#include <vector>
+
+namespace android {
+
+class Surface;
+
+namespace uirenderer {
+
+class RenderState;
+
+namespace renderthread {
+
+class IRenderPipeline;
+class RenderThread;
+
+struct VectorDrawableAtlas {
+ sk_sp<SkSurface> surface;
+ bool isNewAtlas = true;
+};
+
+class CacheManager {
+public:
+ enum class TrimMemoryMode {
+ Complete,
+ UiHidden
+ };
+
+ void configureContext(GrContextOptions* context);
+ void trimMemory(TrimMemoryMode mode);
+ void trimStaleResources();
+ void dumpMemoryUsage(String8& log, const RenderState* renderState = nullptr);
+
+ VectorDrawableAtlas* acquireVectorDrawableAtlas();
+ void releaseVectorDrawableAtlas(VectorDrawableAtlas*);
+
+ size_t getCacheSize() const { return mMaxResourceBytes; }
+ size_t getBackgroundCacheSize() const { return mBackgroundResourceBytes; }
+
+private:
+ friend class RenderThread;
+
+ CacheManager(const DisplayInfo& display);
+
+
+ void reset(GrContext* grContext);
+ void destroy();
+ void updateContextCacheSizes();
+
+ const size_t mMaxSurfaceArea;
+ sk_sp<GrContext> mGrContext;
+
+ int mMaxResources = 0;
+ size_t mMaxResourceBytes = 0;
+ size_t mBackgroundResourceBytes = 0;
+
+ struct PipelineProps {
+ const void* pipelineKey = nullptr;
+ size_t surfaceArea = 0;
+ };
+
+ std::unique_ptr<VectorDrawableAtlas> mVectorDrawableAtlas;
+};
+
+} /* namespace renderthread */
+} /* namespace uirenderer */
+} /* namespace android */
+
+#endif /* CACHEMANAGER_H */
+
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index e2a4a2a8dec2..a79bf359913b 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -585,15 +585,37 @@ void CanvasContext::destroyHardwareResources() {
}
void CanvasContext::trimMemory(RenderThread& thread, int level) {
- // No context means nothing to free
- if (!thread.eglManager().hasEglContext()) return;
-
- ATRACE_CALL();
- if (level >= TRIM_MEMORY_COMPLETE) {
- thread.renderState().flush(Caches::FlushMode::Full);
- thread.eglManager().destroy();
- } else if (level >= TRIM_MEMORY_UI_HIDDEN) {
- thread.renderState().flush(Caches::FlushMode::Moderate);
+ auto renderType = Properties::getRenderPipelineType();
+ switch (renderType) {
+ case RenderPipelineType::OpenGL: {
+ // No context means nothing to free
+ if (!thread.eglManager().hasEglContext()) return;
+ ATRACE_CALL();
+ if (level >= TRIM_MEMORY_COMPLETE) {
+ thread.renderState().flush(Caches::FlushMode::Full);
+ thread.eglManager().destroy();
+ } else if (level >= TRIM_MEMORY_UI_HIDDEN) {
+ thread.renderState().flush(Caches::FlushMode::Moderate);
+ }
+ break;
+ }
+ case RenderPipelineType::SkiaGL:
+ case RenderPipelineType::SkiaVulkan: {
+ // No context means nothing to free
+ if (!thread.getGrContext()) return;
+ ATRACE_CALL();
+ if (level >= TRIM_MEMORY_COMPLETE) {
+ thread.cacheManager().trimMemory(CacheManager::TrimMemoryMode::Complete);
+ thread.eglManager().destroy();
+ thread.vulkanManager().destroy();
+ } else if (level >= TRIM_MEMORY_UI_HIDDEN) {
+ thread.cacheManager().trimMemory(CacheManager::TrimMemoryMode::UiHidden);
+ }
+ break;
+ }
+ default:
+ LOG_ALWAYS_FATAL("canvas context type %d not supported", (int32_t) renderType);
+ break;
}
}
diff --git a/libs/hwui/renderthread/EglManager.cpp b/libs/hwui/renderthread/EglManager.cpp
index 53d42a2b9c43..ecf686c5b40c 100644
--- a/libs/hwui/renderthread/EglManager.cpp
+++ b/libs/hwui/renderthread/EglManager.cpp
@@ -138,7 +138,7 @@ void EglManager::initialize() {
GrContextOptions options;
options.fGpuPathRenderers &= ~GrContextOptions::GpuPathRenderers::kDistanceField;
- options.fAllowPathMaskCaching = true;
+ mRenderThread.cacheManager().configureContext(&options);
mRenderThread.setGrContext(GrContext::Create(GrBackend::kOpenGL_GrBackend,
(GrBackendContext)glInterface.get(), options));
}
diff --git a/libs/hwui/renderthread/RenderProxy.cpp b/libs/hwui/renderthread/RenderProxy.cpp
index 5a4695f1315e..ec56c313f62a 100644
--- a/libs/hwui/renderthread/RenderProxy.cpp
+++ b/libs/hwui/renderthread/RenderProxy.cpp
@@ -469,18 +469,7 @@ uint32_t RenderProxy::frameTimePercentile(int p) {
}
CREATE_BRIDGE2(dumpGraphicsMemory, int fd, RenderThread* thread) {
- args->thread->jankTracker().dump(args->fd);
-
- FILE *file = fdopen(args->fd, "a");
- if (Caches::hasInstance()) {
- String8 cachesLog;
- Caches::getInstance().dumpMemoryUsage(cachesLog);
- fprintf(file, "\nCaches:\n%s\n", cachesLog.string());
- } else {
- fprintf(file, "\nNo caches instance.\n");
- }
- fprintf(file, "\nPipeline=FrameBuilder\n");
- fflush(file);
+ args->thread->dumpGraphicsMemory(args->fd);
return nullptr;
}
diff --git a/libs/hwui/renderthread/RenderThread.cpp b/libs/hwui/renderthread/RenderThread.cpp
index 055458397023..13af2c4d15e8 100644
--- a/libs/hwui/renderthread/RenderThread.cpp
+++ b/libs/hwui/renderthread/RenderThread.cpp
@@ -202,6 +202,45 @@ void RenderThread::initThreadLocals() {
mRenderState = new RenderState(*this);
mJankTracker = new JankTracker(mDisplayInfo);
mVkManager = new VulkanManager(*this);
+ mCacheManager = new CacheManager(mDisplayInfo);
+}
+
+void RenderThread::dumpGraphicsMemory(int fd) {
+ jankTracker().dump(fd);
+
+ String8 cachesOutput;
+ String8 pipeline;
+ auto renderType = Properties::getRenderPipelineType();
+ switch (renderType) {
+ case RenderPipelineType::OpenGL: {
+ if (Caches::hasInstance()) {
+ cachesOutput.appendFormat("Caches:\n");
+ Caches::getInstance().dumpMemoryUsage(cachesOutput);
+ } else {
+ cachesOutput.appendFormat("No caches instance.");
+ }
+ pipeline.appendFormat("FrameBuilder");
+ break;
+ }
+ case RenderPipelineType::SkiaGL: {
+ mCacheManager->dumpMemoryUsage(cachesOutput, mRenderState);
+ pipeline.appendFormat("Skia (OpenGL)");
+ break;
+ }
+ case RenderPipelineType::SkiaVulkan: {
+ mCacheManager->dumpMemoryUsage(cachesOutput, mRenderState);
+ pipeline.appendFormat("Skia (Vulkan)");
+ break;
+ }
+ default:
+ LOG_ALWAYS_FATAL("canvas context type %d not supported", (int32_t) renderType);
+ break;
+ }
+
+ FILE *file = fdopen(fd, "a");
+ fprintf(file, "\n%s\n", cachesOutput.string());
+ fprintf(file, "\nPipeline=%s\n", pipeline.string());
+ fflush(file);
}
Readback& RenderThread::readback() {
@@ -228,6 +267,14 @@ Readback& RenderThread::readback() {
return *mReadback;
}
+void RenderThread::setGrContext(GrContext* context) {
+ mCacheManager->reset(context);
+ if (mGrContext.get()) {
+ mGrContext->releaseResourcesAndAbandonContext();
+ }
+ mGrContext.reset(context);
+}
+
int RenderThread::displayEventReceiverCallback(int fd, int events, void* data) {
if (events & (Looper::EVENT_ERROR | Looper::EVENT_HANGUP)) {
ALOGE("Display event receiver pipe was closed or an error occurred. "
diff --git a/libs/hwui/renderthread/RenderThread.h b/libs/hwui/renderthread/RenderThread.h
index 4b5601c5abc4..d9842572d7cd 100644
--- a/libs/hwui/renderthread/RenderThread.h
+++ b/libs/hwui/renderthread/RenderThread.h
@@ -20,6 +20,7 @@
#include "RenderTask.h"
#include "../JankTracker.h"
+#include "CacheManager.h"
#include "TimeLord.h"
#include <GrContext.h>
@@ -102,11 +103,13 @@ public:
const DisplayInfo& mainDisplayInfo() { return mDisplayInfo; }
GrContext* getGrContext() const { return mGrContext.get(); }
- void setGrContext(GrContext* cxt) { mGrContext.reset(cxt); }
+ void setGrContext(GrContext* cxt);
+ CacheManager& cacheManager() { return *mCacheManager; }
VulkanManager& vulkanManager() { return *mVkManager; }
sk_sp<Bitmap> allocateHardwareBitmap(SkBitmap& skBitmap);
+ void dumpGraphicsMemory(int fd);
protected:
virtual bool threadLoop() override;
@@ -161,6 +164,7 @@ private:
Readback* mReadback = nullptr;
sk_sp<GrContext> mGrContext;
+ CacheManager* mCacheManager;
VulkanManager* mVkManager;
};
diff --git a/libs/hwui/tests/unit/CacheManagerTests.cpp b/libs/hwui/tests/unit/CacheManagerTests.cpp
new file mode 100644
index 000000000000..6115162c8f81
--- /dev/null
+++ b/libs/hwui/tests/unit/CacheManagerTests.cpp
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gtest/gtest.h>
+
+#include "renderthread/CacheManager.h"
+#include "renderthread/EglManager.h"
+#include "tests/common/TestUtils.h"
+
+using namespace android;
+using namespace android::uirenderer;
+using namespace android::uirenderer::renderthread;
+
+static size_t getCacheUsage(GrContext* grContext) {
+ size_t cacheUsage;
+ grContext->getResourceCacheUsage(nullptr, &cacheUsage);
+ return cacheUsage;
+}
+
+RENDERTHREAD_SKIA_PIPELINE_TEST(CacheManager, trimMemory) {
+ DisplayInfo displayInfo = renderThread.mainDisplayInfo();
+ GrContext* grContext = renderThread.getGrContext();
+ ASSERT_TRUE(grContext != nullptr);
+
+ // create pairs of offscreen render targets and images until we exceed the backgroundCacheSizeLimit
+ std::vector<sk_sp<SkSurface>> surfaces;
+
+ while (getCacheUsage(grContext) <= renderThread.cacheManager().getBackgroundCacheSize()) {
+ SkImageInfo info = SkImageInfo::MakeA8(displayInfo.w, displayInfo.h);
+ sk_sp<SkSurface> surface = SkSurface::MakeRenderTarget(grContext, SkBudgeted::kYes, info);
+ surface->getCanvas()->drawColor(SK_AlphaTRANSPARENT);
+
+ grContext->flush();
+
+ surfaces.push_back(surface);
+ }
+
+ ASSERT_TRUE(1 < surfaces.size());
+
+ // attempt to trim all memory while we still hold strong refs
+ renderThread.cacheManager().trimMemory(CacheManager::TrimMemoryMode::Complete);
+ ASSERT_TRUE(0 == grContext->getResourceCachePurgeableBytes());
+
+ // free the surfaces
+ for (size_t i = 0; i < surfaces.size(); i++) {
+ ASSERT_TRUE(surfaces[i]->unique());
+ surfaces[i].reset();
+ }
+
+ // verify that we have enough purgeable bytes
+ const size_t purgeableBytes = grContext->getResourceCachePurgeableBytes();
+ ASSERT_TRUE(renderThread.cacheManager().getBackgroundCacheSize() < purgeableBytes);
+
+ // UI hidden and make sure only some got purged
+ renderThread.cacheManager().trimMemory(CacheManager::TrimMemoryMode::UiHidden);
+ ASSERT_TRUE(0 < grContext->getResourceCachePurgeableBytes());
+ ASSERT_TRUE(renderThread.cacheManager().getBackgroundCacheSize() > getCacheUsage(grContext));
+
+ // complete and make sure all get purged
+ renderThread.cacheManager().trimMemory(CacheManager::TrimMemoryMode::Complete);
+ ASSERT_TRUE(0 == grContext->getResourceCachePurgeableBytes());
+}
diff --git a/location/java/android/location/CountryDetector.java b/location/java/android/location/CountryDetector.java
index ce3c56f73c01..ec6dfb713b10 100644
--- a/location/java/android/location/CountryDetector.java
+++ b/location/java/android/location/CountryDetector.java
@@ -18,6 +18,8 @@ package android.location;
import java.util.HashMap;
+import android.annotation.SystemService;
+import android.content.Context;
import android.os.Handler;
import android.os.Looper;
import android.os.RemoteException;
@@ -40,13 +42,10 @@ import android.util.Log;
* To be notified of the future country change, use the
* {@link #addCountryListener}
* <p>
- * <p>
- * You do not instantiate this class directly; instead, retrieve it through
- * {@link android.content.Context#getSystemService
- * Context.getSystemService(Context.COUNTRY_DETECTOR)}.
*
* @hide
*/
+@SystemService(Context.COUNTRY_DETECTOR)
public class CountryDetector {
/**
diff --git a/location/java/android/location/LocationManager.java b/location/java/android/location/LocationManager.java
index f9385c6d3b7f..26ac2a23d8c5 100644
--- a/location/java/android/location/LocationManager.java
+++ b/location/java/android/location/LocationManager.java
@@ -20,7 +20,9 @@ import com.android.internal.location.ProviderProperties;
import android.Manifest;
import android.annotation.RequiresPermission;
+import android.annotation.SuppressLint;
import android.annotation.SystemApi;
+import android.annotation.SystemService;
import android.annotation.TestApi;
import android.app.PendingIntent;
import android.content.Context;
@@ -47,11 +49,6 @@ import static android.Manifest.permission.ACCESS_FINE_LOCATION;
* {@link Intent} when the device enters the proximity of a given
* geographical location.
*
- * <p>You do not
- * instantiate this class directly; instead, retrieve it through
- * {@link android.content.Context#getSystemService
- * Context.getSystemService(Context.LOCATION_SERVICE)}.
- *
* <p class="note">Unless noted, all Location API methods require
* the {@link android.Manifest.permission#ACCESS_COARSE_LOCATION} or
* {@link android.Manifest.permission#ACCESS_FINE_LOCATION} permissions.
@@ -60,8 +57,8 @@ import static android.Manifest.permission.ACCESS_FINE_LOCATION;
* return location results, but the update rate will be throttled and the exact
* location will be obfuscated to a coarse level of accuracy.
*/
-public class LocationManager
-{
+@SystemService(Context.LOCATION_SERVICE)
+public class LocationManager {
private static final String TAG = "LocationManager";
private final Context mContext;
@@ -831,6 +828,7 @@ public class LocationManager
* @hide
*/
@SystemApi
+ @RequiresPermission(anyOf = {ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION})
public void requestLocationUpdates(LocationRequest request, LocationListener listener,
Looper looper) {
checkListener(listener);
@@ -859,6 +857,7 @@ public class LocationManager
* @hide
*/
@SystemApi
+ @RequiresPermission(anyOf = {ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION})
public void requestLocationUpdates(LocationRequest request, PendingIntent intent) {
checkPendingIntent(intent);
requestLocationUpdates(request, null, null, intent);
@@ -1820,6 +1819,7 @@ public class LocationManager
*/
@Deprecated
@SystemApi
+ @SuppressLint("Doclava125")
public boolean addGpsMeasurementListener(GpsMeasurementsEvent.Listener listener) {
return false;
}
@@ -1857,6 +1857,7 @@ public class LocationManager
*/
@Deprecated
@SystemApi
+ @SuppressLint("Doclava125")
public void removeGpsMeasurementListener(GpsMeasurementsEvent.Listener listener) {
}
@@ -1877,6 +1878,7 @@ public class LocationManager
*/
@Deprecated
@SystemApi
+ @SuppressLint("Doclava125")
public boolean addGpsNavigationMessageListener(GpsNavigationMessageEvent.Listener listener) {
return false;
}
@@ -1891,6 +1893,7 @@ public class LocationManager
*/
@Deprecated
@SystemApi
+ @SuppressLint("Doclava125")
public void removeGpsNavigationMessageListener(GpsNavigationMessageEvent.Listener listener) {
}
diff --git a/lowpan/Android.mk b/lowpan/Android.mk
new file mode 100644
index 000000000000..9e9164f51513
--- /dev/null
+++ b/lowpan/Android.mk
@@ -0,0 +1,31 @@
+#
+# Copyright (C) 2017 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+LOCAL_PATH := $(call my-dir)
+
+ifneq (,$(findstring lowpan/java,$(FRAMEWORKS_BASE_SUBDIRS)))
+include $(CLEAR_VARS)
+LOCAL_MODULE := libandroid_net_lowpan
+LOCAL_MODULE_TAGS := optional
+LOCAL_SHARED_LIBRARIES += libbase
+LOCAL_SHARED_LIBRARIES += libbinder
+LOCAL_SHARED_LIBRARIES += libutils
+LOCAL_AIDL_INCLUDES += frameworks/native/aidl/binder
+LOCAL_AIDL_INCLUDES += frameworks/base/lowpan/java
+LOCAL_AIDL_INCLUDES += frameworks/base/core/java
+LOCAL_SRC_FILES += $(call all-Iaidl-files-under, java/android/net/lowpan)
+include $(BUILD_SHARED_LIBRARY)
+endif
diff --git a/lowpan/java/android/net/lowpan/ILowpanEnergyScanCallback.aidl b/lowpan/java/android/net/lowpan/ILowpanEnergyScanCallback.aidl
new file mode 100644
index 000000000000..f09dbe3d077e
--- /dev/null
+++ b/lowpan/java/android/net/lowpan/ILowpanEnergyScanCallback.aidl
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.lowpan;
+
+/** {@hide} */
+interface ILowpanEnergyScanCallback {
+ oneway void onEnergyScanResult(int channel, int rssi);
+ oneway void onEnergyScanFinished();
+}
diff --git a/lowpan/java/android/net/lowpan/ILowpanInterface.aidl b/lowpan/java/android/net/lowpan/ILowpanInterface.aidl
new file mode 100644
index 000000000000..647fcc1eef3d
--- /dev/null
+++ b/lowpan/java/android/net/lowpan/ILowpanInterface.aidl
@@ -0,0 +1,154 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.lowpan;
+
+import android.net.lowpan.ILowpanInterfaceListener;
+import android.net.lowpan.ILowpanNetScanCallback;
+import android.net.lowpan.ILowpanEnergyScanCallback;
+import android.os.PersistableBundle;
+import android.net.IpPrefix;
+
+/** {@hide} */
+interface ILowpanInterface {
+
+ //////////////////////////////////////////////////////////////////////////
+ // Permission String Constants
+
+ /* These are here for the sake of C++ interface implementations. */
+
+ const String PERM_ACCESS_LOWPAN_STATE = "android.permission.ACCESS_LOWPAN_STATE";
+ const String PERM_CHANGE_LOWPAN_STATE = "android.permission.CHANGE_LOWPAN_STATE";
+ const String PERM_READ_LOWPAN_CREDENTIAL = "android.permission.READ_LOWPAN_CREDENTIAL";
+
+ //////////////////////////////////////////////////////////////////////////
+ // Property Key Constants
+
+ const String KEY_INTERFACE_ENABLED = "android.net.lowpan.property.INTERFACE_ENABLED";
+ const String KEY_INTERFACE_UP = "android.net.lowpan.property.INTERFACE_UP";
+ const String KEY_INTERFACE_COMMISSIONED = "android.net.lowpan.property.INTERFACE_COMMISSIONED";
+ const String KEY_INTERFACE_CONNECTED = "android.net.lowpan.property.INTERFACE_CONNECTED";
+ const String KEY_INTERFACE_STATE = "android.net.lowpan.property.INTERFACE_STATE";
+
+ const String KEY_NETWORK_NAME = "android.net.lowpan.property.NETWORK_NAME";
+ const String KEY_NETWORK_TYPE = "android.net.lowpan.property.NETWORK_TYPE";
+ const String KEY_NETWORK_PANID = "android.net.lowpan.property.NETWORK_PANID";
+ const String KEY_NETWORK_XPANID = "android.net.lowpan.property.NETWORK_XPANID";
+ const String KEY_NETWORK_ROLE = "android.net.lowpan.property.NETWORK_ROLE";
+ const String KEY_NETWORK_MASTER_KEY = "android.net.lowpan.property.NETWORK_MASTER_KEY";
+ const String KEY_NETWORK_MASTER_KEY_INDEX
+ = "android.net.lowpan.property.NETWORK_MASTER_KEY_INDEX";
+
+ const String KEY_SUPPORTED_CHANNELS = "android.net.lowpan.property.SUPPORTED_CHANNELS";
+ const String KEY_CHANNEL = "android.net.lowpan.property.CHANNEL";
+ const String KEY_CHANNEL_MASK = "android.net.lowpan.property.CHANNEL_MASK";
+ const String KEY_MAX_TX_POWER = "android.net.lowpan.property.MAX_TX_POWER";
+ const String KEY_RSSI = "android.net.lowpan.property.RSSI";
+ const String KEY_LQI = "android.net.lowpan.property.LQI";
+
+ const String KEY_LINK_ADDRESS_ARRAY = "android.net.lowpan.property.LINK_ADDRESS_ARRAY";
+ const String KEY_ROUTE_INFO_ARRAY = "android.net.lowpan.property.ROUTE_INFO_ARRAY";
+
+ const String KEY_BEACON_ADDRESS = "android.net.lowpan.property.BEACON_ORIGIN_ADDRESS";
+ const String KEY_BEACON_CAN_ASSIST = "android.net.lowpan.property.BEACON_CAN_ASSIST";
+
+ const String DRIVER_VERSION = "android.net.lowpan.property.DRIVER_VERSION";
+ const String NCP_VERSION = "android.net.lowpan.property.NCP_VERSION";
+
+ /** @hide */
+ const String KEY_EXTENDED_ADDRESS = "android.net.lowpan.property.EXTENDED_ADDRESS";
+
+ /** @hide */
+ const String KEY_MAC_ADDRESS = "android.net.lowpan.property.MAC_ADDRESS";
+
+ //////////////////////////////////////////////////////////////////////////
+ // Interface States
+
+ const String STATE_OFFLINE = "offline";
+ const String STATE_COMMISSIONING = "commissioning";
+ const String STATE_ATTACHING = "attaching";
+ const String STATE_ATTACHED = "attached";
+ const String STATE_FAULT = "fault";
+
+ //////////////////////////////////////////////////////////////////////////
+ // Device Roles
+
+ const String ROLE_END_DEVICE = "end-device";
+ const String ROLE_ROUTER = "router";
+ const String ROLE_SLEEPY_END_DEVICE = "sleepy-end-device";
+ const String ROLE_SLEEPY_ROUTER = "sleepy-router";
+ const String ROLE_UNKNOWN = "unknown";
+
+ //////////////////////////////////////////////////////////////////////////
+ // Service-Specific Error Code Constants
+
+ const int ERROR_UNSPECIFIED = 1;
+ const int ERROR_INVALID_ARGUMENT = 2;
+ const int ERROR_DISABLED = 3;
+ const int ERROR_WRONG_STATE = 4;
+ const int ERROR_INVALID_TYPE = 5;
+ const int ERROR_INVALID_VALUE = 6;
+ const int ERROR_TIMEOUT = 7;
+ const int ERROR_IO_FAILURE = 8;
+ const int ERROR_BUSY = 9;
+ const int ERROR_ALREADY = 10;
+ const int ERROR_CANCELED = 11;
+ const int ERROR_CREDENTIAL_NEEDED = 12;
+ const int ERROR_FEATURE_NOT_SUPPORTED = 14;
+ const int ERROR_PROPERTY_NOT_FOUND = 16;
+ const int ERROR_JOIN_FAILED_UNKNOWN = 18;
+ const int ERROR_JOIN_FAILED_AT_SCAN = 19;
+ const int ERROR_JOIN_FAILED_AT_AUTH = 20;
+ const int ERROR_FORM_FAILED_AT_SCAN = 21;
+ const int ERROR_NCP_PROBLEM = 27;
+ const int ERROR_PERMISSION_DENIED = 28;
+
+ //////////////////////////////////////////////////////////////////////////
+ // Methods
+
+ @utf8InCpp String getName();
+
+ void join(in Map parameters);
+ void form(in Map parameters);
+ void leave();
+ void reset();
+
+ void beginLowPower();
+ void pollForData();
+
+ oneway void onHostWake();
+
+ @utf8InCpp String[] getPropertyKeys();
+ Map getProperties(in @utf8InCpp String[] keys);
+ void setProperties(in Map properties);
+
+ void addListener(ILowpanInterfaceListener listener);
+ oneway void removeListener(ILowpanInterfaceListener listener);
+
+ void startNetScan(in Map properties, ILowpanNetScanCallback listener);
+ oneway void stopNetScan();
+
+ void startEnergyScan(in Map properties, ILowpanEnergyScanCallback listener);
+ oneway void stopEnergyScan();
+
+ void addOnMeshPrefix(in IpPrefix prefix, int flags);
+ oneway void removeOnMeshPrefix(in IpPrefix prefix);
+
+ void addExternalRoute(in IpPrefix prefix, int flags);
+ oneway void removeExternalRoute(in IpPrefix prefix);
+
+ @utf8InCpp String getPropertyAsString(@utf8InCpp String key);
+}
diff --git a/lowpan/java/android/net/lowpan/ILowpanInterfaceListener.aidl b/lowpan/java/android/net/lowpan/ILowpanInterfaceListener.aidl
new file mode 100644
index 000000000000..c99d732d4eba
--- /dev/null
+++ b/lowpan/java/android/net/lowpan/ILowpanInterfaceListener.aidl
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.lowpan;
+
+/** {@hide} */
+interface ILowpanInterfaceListener {
+ oneway void onPropertiesChanged(in Map properties);
+}
diff --git a/lowpan/java/android/net/lowpan/ILowpanManager.aidl b/lowpan/java/android/net/lowpan/ILowpanManager.aidl
new file mode 100644
index 000000000000..5a8d7dce7c6f
--- /dev/null
+++ b/lowpan/java/android/net/lowpan/ILowpanManager.aidl
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.lowpan;
+import android.net.lowpan.ILowpanInterface;
+import android.net.lowpan.ILowpanManagerListener;
+
+/** {@hide} */
+interface ILowpanManager {
+
+ const String LOWPAN_SERVICE_NAME = "lowpan";
+
+ ILowpanInterface getInterface(@utf8InCpp String name);
+
+ @utf8InCpp String[] getInterfaceList();
+
+ void addListener(ILowpanManagerListener listener);
+ void removeListener(ILowpanManagerListener listener);
+
+ void addInterface(ILowpanInterface lowpan_interface);
+ void removeInterface(ILowpanInterface lowpan_interface);
+}
diff --git a/lowpan/java/android/net/lowpan/ILowpanManagerListener.aidl b/lowpan/java/android/net/lowpan/ILowpanManagerListener.aidl
new file mode 100644
index 000000000000..d4846f6740b9
--- /dev/null
+++ b/lowpan/java/android/net/lowpan/ILowpanManagerListener.aidl
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.lowpan;
+
+import android.net.lowpan.ILowpanInterface;
+
+/** {@hide} */
+interface ILowpanManagerListener {
+ oneway void onInterfaceAdded(ILowpanInterface lowpanInterface);
+ oneway void onInterfaceRemoved(ILowpanInterface lowpanInterface);
+}
diff --git a/lowpan/java/android/net/lowpan/ILowpanNetScanCallback.aidl b/lowpan/java/android/net/lowpan/ILowpanNetScanCallback.aidl
new file mode 100644
index 000000000000..c20a6f8110c8
--- /dev/null
+++ b/lowpan/java/android/net/lowpan/ILowpanNetScanCallback.aidl
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.lowpan;
+
+/** {@hide} */
+interface ILowpanNetScanCallback {
+ oneway void onNetScanBeacon(in Map parameters);
+ oneway void onNetScanFinished();
+}
diff --git a/lowpan/java/android/net/lowpan/LowpanBeaconInfo.java b/lowpan/java/android/net/lowpan/LowpanBeaconInfo.java
new file mode 100644
index 000000000000..b344527e4be5
--- /dev/null
+++ b/lowpan/java/android/net/lowpan/LowpanBeaconInfo.java
@@ -0,0 +1,150 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.lowpan;
+
+import com.android.internal.util.HexDump;
+import java.util.Collection;
+import java.util.Map;
+import java.util.TreeSet;
+
+/**
+ * Describes a LoWPAN Beacon
+ *
+ * @hide
+ */
+//@SystemApi
+public class LowpanBeaconInfo extends LowpanIdentity {
+
+ private int mRssi = UNKNOWN;
+ private int mLqi = UNKNOWN;
+ private byte[] mBeaconAddress = null;
+ private final TreeSet<Integer> mFlags = new TreeSet<>();
+
+ public static final int FLAG_CAN_ASSIST = 1;
+
+ static class Builder extends LowpanIdentity.Builder {
+ private final LowpanBeaconInfo identity = new LowpanBeaconInfo();
+
+ public Builder setRssi(int x) {
+ identity.mRssi = x;
+ return this;
+ }
+
+ public Builder setLqi(int x) {
+ identity.mLqi = x;
+ return this;
+ }
+
+ public Builder setBeaconAddress(byte x[]) {
+ identity.mBeaconAddress = x.clone();
+ return this;
+ }
+
+ public Builder setFlag(int x) {
+ identity.mFlags.add(x);
+ return this;
+ }
+
+ public Builder setFlags(Collection<Integer> x) {
+ identity.mFlags.addAll(x);
+ return this;
+ }
+
+ /** @hide */
+ Builder updateFromMap(Map map) {
+ if (map.containsKey(LowpanProperties.KEY_RSSI.getName())) {
+ setRssi(LowpanProperties.KEY_RSSI.getFromMap(map));
+ }
+ if (map.containsKey(LowpanProperties.KEY_LQI.getName())) {
+ setLqi(LowpanProperties.KEY_LQI.getFromMap(map));
+ }
+ if (map.containsKey(LowpanProperties.KEY_BEACON_ADDRESS.getName())) {
+ setBeaconAddress(LowpanProperties.KEY_BEACON_ADDRESS.getFromMap(map));
+ }
+ identity.mFlags.clear();
+ if (map.containsKey(LowpanProperties.KEY_BEACON_CAN_ASSIST.getName())
+ && LowpanProperties.KEY_BEACON_CAN_ASSIST.getFromMap(map).booleanValue()) {
+ setFlag(FLAG_CAN_ASSIST);
+ }
+ super.updateFromMap(map);
+ return this;
+ }
+
+ public LowpanBeaconInfo build() {
+ return identity;
+ }
+ }
+
+ private LowpanBeaconInfo() {}
+
+ public int getRssi() {
+ return mRssi;
+ }
+
+ public int getLqi() {
+ return mLqi;
+ }
+
+ public byte[] getBeaconAddress() {
+ return mBeaconAddress.clone();
+ }
+
+ public Collection<Integer> getFlags() {
+ return mFlags.clone();
+ }
+
+ public boolean isFlagSet(int flag) {
+ return mFlags.contains(flag);
+ }
+
+ @Override
+ void addToMap(Map<String, Object> parameters) {
+ super.addToMap(parameters);
+ }
+
+ @Override
+ public String toString() {
+ StringBuffer sb = new StringBuffer();
+
+ sb.append(super.toString());
+
+ if (mRssi != UNKNOWN) {
+ sb.append(", RSSI: ").append(mRssi);
+ }
+
+ if (mLqi != UNKNOWN) {
+ sb.append(", LQI: ").append(mLqi);
+ }
+
+ if (mBeaconAddress != null) {
+ sb.append(", BeaconAddress: ").append(HexDump.toHexString(mBeaconAddress));
+ }
+
+ for (Integer flag : mFlags) {
+ switch (flag.intValue()) {
+ case FLAG_CAN_ASSIST:
+ sb.append(", CAN_ASSIST");
+ break;
+ default:
+ sb.append(", FLAG_").append(Integer.toHexString(flag));
+ break;
+ }
+ }
+
+ return sb.toString();
+ }
+}
diff --git a/lowpan/java/android/net/lowpan/LowpanChannelInfo.java b/lowpan/java/android/net/lowpan/LowpanChannelInfo.java
new file mode 100644
index 000000000000..50afe6d3a4c0
--- /dev/null
+++ b/lowpan/java/android/net/lowpan/LowpanChannelInfo.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.lowpan;
+
+
+/** Provides detailed information about a given channel. */
+//@SystemApi
+public class LowpanChannelInfo {
+
+ public static final int UNKNOWN_POWER = Integer.MAX_VALUE;
+
+ //////////////////////////////////////////////////////////////////////////
+ // Instance Variables
+
+ private String mName = null;
+ private int mIndex = 0;
+ private boolean mIsMaskedByRegulatoryDomain = false;
+ private float mSpectrumCenterFrequency = 0.0f;
+ private float mSpectrumBandwidth = 0.0f;
+ private int mMaxTransmitPower = UNKNOWN_POWER;
+
+ //////////////////////////////////////////////////////////////////////////
+ // Public Getters and Setters
+
+ public String getName() {
+ return mName;
+ }
+
+ public int getIndex() {
+ return mIndex;
+ }
+
+ public int getMaxTransmitPower() {
+ return mMaxTransmitPower;
+ }
+
+ public boolean isMaskedByRegulatoryDomain() {
+ return mIsMaskedByRegulatoryDomain;
+ }
+
+ public float getSpectrumCenterFrequency() {
+ return mSpectrumCenterFrequency;
+ }
+
+ public float getSpectrumBandwidth() {
+ return mSpectrumBandwidth;
+ }
+
+ @Override
+ public String toString() {
+ StringBuffer sb = new StringBuffer();
+
+ sb.append("Channel ").append(mIndex);
+
+ if (mName != null) {
+ sb.append(" (").append(mName).append(")");
+ }
+
+ if (mSpectrumCenterFrequency > 0.0f) {
+ sb.append(", SpectrumCenterFrequency: ").append(mSpectrumCenterFrequency).append("Hz");
+ }
+
+ if (mSpectrumBandwidth > 0.0f) {
+ sb.append(", SpectrumBandwidth: ").append(mSpectrumBandwidth).append("Hz");
+ }
+
+ if (mMaxTransmitPower != UNKNOWN_POWER) {
+ sb.append(", MaxTransmitPower: ").append(mMaxTransmitPower);
+ }
+
+ return sb.toString();
+ }
+}
diff --git a/lowpan/java/android/net/lowpan/LowpanCommissioningSession.java b/lowpan/java/android/net/lowpan/LowpanCommissioningSession.java
new file mode 100644
index 000000000000..9cad00c3415a
--- /dev/null
+++ b/lowpan/java/android/net/lowpan/LowpanCommissioningSession.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.lowpan;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.net.Network;
+import android.os.Handler;
+import java.net.InetSocketAddress;
+
+/**
+ * Commissioning Session.
+ *
+ * <p>This class enables a device to learn the credential needed to join a network using a technique
+ * called "in-band commissioning".
+ *
+ * @hide
+ */
+//@SystemApi
+public abstract class LowpanCommissioningSession {
+ public LowpanCommissioningSession() {}
+
+ /**
+ * Callback base class for {@link LowpanCommissioningSession}
+ *
+ * @hide
+ */
+ //@SystemApi
+ public class Callback {
+ public void onReceiveFromCommissioner(@NonNull byte[] packet) {};
+
+ public void onClosed() {};
+ }
+
+ /** TODO: doc */
+ @NonNull
+ public abstract LowpanBeaconInfo getBeaconInfo();
+
+ /** TODO: doc */
+ public abstract void sendToCommissioner(@NonNull byte[] packet);
+
+ /** TODO: doc */
+ public abstract void setCallback(@Nullable Callback cb, @Nullable Handler handler);
+
+ /** TODO: doc */
+ public abstract void close();
+
+ /**
+ * This method is largely for Nest Weave, as an alternative to {@link #sendToCommissioner()}
+ * and @{link Callback#onReceiveFromCommissioner()}.
+ *
+ * <p>When used with the Network instance obtained from getNetwork(), the caller can use the
+ * given InetSocketAddress to communicate with the commissioner using a UDP (or, under certain
+ * circumstances, TCP) socket.
+ */
+ public abstract @Nullable InetSocketAddress getInetSocketAddress();
+
+ public abstract @Nullable Network getNetwork();
+}
diff --git a/lowpan/java/android/net/lowpan/LowpanCredential.java b/lowpan/java/android/net/lowpan/LowpanCredential.java
new file mode 100644
index 000000000000..dea4d7888884
--- /dev/null
+++ b/lowpan/java/android/net/lowpan/LowpanCredential.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.lowpan;
+
+
+import java.util.Map;
+
+/**
+ * Describes a credential for a LoWPAN network.
+ *
+ * @hide
+ */
+//@SystemApi
+public class LowpanCredential {
+
+ public static final int UNSPECIFIED_KEY_INDEX = 0;
+
+ private byte[] mMasterKey = null;
+ private int mMasterKeyIndex = UNSPECIFIED_KEY_INDEX;
+
+ LowpanCredential() {}
+
+ private LowpanCredential(byte[] masterKey, int keyIndex) {
+ setMasterKey(masterKey, keyIndex);
+ }
+
+ private LowpanCredential(byte[] masterKey) {
+ setMasterKey(masterKey);
+ }
+
+ public static LowpanCredential createMasterKey(byte[] masterKey) {
+ return new LowpanCredential(masterKey);
+ }
+
+ public static LowpanCredential createMasterKey(byte[] masterKey, int keyIndex) {
+ return new LowpanCredential(masterKey, keyIndex);
+ }
+
+ public void setMasterKey(byte[] masterKey) {
+ if (masterKey != null) {
+ masterKey = masterKey.clone();
+ }
+ mMasterKey = masterKey;
+ }
+
+ public void setMasterKeyIndex(int keyIndex) {
+ mMasterKeyIndex = keyIndex;
+ }
+
+ public void setMasterKey(byte[] masterKey, int keyIndex) {
+ setMasterKey(masterKey);
+ setMasterKeyIndex(keyIndex);
+ }
+
+ public byte[] getMasterKey() {
+ if (mMasterKey != null) {
+ return mMasterKey.clone();
+ }
+ return null;
+ }
+
+ public int getMasterKeyIndex() {
+ return mMasterKeyIndex;
+ }
+
+ public boolean isMasterKey() {
+ return mMasterKey != null;
+ }
+
+ void addToMap(Map<String, Object> parameters) throws LowpanException {
+ if (isMasterKey()) {
+ LowpanProperties.KEY_NETWORK_MASTER_KEY.putInMap(parameters, getMasterKey());
+ LowpanProperties.KEY_NETWORK_MASTER_KEY_INDEX.putInMap(
+ parameters, getMasterKeyIndex());
+ } else {
+ throw new LowpanException("Unsupported Network Credential");
+ }
+ }
+}
diff --git a/lowpan/java/android/net/lowpan/LowpanEnergyScanResult.java b/lowpan/java/android/net/lowpan/LowpanEnergyScanResult.java
new file mode 100644
index 000000000000..c680687d0e09
--- /dev/null
+++ b/lowpan/java/android/net/lowpan/LowpanEnergyScanResult.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.lowpan;
+
+
+/**
+ * Describes the result from one channel of an energy scan.
+ *
+ * @hide
+ */
+//@SystemApi
+public class LowpanEnergyScanResult {
+ public static final int UNKNOWN = Integer.MAX_VALUE;
+
+ private int mChannel = UNKNOWN;
+ private int mMaxRssi = UNKNOWN;
+
+ public LowpanEnergyScanResult() {}
+
+ public int getChannel() {
+ return mChannel;
+ }
+
+ public int getMaxRssi() {
+ return mMaxRssi;
+ }
+
+ public void setChannel(int x) {
+ mChannel = x;
+ }
+
+ public void setMaxRssi(int x) {
+ mMaxRssi = x;
+ }
+
+ @Override
+ public String toString() {
+ return "LowpanEnergyScanResult(channel: " + mChannel + ", maxRssi:" + mMaxRssi + ")";
+ }
+}
diff --git a/lowpan/java/android/net/lowpan/LowpanException.java b/lowpan/java/android/net/lowpan/LowpanException.java
new file mode 100644
index 000000000000..8ff37f926899
--- /dev/null
+++ b/lowpan/java/android/net/lowpan/LowpanException.java
@@ -0,0 +1,290 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.lowpan;
+
+import android.os.DeadObjectException;
+import android.os.RemoteException;
+import android.os.ServiceSpecificException;
+import android.util.AndroidException;
+
+/**
+ * <code>LowpanException</code> is thrown if an action to a LoWPAN interface could not be performed
+ * or a LoWPAN interface property could not be fetched or changed.
+ *
+ * @see LowpanInterface
+ * @hide
+ */
+//@SystemApi
+public class LowpanException extends AndroidException {
+ // Make the eclipse warning about serializable exceptions go away
+ private static final long serialVersionUID = 0x31863cbe562b0e11l; // randomly generated
+
+ public static final int LOWPAN_ERROR = 1;
+ public static final int LOWPAN_CREDENTIAL_NEEDED = 2;
+ public static final int LOWPAN_DEAD = 3;
+ public static final int LOWPAN_DISABLED = 4;
+ public static final int LOWPAN_WRONG_STATE = 5;
+ public static final int LOWPAN_BUSY = 7;
+ public static final int LOWPAN_NCP_PROBLEM = 8;
+ public static final int LOWPAN_ALREADY = 9;
+ public static final int LOWPAN_CANCELED = 10;
+ public static final int LOWPAN_FEATURE_NOT_SUPPORTED = 12;
+ public static final int LOWPAN_PROPERTY_NOT_FOUND = 13;
+ public static final int LOWPAN_JOIN_FAILED_UNKNOWN = 14;
+ public static final int LOWPAN_JOIN_FAILED_AT_SCAN = 15;
+ public static final int LOWPAN_JOIN_FAILED_AT_AUTH = 16;
+ public static final int LOWPAN_FORM_FAILED_AT_SCAN = 17;
+
+ /**
+ * Convert ServiceSpecificExceptions and Binder RemoteExceptions from LoWPAN binder interfaces
+ * into the correct public exceptions.
+ *
+ * @hide
+ */
+ public static void throwAsPublicException(Throwable t) throws LowpanException {
+ if (t instanceof ServiceSpecificException) {
+ ServiceSpecificException e = (ServiceSpecificException) t;
+ int reason;
+ switch (e.errorCode) {
+ case ILowpanInterface.ERROR_INVALID_ARGUMENT:
+ case ILowpanInterface.ERROR_INVALID_TYPE:
+ case ILowpanInterface.ERROR_INVALID_VALUE:
+ throw new IllegalArgumentException(e.getMessage(), e);
+
+ case ILowpanInterface.ERROR_PERMISSION_DENIED:
+ throw new SecurityException(e.getMessage(), e);
+
+ case ILowpanInterface.ERROR_DISABLED:
+ reason = LowpanException.LOWPAN_DISABLED;
+ break;
+
+ case ILowpanInterface.ERROR_WRONG_STATE:
+ reason = LowpanException.LOWPAN_WRONG_STATE;
+ break;
+
+ case ILowpanInterface.ERROR_BUSY:
+ reason = LowpanException.LOWPAN_BUSY;
+ break;
+
+ case ILowpanInterface.ERROR_ALREADY:
+ reason = LowpanException.LOWPAN_ALREADY;
+ break;
+
+ case ILowpanInterface.ERROR_CANCELED:
+ reason = LowpanException.LOWPAN_CANCELED;
+ break;
+
+ case ILowpanInterface.ERROR_CREDENTIAL_NEEDED:
+ reason = LowpanException.LOWPAN_CREDENTIAL_NEEDED;
+ break;
+
+ case ILowpanInterface.ERROR_FEATURE_NOT_SUPPORTED:
+ reason = LowpanException.LOWPAN_FEATURE_NOT_SUPPORTED;
+ break;
+
+ case ILowpanInterface.ERROR_PROPERTY_NOT_FOUND:
+ reason = LowpanException.LOWPAN_PROPERTY_NOT_FOUND;
+ break;
+
+ case ILowpanInterface.ERROR_JOIN_FAILED_UNKNOWN:
+ reason = LowpanException.LOWPAN_JOIN_FAILED_UNKNOWN;
+ break;
+
+ case ILowpanInterface.ERROR_JOIN_FAILED_AT_SCAN:
+ reason = LowpanException.LOWPAN_JOIN_FAILED_AT_SCAN;
+ break;
+
+ case ILowpanInterface.ERROR_JOIN_FAILED_AT_AUTH:
+ reason = LowpanException.LOWPAN_JOIN_FAILED_AT_AUTH;
+ break;
+
+ case ILowpanInterface.ERROR_FORM_FAILED_AT_SCAN:
+ reason = LowpanException.LOWPAN_FORM_FAILED_AT_SCAN;
+ break;
+
+ case ILowpanInterface.ERROR_TIMEOUT:
+ case ILowpanInterface.ERROR_NCP_PROBLEM:
+ reason = LowpanException.LOWPAN_NCP_PROBLEM;
+ break;
+ case ILowpanInterface.ERROR_UNSPECIFIED:
+ default:
+ reason = LOWPAN_ERROR;
+ break;
+ }
+ throw new LowpanException(reason, e.getMessage(), e);
+ } else if (t instanceof DeadObjectException) {
+ throw new LowpanException(LOWPAN_DEAD, t);
+ } else if (t instanceof RemoteException) {
+ throw new UnsupportedOperationException(
+ "An unknown RemoteException was thrown" + " which should never happen.", t);
+ } else if (t instanceof RuntimeException) {
+ RuntimeException e = (RuntimeException) t;
+ throw e;
+ }
+ }
+
+ private final int mReason;
+
+ public final int getReason() {
+ return mReason;
+ }
+
+ public LowpanException(int problem) {
+ super(getDefaultMessage(problem));
+ mReason = problem;
+ }
+
+ public LowpanException(String message) {
+ super(getCombinedMessage(LOWPAN_ERROR, message));
+ mReason = LOWPAN_ERROR;
+ }
+
+ public LowpanException(int problem, String message, Throwable cause) {
+ super(getCombinedMessage(problem, message), cause);
+ mReason = problem;
+ }
+
+ public LowpanException(int problem, Throwable cause) {
+ super(getDefaultMessage(problem), cause);
+ mReason = problem;
+ }
+
+ /** @hide */
+ public static String getDefaultMessage(int problem) {
+ String problemString;
+
+ // TODO: Does this need localization?
+
+ switch (problem) {
+ case LOWPAN_DEAD:
+ problemString = "LoWPAN interface is no longer alive";
+ break;
+ case LOWPAN_DISABLED:
+ problemString = "LoWPAN interface is disabled";
+ break;
+ case LOWPAN_WRONG_STATE:
+ problemString = "LoWPAN interface in wrong state to perfom requested action";
+ break;
+ case LOWPAN_BUSY:
+ problemString =
+ "LoWPAN interface was unable to perform the requestion action because it was busy";
+ break;
+ case LOWPAN_NCP_PROBLEM:
+ problemString =
+ "The Network Co-Processor associated with this interface has experienced a problem";
+ break;
+ case LOWPAN_ALREADY:
+ problemString = "The LoWPAN interface is already in the given state";
+ break;
+ case LOWPAN_CANCELED:
+ problemString = "This operation was canceled";
+ break;
+ case LOWPAN_CREDENTIAL_NEEDED:
+ problemString = "Additional credentials are required to complete this operation";
+ break;
+ case LOWPAN_FEATURE_NOT_SUPPORTED:
+ problemString =
+ "A dependent feature required to perform the given action is not currently supported";
+ break;
+ case LOWPAN_PROPERTY_NOT_FOUND:
+ problemString = "The given property was not found";
+ break;
+ case LOWPAN_JOIN_FAILED_UNKNOWN:
+ problemString = "The join operation failed for an unspecified reason";
+ break;
+ case LOWPAN_JOIN_FAILED_AT_SCAN:
+ problemString =
+ "The join operation failed because it could not communicate with any peers";
+ break;
+ case LOWPAN_JOIN_FAILED_AT_AUTH:
+ problemString =
+ "The join operation failed because the credentials were not accepted by any peers";
+ break;
+ case LOWPAN_FORM_FAILED_AT_SCAN:
+ problemString = "Network form failed";
+ break;
+ case LOWPAN_ERROR:
+ default:
+ problemString = "The requested LoWPAN operation failed";
+ break;
+ }
+
+ return problemString;
+ }
+
+ private static String getCombinedMessage(int problem, String message) {
+ String problemString = getProblemString(problem);
+ return String.format("%s (%d): %s", problemString, problem, message);
+ }
+
+ private static String getProblemString(int problem) {
+ String problemString;
+
+ switch (problem) {
+ case LOWPAN_ERROR:
+ problemString = "LOWPAN_ERROR";
+ break;
+ case LOWPAN_DEAD:
+ problemString = "LOWPAN_DEAD";
+ break;
+ case LOWPAN_DISABLED:
+ problemString = "LOWPAN_DISABLED";
+ break;
+ case LOWPAN_WRONG_STATE:
+ problemString = "LOWPAN_WRONG_STATE";
+ break;
+ case LOWPAN_BUSY:
+ problemString = "LOWPAN_BUSY";
+ break;
+ case LOWPAN_NCP_PROBLEM:
+ problemString = "LOWPAN_NCP_PROBLEM";
+ break;
+ case LOWPAN_ALREADY:
+ problemString = "LOWPAN_ALREADY";
+ break;
+ case LOWPAN_CANCELED:
+ problemString = "LOWPAN_CANCELED";
+ break;
+ case LOWPAN_CREDENTIAL_NEEDED:
+ problemString = "LOWPAN_CREDENTIAL_NEEDED";
+ break;
+ case LOWPAN_FEATURE_NOT_SUPPORTED:
+ problemString = "LOWPAN_FEATURE_NOT_SUPPORTED";
+ break;
+ case LOWPAN_PROPERTY_NOT_FOUND:
+ problemString = "LOWPAN_PROPERTY_NOT_FOUND";
+ break;
+ case LOWPAN_JOIN_FAILED_UNKNOWN:
+ problemString = "LOWPAN_JOIN_FAILED_UNKNOWN";
+ break;
+ case LOWPAN_JOIN_FAILED_AT_SCAN:
+ problemString = "LOWPAN_JOIN_FAILED_AT_SCAN";
+ break;
+ case LOWPAN_JOIN_FAILED_AT_AUTH:
+ problemString = "LOWPAN_JOIN_FAILED_AT_AUTH";
+ break;
+ case LOWPAN_FORM_FAILED_AT_SCAN:
+ problemString = "LOWPAN_FORM_FAILED_AT_SCAN";
+ break;
+ default:
+ problemString = "LOWPAN_ERROR_CODE_" + problem;
+ break;
+ }
+
+ return problemString;
+ }
+}
diff --git a/lowpan/java/android/net/lowpan/LowpanIdentity.java b/lowpan/java/android/net/lowpan/LowpanIdentity.java
new file mode 100644
index 000000000000..2e7b560fda5e
--- /dev/null
+++ b/lowpan/java/android/net/lowpan/LowpanIdentity.java
@@ -0,0 +1,179 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.lowpan;
+
+import com.android.internal.util.HexDump;
+import java.util.Map;
+
+/**
+ * Describes an instance of a LoWPAN network.
+ *
+ * @hide
+ */
+//@SystemApi
+public class LowpanIdentity {
+
+ //////////////////////////////////////////////////////////////////////////
+ // Constants
+
+ /** @hide */
+ public static final int TYPE_ZIGBEE = 1;
+
+ /** @hide */
+ public static final int TYPE_ZIGBEE_IP = 2;
+
+ /** @hide */
+ public static final int TYPE_THREAD = 3;
+
+ public static final int UNKNOWN = Integer.MAX_VALUE;
+
+ //////////////////////////////////////////////////////////////////////////
+ // Builder
+
+ /** @hide */
+ //@SystemApi
+ public static class Builder {
+ private final LowpanIdentity identity = new LowpanIdentity();
+
+ public Builder setName(String x) {
+ identity.mName = x;
+ return this;
+ }
+
+ public Builder setXpanid(byte x[]) {
+ identity.mXpanid = x.clone();
+ return this;
+ }
+
+ public Builder setPanid(int x) {
+ identity.mPanid = x;
+ return this;
+ }
+
+ /** @hide */
+ public Builder setType(int x) {
+ identity.mType = x;
+ return this;
+ }
+
+ public Builder setChannel(int x) {
+ identity.mChannel = x;
+ return this;
+ }
+
+ /** @hide */
+ Builder updateFromMap(Map map) {
+ if (map.containsKey(ILowpanInterface.KEY_NETWORK_NAME)) {
+ setName(LowpanProperties.KEY_NETWORK_NAME.getFromMap(map));
+ }
+ if (map.containsKey(ILowpanInterface.KEY_NETWORK_PANID)) {
+ setPanid(LowpanProperties.KEY_NETWORK_PANID.getFromMap(map));
+ }
+ if (map.containsKey(ILowpanInterface.KEY_NETWORK_XPANID)) {
+ setXpanid(LowpanProperties.KEY_NETWORK_XPANID.getFromMap(map));
+ }
+ if (map.containsKey(ILowpanInterface.KEY_CHANNEL)) {
+ setChannel(LowpanProperties.KEY_CHANNEL.getFromMap(map));
+ }
+ if (map.containsKey(ILowpanInterface.KEY_NETWORK_TYPE)) {
+ setType(LowpanProperties.KEY_NETWORK_TYPE.getFromMap(map));
+ }
+ return this;
+ }
+
+ public LowpanIdentity build() {
+ return identity;
+ }
+ }
+
+ LowpanIdentity() {}
+
+ //////////////////////////////////////////////////////////////////////////
+ // Instance Variables
+
+ private String mName = null;
+ private byte[] mXpanid = null;
+ private int mType = UNKNOWN;
+ private int mPanid = UNKNOWN;
+ private int mChannel = UNKNOWN;
+
+ //////////////////////////////////////////////////////////////////////////
+ // Public Getters and Setters
+
+ public String getName() {
+ return mName;
+ }
+
+ public byte[] getXpanid() {
+ return mXpanid.clone();
+ }
+
+ public int getPanid() {
+ return mPanid;
+ }
+
+ /** @hide */
+ public int getType() {
+ return mType;
+ }
+
+ public int getChannel() {
+ return mChannel;
+ }
+
+ static void addToMap(Map<String, Object> parameters, LowpanIdentity networkInfo) {
+ if (networkInfo.getName() != null) {
+ LowpanProperties.KEY_NETWORK_NAME.putInMap(parameters, networkInfo.getName());
+ }
+ if (networkInfo.getPanid() != LowpanIdentity.UNKNOWN) {
+ LowpanProperties.KEY_NETWORK_PANID.putInMap(
+ parameters, networkInfo.getPanid());
+ }
+ if (networkInfo.getChannel() != LowpanIdentity.UNKNOWN) {
+ LowpanProperties.KEY_CHANNEL.putInMap(
+ parameters, networkInfo.getChannel());
+ }
+ if (networkInfo.getXpanid() != null) {
+ LowpanProperties.KEY_NETWORK_XPANID.putInMap(parameters, networkInfo.getXpanid());
+ }
+ }
+
+ void addToMap(Map<String, Object> parameters) {
+ addToMap(parameters, this);
+ }
+
+ @Override
+ public String toString() {
+ StringBuffer sb = new StringBuffer();
+
+ sb.append("Name: ").append(mName == null ? "<none>" : mName);
+
+ if (mXpanid != null) {
+ sb.append(", XPANID: ").append(HexDump.toHexString(mXpanid));
+ }
+
+ if (mPanid != UNKNOWN) {
+ sb.append(", PANID: ").append(String.format("0x%04X", mPanid));
+ }
+
+ if (mChannel != UNKNOWN) {
+ sb.append(", Channel: ").append(mChannel);
+ }
+
+ return sb.toString();
+ }
+}
diff --git a/lowpan/java/android/net/lowpan/LowpanInterface.java b/lowpan/java/android/net/lowpan/LowpanInterface.java
new file mode 100644
index 000000000000..cd548190fa17
--- /dev/null
+++ b/lowpan/java/android/net/lowpan/LowpanInterface.java
@@ -0,0 +1,824 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.lowpan;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.net.IpPrefix;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.os.ServiceSpecificException;
+import android.util.Log;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Class for managing a specific Low-power Wireless Personal Area Network (LoWPAN) interface.
+ *
+ * @hide
+ */
+//@SystemApi
+public class LowpanInterface {
+ private static final String TAG = LowpanInterface.class.getSimpleName();
+
+ /** Detached role. The interface is not currently attached to a network. */
+ public static final String ROLE_DETACHED = "detached";
+
+ /** End-device role. End devices do not route traffic for other nodes. */
+ public static final String ROLE_END_DEVICE = "end-device";
+
+ /** Router role. Routers help route traffic around the mesh network. */
+ public static final String ROLE_ROUTER = "router";
+
+ /**
+ * Sleepy End-Device role.
+ *
+ * <p>End devices with this role are nominally asleep, waking up periodically to check in with
+ * their parent to see if there are packets destined for them. Such devices are capable of
+ * extraordinarilly low power consumption, but packet latency can be on the order of dozens of
+ * seconds(depending on how the node is configured).
+ */
+ public static final String ROLE_SLEEPY_END_DEVICE = "sleepy-end-device";
+
+ /**
+ * Sleepy-router role.
+ *
+ * <p>Routers with this role are nominally asleep, waking up periodically to check in with other
+ * routers and their children.
+ */
+ public static final String ROLE_SLEEPY_ROUTER = "sleepy-router";
+
+ /** TODO: doc */
+ public static final String ROLE_LEADER = "leader";
+
+ /** TODO: doc */
+ public static final String ROLE_COORDINATOR = "coordinator";
+
+ /**
+ * Offline state.
+ *
+ * <p>This is the initial state of the LoWPAN interface when the underlying driver starts. In
+ * this state the NCP is idle and not connected to any network.
+ *
+ * <p>This state can be explicitly entered by calling {@link #reset()}, {@link #leave()}, or
+ * <code>setUp(false)</code>, with the later two only working if we were not previously in the
+ * {@link #STATE_FAULT} state.
+ *
+ * @see #getState()
+ * @see #STATE_FAULT
+ */
+ public static final String STATE_OFFLINE = "offline";
+
+ /**
+ * Commissioning state.
+ *
+ * <p>The interface enters this state after a call to {@link #startCommissioningSession()}. This
+ * state may only be entered directly from the {@link #STATE_OFFLINE} state.
+ *
+ * @see #startCommissioningSession()
+ * @see #getState()
+ * @hide
+ */
+ public static final String STATE_COMMISSIONING = "commissioning";
+
+ /**
+ * Attaching state.
+ *
+ * <p>The interface enters this state when it starts the process of trying to find other nodes
+ * so that it can attach to any pre-existing network fragment, or when it is in the process of
+ * calculating the optimal values for unspecified parameters when forming a new network.
+ *
+ * <p>The interface may stay in this state for a prolonged period of time (or may spontaneously
+ * enter this state from {@link #STATE_ATTACHED}) if the underlying network technology is
+ * heirarchical (like ZigBeeIP) or if the device role is that of an "end-device" ({@link
+ * #ROLE_END_DEVICE} or {@link #ROLE_SLEEPY_END_DEVICE}). This is because such roles cannot
+ * create their own network fragments.
+ *
+ * @see #STATE_ATTACHED
+ * @see #getState()
+ */
+ public static final String STATE_ATTACHING = "attaching";
+
+ /**
+ * Attached state.
+ *
+ * <p>The interface enters this state from {@link #STATE_ATTACHING} once it is actively
+ * participating on a network fragment.
+ *
+ * @see #STATE_ATTACHING
+ * @see #getState()
+ */
+ public static final String STATE_ATTACHED = "attached";
+
+ /**
+ * Fault state.
+ *
+ * <p>The interface will enter this state when the driver has detected some sort of problem from
+ * which it was not immediately able to recover.
+ *
+ * <p>This state can be entered spontaneously from any other state. Calling {@link #reset} will
+ * cause the device to return to the {@link #STATE_OFFLINE} state.
+ *
+ * @see #getState
+ * @see #STATE_OFFLINE
+ */
+ public static final String STATE_FAULT = "fault";
+
+ /**
+ * Network type for Thread 1.x networks.
+ *
+ * @see android.net.lowpan.LowpanIdentity#getType
+ * @see #getLowpanIdentity
+ * @hide
+ */
+ public static final String NETWORK_TYPE_THREAD = "org.threadgroup.thread.v1";
+
+ /**
+ * Network type for ZigBeeIP 1.x networks.
+ *
+ * @see android.net.lowpan.LowpanIdentity#getType
+ * @see #getLowpanIdentity
+ * @hide
+ */
+ public static final String NETWORK_TYPE_ZIGBEE_IP = "org.zigbee.zigbeeip.v1";
+
+ private static final String NETWORK_PROPERTY_KEYS[] = {
+ LowpanProperties.KEY_NETWORK_NAME.getName(),
+ LowpanProperties.KEY_NETWORK_PANID.getName(),
+ LowpanProperties.KEY_NETWORK_XPANID.getName(),
+ LowpanProperties.KEY_CHANNEL.getName()
+ };
+
+ /**
+ * Callback base class for LowpanInterface
+ *
+ * @hide
+ */
+ //@SystemApi
+ public abstract static class Callback {
+ public void onConnectedChanged(boolean value) {}
+
+ public void onEnabledChanged(boolean value) {}
+
+ public void onUpChanged(boolean value) {}
+
+ public void onRoleChanged(@NonNull String value) {}
+
+ public void onStateChanged(@NonNull String state) {}
+
+ public void onLowpanIdentityChanged(@NonNull LowpanIdentity value) {}
+
+ /** @hide */
+ public void onPropertiesChanged(@NonNull Map properties) {}
+ }
+
+ private ILowpanInterface mBinder;
+ private final HashMap<Integer, ILowpanInterfaceListener> mListenerMap = new HashMap<>();
+
+ /** Map between IBinder identity hashes and LowpanInstance objects. */
+ private static final HashMap<Integer, LowpanInterface> sInstanceMap = new HashMap<>();
+
+ private LowpanInterface(IBinder binder) {
+ mBinder = ILowpanInterface.Stub.asInterface(binder);
+ }
+
+ /**
+ * Get the LowpanInterface object associated with this IBinder. Returns null if this IBinder
+ * does not implement the appropriate interface.
+ *
+ * @hide
+ */
+ @NonNull
+ public static final LowpanInterface from(IBinder binder) {
+ Integer hashCode = Integer.valueOf(System.identityHashCode(binder));
+ LowpanInterface instance;
+
+ synchronized (sInstanceMap) {
+ instance = sInstanceMap.get(hashCode);
+
+ if (instance == null) {
+ instance = new LowpanInterface(binder);
+ sInstanceMap.put(hashCode, instance);
+ }
+ }
+
+ return instance;
+ }
+
+ /** {@hide} */
+ public static final LowpanInterface from(ILowpanInterface iface) {
+ return from(iface.asBinder());
+ }
+
+ /** {@hide} */
+ public static final LowpanInterface getInterfaceFromBinder(IBinder binder) {
+ return from(binder);
+ }
+
+ /**
+ * Returns the IBinder object associated with this interface.
+ *
+ * @hide
+ */
+ public IBinder getBinder() {
+ return mBinder.asBinder();
+ }
+
+ private static void throwAsPublicException(Throwable t) throws LowpanException {
+ LowpanException.throwAsPublicException(t);
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // Private Property Helpers
+
+ void setProperties(Map properties) throws LowpanException {
+ try {
+ mBinder.setProperties(properties);
+
+ } catch (RemoteException x) {
+ // Catch and ignore all binder exceptions
+ Log.e(TAG, x.toString());
+
+ } catch (ServiceSpecificException x) {
+ throwAsPublicException(x);
+ }
+ }
+
+ @NonNull
+ Map<String, Object> getProperties(String keys[]) throws LowpanException {
+ try {
+ return mBinder.getProperties(keys);
+ } catch (RemoteException x) {
+ // Catch and ignore all binder exceptions
+ Log.e(TAG, x.toString());
+ } catch (ServiceSpecificException x) {
+ throwAsPublicException(x);
+ }
+ return new HashMap();
+ }
+
+ /** @hide */
+ public <T> void setProperty(LowpanProperty<T> key, T value) throws LowpanException {
+ HashMap<String, T> prop = new HashMap<>();
+ prop.put(key.getName(), value);
+ setProperties(prop);
+ }
+
+ /** @hide */
+ @Nullable
+ public <T> T getProperty(LowpanProperty<T> key) throws LowpanException {
+ Map<String, Object> map = getProperties(new String[] {key.getName()});
+ if (map != null && !map.isEmpty()) {
+ // We know there is only one value.
+ return (T) map.values().iterator().next();
+ }
+ return null;
+ }
+
+ @Nullable
+ <T> String getPropertyAsString(LowpanProperty<T> key) throws LowpanException {
+ try {
+ return mBinder.getPropertyAsString(key.getName());
+ } catch (RemoteException x) {
+ // Catch and ignore all binder exceptions
+ Log.e(TAG, x.toString());
+ } catch (ServiceSpecificException x) {
+ throwAsPublicException(x);
+ }
+ return null;
+ }
+
+ int getPropertyAsInt(LowpanProperty<Integer> key) throws LowpanException {
+ Integer value = getProperty(key);
+ return (value != null) ? value : 0;
+ }
+
+ boolean getPropertyAsBoolean(LowpanProperty<Boolean> key) throws LowpanException {
+ Boolean value = getProperty(key);
+ return (value != null) ? value : 0;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // Public Actions
+
+ /**
+ * Form a new network with the given network information optional credential. Unspecified fields
+ * in the network information will be filled in with reasonable values. If the network
+ * credential is unspecified, one will be generated automatically.
+ *
+ * <p>This method will block until either the network was successfully formed or an error
+ * prevents the network form being formed.
+ *
+ * <p>Upon success, the interface will be up and attached to the newly formed network.
+ *
+ * @see #join(LowpanProvision)
+ */
+ public void form(@NonNull LowpanProvision provision) throws LowpanException {
+ try {
+ Map<String, Object> parameters = new HashMap();
+ provision.addToMap(parameters);
+ mBinder.form(parameters);
+ } catch (RemoteException x) {
+ throwAsPublicException(x);
+ } catch (ServiceSpecificException x) {
+ throwAsPublicException(x);
+ }
+ }
+
+ /**
+ * Attempts to join a new network with the given network information. This method will block
+ * until either the network was successfully joined or an error prevented the network from being
+ * formed. Upon success, the interface will be up and attached to the newly joined network.
+ *
+ * <p>Note that “joining” is distinct from “attaching”: Joining requires at least one other peer
+ * device to be present in order for the operation to complete successfully.
+ */
+ public void join(@NonNull LowpanProvision provision) throws LowpanException {
+ try {
+ Map<String, Object> parameters = new HashMap();
+ provision.addToMap(parameters);
+ mBinder.join(parameters);
+ } catch (RemoteException x) {
+ throwAsPublicException(x);
+ } catch (ServiceSpecificException x) {
+ throwAsPublicException(x);
+ }
+ }
+
+ /**
+ * Attaches to the network described by identity and credential. This is similar to {@link
+ * #join}, except that (assuming the identity and credential are valid) it will always succeed
+ * and provision the interface, even if there are no peers nearby.
+ *
+ * <p>This method will block execution until the operation has completed.
+ */
+ public void attach(@NonNull LowpanProvision provision) throws LowpanException {
+ if (ROLE_DETACHED.equals(getRole())) {
+ Map<String, Object> parameters = new HashMap();
+ provision.addToMap(parameters);
+ setProperties(parameters);
+ setUp(true);
+ } else {
+ throw new LowpanException(LowpanException.LOWPAN_ALREADY);
+ }
+ }
+
+ /**
+ * Bring down the network interface and forget all non-volatile details about the current
+ * network.
+ *
+ * <p>This method will block execution until the operation has completed.
+ */
+ public void leave() throws LowpanException {
+ try {
+ mBinder.leave();
+ } catch (RemoteException x) {
+ throwAsPublicException(x);
+ } catch (ServiceSpecificException x) {
+ throwAsPublicException(x);
+ }
+ }
+
+ /**
+ * Start a new commissioning session. Will fail if the interface is attached to a network or if
+ * the interface is disabled.
+ */
+ public @NonNull LowpanCommissioningSession startCommissioningSession(
+ @NonNull LowpanBeaconInfo beaconInfo) throws LowpanException {
+
+ /* TODO: Implement startCommissioningSession */
+ throw new LowpanException(LowpanException.LOWPAN_FEATURE_NOT_SUPPORTED);
+ }
+
+ /**
+ * Reset this network interface as if it has been power cycled. Will bring the network interface
+ * down if it was previously up. Will not erase any non-volatile settings.
+ *
+ * <p>This method will block execution until the operation has completed.
+ *
+ * @hide
+ */
+ public void reset() throws LowpanException {
+ try {
+ mBinder.reset();
+ } catch (RemoteException x) {
+ throwAsPublicException(x);
+ } catch (ServiceSpecificException x) {
+ throwAsPublicException(x);
+ }
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // Public Getters and Setters
+
+ /**
+ * Returns the name of this network interface.
+ *
+ * <p>Will return empty string if this interface is no longer viable.
+ */
+ @NonNull
+ public String getName() {
+ try {
+ return mBinder.getName();
+ } catch (RemoteException x) {
+ // Catch and ignore all binder exceptions
+ // when fetching the name.
+ Log.e(TAG, x.toString());
+ } catch (ServiceSpecificException x) {
+ // Catch and ignore all service-specific exceptions
+ // when fetching the name.
+ Log.e(TAG, x.toString());
+ }
+ return "";
+ }
+
+ /**
+ * Indicates if the interface is enabled or disabled.
+ *
+ * @see #setEnabled
+ * @see android.net.lowpan.LowpanException#LOWPAN_DISABLED
+ */
+ public boolean isEnabled() {
+ try {
+ return getPropertyAsBoolean(LowpanProperties.KEY_INTERFACE_ENABLED);
+ } catch (LowpanException x) {
+ return false;
+ }
+ }
+
+ /**
+ * Enables or disables the LoWPAN interface. When disabled, the interface is put into a low-power
+ * state and all commands that require the NCP to be queried will fail with {@link
+ * android.net.lowpan.LowpanException#LOWPAN_DISABLED}.
+ *
+ * @see #isEnabled
+ * @see android.net.lowpan.LowpanException#LOWPAN_DISABLED
+ * @hide
+ */
+ public void setEnabled(boolean enabled) throws LowpanException {
+ setProperty(LowpanProperties.KEY_INTERFACE_ENABLED, enabled);
+ }
+
+ /**
+ * Indicates if the network interface is up or down.
+ *
+ * @hide
+ */
+ public boolean isUp() {
+ try {
+ return getPropertyAsBoolean(LowpanProperties.KEY_INTERFACE_UP);
+ } catch (LowpanException x) {
+ return false;
+ }
+ }
+
+ /**
+ * Bring up or shut down the network interface.
+ *
+ * <p>This method brings up or shuts down the network interface, attaching or (gracefully)
+ * detaching from the currently configured LoWPAN network as appropriate.
+ *
+ * @hide
+ */
+ public void setUp(boolean interfaceUp) throws LowpanException {
+ setProperty(LowpanProperties.KEY_INTERFACE_UP, interfaceUp);
+ }
+
+ /**
+ * Indicates if there is at least one peer in range.
+ *
+ * @return <code>true</code> if we have at least one other peer in range, <code>false</code>
+ * otherwise.
+ */
+ public boolean isConnected() {
+ try {
+ return getPropertyAsBoolean(LowpanProperties.KEY_INTERFACE_CONNECTED);
+ } catch (LowpanException x) {
+ return false;
+ }
+ }
+
+ /**
+ * Indicates if this interface is currently commissioned onto an existing network. If the
+ * interface is commissioned, the interface may be brought up using setUp().
+ */
+ public boolean isCommissioned() {
+ try {
+ return getPropertyAsBoolean(LowpanProperties.KEY_INTERFACE_COMMISSIONED);
+ } catch (LowpanException x) {
+ return false;
+ }
+ }
+
+ /**
+ * Get interface state
+ *
+ * <h3>State Diagram</h3>
+ *
+ * <img src="LowpanInterface-1.png" />
+ *
+ * @return The current state of the interface.
+ * @see #STATE_OFFLINE
+ * @see #STATE_COMMISSIONING
+ * @see #STATE_ATTACHING
+ * @see #STATE_ATTACHED
+ * @see #STATE_FAULT
+ */
+ public String getState() {
+ try {
+ return getProperty(LowpanProperties.KEY_INTERFACE_STATE);
+ } catch (LowpanException x) {
+ Log.e(TAG, x.toString());
+ return STATE_FAULT;
+ }
+ }
+
+ /** TODO: doc */
+ public LowpanIdentity getLowpanIdentity() {
+ LowpanIdentity.Builder builder = new LowpanIdentity.Builder();
+ try {
+ builder.updateFromMap(getProperties(NETWORK_PROPERTY_KEYS));
+ } catch (LowpanException x) {
+ // We ignore all LoWPAN-specitic exceptions here.
+ }
+
+ return builder.build();
+ }
+
+ /**
+ * TODO: doc
+ *
+ * @hide
+ */
+ public void setLowpanIdentity(LowpanIdentity network) throws LowpanException {
+ Map<String, Object> map = new HashMap();
+ LowpanIdentity.addToMap(map, network);
+ setProperties(map);
+ }
+
+ /** TODO: doc */
+ @NonNull
+ public String getRole() {
+ String role = null;
+
+ try {
+ role = getProperty(LowpanProperties.KEY_NETWORK_ROLE);
+ } catch (LowpanException x) {
+ // We ignore all LoWPAN-specitic exceptions here.
+ Log.e(TAG, x.toString());
+ }
+
+ if (role == null) {
+ role = ROLE_DETACHED;
+ }
+
+ return role;
+ }
+
+ /** TODO: doc */
+ @Nullable
+ public LowpanCredential getLowpanCredential() {
+ LowpanCredential credential = null;
+
+ try {
+ Integer keyIndex = getProperty(LowpanProperties.KEY_NETWORK_MASTER_KEY_INDEX);
+
+ if (keyIndex == null) {
+ credential =
+ LowpanCredential.createMasterKey(
+ getProperty(LowpanProperties.KEY_NETWORK_MASTER_KEY));
+ } else {
+ credential =
+ LowpanCredential.createMasterKey(
+ getProperty(LowpanProperties.KEY_NETWORK_MASTER_KEY),
+ keyIndex.intValue());
+ }
+ } catch (LowpanException x) {
+ // We ignore all LoWPAN-specitic exceptions here.
+ Log.e(TAG, x.toString());
+ }
+
+ return credential;
+ }
+
+ /**
+ * TODO: doc
+ *
+ * @hide
+ */
+ public void setLowpanCredential(LowpanCredential networkCredential) throws LowpanException {
+ Map<String, Object> map = new HashMap();
+ networkCredential.addToMap(map);
+ setProperties(map);
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // Listener Support
+
+ /**
+ * Registers a subclass of {@link LowpanInterface.Callback} to receive events.
+ *
+ * @param cb Subclass of {@link LowpanInterface.Callback} which will receive events.
+ * @param handler If not <code>null</code>, events will be dispatched via the given handler
+ * object. If <code>null</code>, the thread upon which events will be dispatched is
+ * unspecified.
+ * @see #registerCallback(Callback)
+ * @see #unregisterCallback(Callback)
+ */
+ public void registerCallback(@NonNull Callback cb, @Nullable Handler handler) {
+ ILowpanInterfaceListener.Stub listenerBinder =
+ new ILowpanInterfaceListener.Stub() {
+ public void onPropertiesChanged(Map<String, Object> properties) {
+ Runnable runnable =
+ new Runnable() {
+ @Override
+ public void run() {
+ for (String key : (Set<String>) properties.keySet()) {
+ Object value = properties.get(key);
+ switch (key) {
+ case ILowpanInterface.KEY_INTERFACE_ENABLED:
+ cb.onEnabledChanged(
+ ((Boolean) value).booleanValue());
+ break;
+ case ILowpanInterface.KEY_INTERFACE_UP:
+ cb.onUpChanged(
+ ((Boolean) value).booleanValue());
+ break;
+ case ILowpanInterface.KEY_INTERFACE_CONNECTED:
+ cb.onConnectedChanged(
+ ((Boolean) value).booleanValue());
+ break;
+ case ILowpanInterface.KEY_INTERFACE_STATE:
+ cb.onStateChanged((String) value);
+ break;
+ case ILowpanInterface.KEY_NETWORK_NAME:
+ case ILowpanInterface.KEY_NETWORK_PANID:
+ case ILowpanInterface.KEY_NETWORK_XPANID:
+ case ILowpanInterface.KEY_CHANNEL:
+ cb.onLowpanIdentityChanged(getLowpanIdentity());
+ break;
+ case ILowpanInterface.KEY_NETWORK_ROLE:
+ cb.onRoleChanged(value.toString());
+ break;
+ }
+ }
+ cb.onPropertiesChanged(properties);
+ }
+ };
+
+ if (handler != null) {
+ handler.post(runnable);
+ } else {
+ runnable.run();
+ }
+ }
+ };
+ try {
+ mBinder.addListener(listenerBinder);
+ } catch (RemoteException x) {
+ // Log and ignore. If this happens, this interface
+ // is likely dead anyway.
+ Log.e(TAG, x.toString());
+ }
+ synchronized (mListenerMap) {
+ mListenerMap.put(System.identityHashCode(cb), listenerBinder);
+ }
+ }
+
+ /**
+ * Registers a subclass of {@link LowpanInterface.Callback} to receive events.
+ *
+ * <p>The thread upon which events will be dispatched is unspecified.
+ *
+ * @param cb Subclass of {@link LowpanInterface.Callback} which will receive events.
+ * @see #registerCallback(Callback, Handler)
+ * @see #unregisterCallback(Callback)
+ */
+ public void registerCallback(Callback cb) {
+ registerCallback(cb, null);
+ }
+
+ /**
+ * Unregisters a previously registered callback class.
+ *
+ * @param cb Subclass of {@link LowpanInterface.Callback} which was previously registered to
+ * receive events.
+ * @see #registerCallback(Callback, Handler)
+ * @see #registerCallback(Callback)
+ */
+ public void unregisterCallback(Callback cb) {
+ int hashCode = System.identityHashCode(cb);
+ ILowpanInterfaceListener listenerBinder = mListenerMap.get(hashCode);
+
+ if (listenerBinder != null) {
+ synchronized (mListenerMap) {
+ mListenerMap.remove(hashCode);
+ }
+ try {
+ mBinder.removeListener(listenerBinder);
+ } catch (RemoteException x) {
+ // Catch and ignore all binder exceptions
+ Log.e(TAG, x.toString());
+ }
+ }
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // Active and Passive Scanning
+
+ /**
+ * Creates a new {@link android.net.lowpan.LowpanScanner} object for this interface.
+ *
+ * <p>This method allocates a new unique object for each call.
+ *
+ * @see android.net.lowpan.LowpanScanner
+ */
+ public @NonNull LowpanScanner createScanner() {
+ return new LowpanScanner(mBinder);
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // Route Management
+
+ /**
+ * Advertise the given IP prefix as an on-mesh prefix.
+ *
+ * @hide
+ */
+ public void addOnMeshPrefix(IpPrefix prefix, int flags) throws LowpanException {
+ try {
+ mBinder.addOnMeshPrefix(prefix, flags);
+ } catch (RemoteException x) {
+ throwAsPublicException(x);
+ } catch (ServiceSpecificException x) {
+ throwAsPublicException(x);
+ }
+ }
+
+ /**
+ * Remove an IP prefix previously advertised by this device from the list of advertised on-mesh
+ * prefixes.
+ *
+ * @hide
+ */
+ public void removeOnMeshPrefix(IpPrefix prefix) {
+ try {
+ mBinder.removeOnMeshPrefix(prefix);
+ } catch (RemoteException x) {
+ // Catch and ignore all binder exceptions
+ Log.e(TAG, x.toString());
+ } catch (ServiceSpecificException x) {
+ // Catch and ignore all service exceptions
+ Log.e(TAG, x.toString());
+ }
+ }
+
+ /**
+ * Advertise this device to other devices on the mesh network as having a specific route to the
+ * given network. This device will then receive forwarded traffic for that network.
+ *
+ * @hide
+ */
+ public void addExternalRoute(IpPrefix prefix, int flags) throws LowpanException {
+ try {
+ mBinder.addExternalRoute(prefix, flags);
+ } catch (RemoteException x) {
+ throwAsPublicException(x);
+ } catch (ServiceSpecificException x) {
+ throwAsPublicException(x);
+ }
+ }
+
+ /**
+ * Revoke a previously advertised specific route to the given network.
+ *
+ * @hide
+ */
+ public void removeExternalRoute(IpPrefix prefix) {
+ try {
+ mBinder.removeExternalRoute(prefix);
+ } catch (RemoteException x) {
+ // Catch and ignore all binder exceptions
+ Log.e(TAG, x.toString());
+ } catch (ServiceSpecificException x) {
+ // Catch and ignore all service exceptions
+ Log.e(TAG, x.toString());
+ }
+ }
+}
diff --git a/lowpan/java/android/net/lowpan/LowpanManager.java b/lowpan/java/android/net/lowpan/LowpanManager.java
new file mode 100644
index 000000000000..b58608da7c21
--- /dev/null
+++ b/lowpan/java/android/net/lowpan/LowpanManager.java
@@ -0,0 +1,283 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.lowpan;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.Context;
+import android.os.DeadObjectException;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.util.AndroidException;
+import android.util.Log;
+import java.util.HashMap;
+
+/**
+ * Manager object for looking up LoWPAN interfaces.
+ *
+ * @hide
+ */
+//@SystemApi
+public class LowpanManager {
+ private static final String TAG = LowpanManager.class.getSimpleName();
+
+ //////////////////////////////////////////////////////////////////////////
+ // Public Classes
+
+ /** @hide */
+ //@SystemApi
+ public abstract static class Callback {
+ public void onInterfaceAdded(LowpanInterface lowpan_interface) {}
+
+ public void onInterfaceRemoved(LowpanInterface lowpan_interface) {}
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // Instance Variables
+
+ private ILowpanManager mManager;
+ private HashMap<Integer, ILowpanManagerListener> mListenerMap = new HashMap<>();
+
+ //////////////////////////////////////////////////////////////////////////
+
+ private static LowpanManager sSingletonInstance;
+
+ //////////////////////////////////////////////////////////////////////////
+ // Static Methods
+
+ /** Returns a reference to the LowpanManager object, allocating it if necessary. */
+ public static LowpanManager getManager() {
+ return from(null);
+ }
+
+ public static LowpanManager from(Context context) {
+ // TODO: Actually get this from the context!
+
+ if (sSingletonInstance == null) {
+ sSingletonInstance = new LowpanManager();
+ }
+ return sSingletonInstance;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // Constructors
+
+ /**
+ * Private LowpanManager constructor. Since we are a singleton, we do not allow external
+ * construction.
+ */
+ private LowpanManager() {}
+
+ //////////////////////////////////////////////////////////////////////////
+ // Private Methods
+
+ /**
+ * Returns a reference to the ILowpanManager interface, provided by the LoWPAN Manager Service.
+ */
+ @Nullable
+ private ILowpanManager getILowpanManager() {
+ ILowpanManager manager = mManager;
+ if (manager == null) {
+ IBinder serviceBinder =
+ new ServiceManager().getService(ILowpanManager.LOWPAN_SERVICE_NAME);
+ mManager = manager = ILowpanManager.Stub.asInterface(serviceBinder);
+
+ // Add any listeners
+ synchronized (mListenerMap) {
+ for (Integer hashObj : mListenerMap.keySet()) {
+ try {
+ manager.addListener(mListenerMap.get(hashObj));
+ } catch (RemoteException x) {
+ // Consider any failure here as implying the manager is defunct
+ mManager = manager = null;
+ }
+ }
+ }
+ }
+ return manager;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // Public Methods
+
+ /**
+ * Returns a reference to the requested LowpanInterface object. If the given interface doesn't
+ * exist, or it is not a LoWPAN interface, returns null.
+ */
+ @Nullable
+ public LowpanInterface getInterface(@NonNull String name) {
+ LowpanInterface ret = null;
+ ILowpanManager manager = getILowpanManager();
+
+ // Maximum number of tries is two. We should only try
+ // more than once if our manager has died or there
+ // was some sort of AIDL buffer full event.
+ for (int i = 0; i < 2 && manager != null; i++) {
+ try {
+ ILowpanInterface iface = manager.getInterface(name);
+ if (iface != null) {
+ ret = LowpanInterface.getInterfaceFromBinder(iface.asBinder());
+ }
+ break;
+ } catch (RemoteException x) {
+ // In all of the cases when we get this exception, we reconnect and try again
+ mManager = null;
+ manager = getILowpanManager();
+ }
+ }
+ return ret;
+ }
+
+ /**
+ * Returns a reference to the first registered LowpanInterface object. If there are no LoWPAN
+ * interfaces registered, returns null.
+ */
+ @Nullable
+ public LowpanInterface getInterface() {
+ String[] ifaceList = getInterfaceList();
+ if (ifaceList != null && ifaceList.length > 0) {
+ return getInterface(ifaceList[0]);
+ }
+ return null;
+ }
+
+ /**
+ * Returns a string array containing the names of LoWPAN interfaces. This list may contain fewer
+ * interfaces if the calling process does not have permissions to see individual interfaces.
+ */
+ @NonNull
+ public String[] getInterfaceList() {
+ ILowpanManager manager = getILowpanManager();
+
+ if (manager != null) {
+ try {
+ return manager.getInterfaceList();
+
+ } catch (RemoteException x) {
+ // In all of the cases when we get this exception, we reconnect and try again
+ mManager = null;
+ try {
+ manager = getILowpanManager();
+ if (manager != null) {
+ return manager.getInterfaceList();
+ }
+ } catch (RemoteException ex) {
+ // Something weird is going on, so we log it
+ // and fall back thru to returning an empty array.
+ Log.e(TAG, ex.toString());
+ mManager = null;
+ }
+ }
+ }
+
+ // Return empty list if we have no service.
+ return new String[0];
+ }
+
+ /**
+ * Registers a callback object to receive notifications when LoWPAN interfaces are added or
+ * removed.
+ *
+ * @hide
+ */
+ public void registerCallback(@NonNull Callback cb, @Nullable Handler handler)
+ throws LowpanException {
+ ILowpanManagerListener.Stub listenerBinder =
+ new ILowpanManagerListener.Stub() {
+ public void onInterfaceAdded(ILowpanInterface lowpan_interface) {
+ Runnable runnable =
+ new Runnable() {
+ @Override
+ public void run() {
+ cb.onInterfaceAdded(
+ LowpanInterface.getInterfaceFromBinder(
+ lowpan_interface.asBinder()));
+ }
+ };
+
+ if (handler != null) {
+ handler.post(runnable);
+ } else {
+ runnable.run();
+ }
+ }
+
+ public void onInterfaceRemoved(ILowpanInterface lowpan_interface) {
+ Runnable runnable =
+ new Runnable() {
+ @Override
+ public void run() {
+ cb.onInterfaceRemoved(
+ LowpanInterface.getInterfaceFromBinder(
+ lowpan_interface.asBinder()));
+ }
+ };
+
+ if (handler != null) {
+ handler.post(runnable);
+ } else {
+ runnable.run();
+ }
+ }
+ };
+ ILowpanManager manager = getILowpanManager();
+ if (manager != null) {
+ try {
+ manager.addListener(listenerBinder);
+ } catch (DeadObjectException x) {
+ mManager = null;
+ // Tickle the ILowpanManager instance, which might
+ // get us added back.
+ getILowpanManager();
+ } catch (Throwable x) {
+ LowpanException.throwAsPublicException(x);
+ }
+ }
+ synchronized (mListenerMap) {
+ mListenerMap.put(Integer.valueOf(System.identityHashCode(cb)), listenerBinder);
+ }
+ }
+
+ /** @hide */
+ public void registerCallback(@NonNull Callback cb) throws LowpanException {
+ registerCallback(cb, null);
+ }
+
+ /**
+ * Unregisters a previously registered {@link LowpanManager.Callback} object.
+ *
+ * @hide
+ */
+ public void unregisterCallback(@NonNull Callback cb) throws AndroidException {
+ Integer hashCode = Integer.valueOf(System.identityHashCode(cb));
+ ILowpanManagerListener listenerBinder = mListenerMap.get(hashCode);
+ if (listenerBinder != null) {
+ synchronized (mListenerMap) {
+ mListenerMap.remove(hashCode);
+ }
+ if (getILowpanManager() != null) {
+ try {
+ mManager.removeListener(listenerBinder);
+ } catch (DeadObjectException x) {
+ mManager = null;
+ }
+ }
+ }
+ }
+}
diff --git a/lowpan/java/android/net/lowpan/LowpanProperties.java b/lowpan/java/android/net/lowpan/LowpanProperties.java
new file mode 100644
index 000000000000..0d5acc2d0c21
--- /dev/null
+++ b/lowpan/java/android/net/lowpan/LowpanProperties.java
@@ -0,0 +1,125 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.lowpan;
+
+import android.net.LinkAddress;
+import android.net.RouteInfo;
+import java.util.List;
+
+/** {@hide} */
+public final class LowpanProperties {
+
+ public static final LowpanProperty<Boolean> KEY_INTERFACE_ENABLED =
+ new LowpanStandardProperty(
+ "android.net.lowpan.property.INTERFACE_ENABLED", Boolean.class);
+ public static final LowpanProperty<Boolean> KEY_INTERFACE_COMMISSIONED =
+ new LowpanStandardProperty(
+ "android.net.lowpan.property.INTERFACE_COMMISSIONED", Boolean.class);
+ public static final LowpanProperty<Boolean> KEY_INTERFACE_CONNECTED =
+ new LowpanStandardProperty(
+ "android.net.lowpan.property.INTERFACE_CONNECTED", Boolean.class);
+ public static final LowpanProperty<Boolean> KEY_INTERFACE_UP =
+ new LowpanStandardProperty("android.net.lowpan.property.INTERFACE_UP", Boolean.class);
+ public static final LowpanProperty<String> KEY_INTERFACE_STATE =
+ new LowpanStandardProperty("android.net.lowpan.property.INTERFACE_STATE", String.class);
+
+ public static final LowpanProperty<String> KEY_NETWORK_NAME =
+ new LowpanStandardProperty("android.net.lowpan.property.NETWORK_NAME", Boolean.class);
+ public static final LowpanProperty<Integer> KEY_NETWORK_PANID =
+ new LowpanStandardProperty("android.net.lowpan.property.NETWORK_PANID", Integer.class);
+ public static final LowpanProperty<byte[]> KEY_NETWORK_XPANID =
+ new LowpanStandardProperty("android.net.lowpan.property.NETWORK_XPANID", byte[].class);
+ public static final LowpanProperty<byte[]> KEY_NETWORK_MASTER_KEY =
+ new LowpanStandardProperty(
+ "android.net.lowpan.property.NETWORK_MASTER_KEY", byte[].class);
+ public static final LowpanProperty<Integer> KEY_NETWORK_MASTER_KEY_INDEX =
+ new LowpanStandardProperty(
+ "android.net.lowpan.property.NETWORK_MASTER_KEY_INDEX", Integer.class);
+ public static final LowpanProperty<Integer> KEY_NETWORK_TYPE =
+ new LowpanStandardProperty("android.net.lowpan.property.NETWORK_TYPE", Integer.class);
+ public static final LowpanProperty<String> KEY_NETWORK_ROLE =
+ new LowpanStandardProperty("android.net.lowpan.property.NETWORK_ROLE", String.class);
+
+ public static final LowpanProperty<Integer> KEY_CHANNEL =
+ new LowpanStandardProperty("android.net.lowpan.property.CHANNEL", Integer.class);
+ public static final LowpanProperty<int[]> KEY_CHANNEL_MASK =
+ new LowpanStandardProperty("android.net.lowpan.property.CHANNEL_MASK", int[].class);
+ public static final LowpanProperty<Integer> KEY_MAX_TX_POWER =
+ new LowpanStandardProperty("android.net.lowpan.property.MAX_TX_POWER", Integer.class);
+ public static final LowpanProperty<Integer> KEY_RSSI =
+ new LowpanStandardProperty("android.net.lowpan.property.RSSI", Integer.class);
+
+ public static final LowpanProperty<Integer> KEY_LQI =
+ new LowpanStandardProperty("android.net.lowpan.property.LQI", Integer.class);
+ public static final LowpanProperty<byte[]> KEY_BEACON_ADDRESS =
+ new LowpanStandardProperty("android.net.lowpan.property.BEACON_ADDRESS", byte[].class);
+ public static final LowpanProperty<Boolean> KEY_BEACON_CAN_ASSIST =
+ new LowpanStandardProperty(
+ "android.net.lowpan.property.BEACON_CAN_ASSIST", Boolean.class);
+
+ public static final LowpanProperty<String> KEY_DRIVER_VERSION =
+ new LowpanStandardProperty("android.net.lowpan.property.DRIVER_VERSION", String.class);
+
+ public static final LowpanProperty<String> KEY_NCP_VERSION =
+ new LowpanStandardProperty("android.net.lowpan.property.NCP_VERSION", String.class);
+
+ public static final LowpanProperty<List<LinkAddress>> KEY_LINK_ADDRESS_ARRAY =
+ new LowpanStandardProperty(
+ "android.net.lowpan.property.LINK_ADDRESS_ARRAY", LinkAddress[].class);
+
+ public static final LowpanProperty<List<RouteInfo>> KEY_ROUTE_INFO_ARRAY =
+ new LowpanStandardProperty(
+ "android.net.lowpan.property.ROUTE_INFO_ARRAY", RouteInfo[].class);
+
+ /** @hide */
+ public static final LowpanProperty<byte[]> KEY_EXTENDED_ADDRESS =
+ new LowpanStandardProperty(
+ "android.net.lowpan.property.EXTENDED_ADDRESS", byte[].class);
+
+ /** @hide */
+ public static final LowpanProperty<byte[]> KEY_MAC_ADDRESS =
+ new LowpanStandardProperty("android.net.lowpan.property.MAC_ADDRESS", byte[].class);
+
+ /** @hide */
+ private LowpanProperties() {}
+
+ /** @hide */
+ static final class LowpanStandardProperty<T> extends LowpanProperty<T> {
+ private final String mName;
+ private final Class<T> mType;
+
+ LowpanStandardProperty(String name, Class<T> type) {
+ mName = name;
+ mType = type;
+ }
+
+ @Override
+ public String getName() {
+ return mName;
+ }
+
+ @Override
+ public Class<T> getType() {
+ return mType;
+ }
+
+ @Override
+ public String toString() {
+ return getName();
+ }
+ }
+}
diff --git a/lowpan/java/android/net/lowpan/LowpanProperty.java b/lowpan/java/android/net/lowpan/LowpanProperty.java
new file mode 100644
index 000000000000..7f26986e9da0
--- /dev/null
+++ b/lowpan/java/android/net/lowpan/LowpanProperty.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.lowpan;
+
+import java.util.Map;
+
+/** {@hide} */
+public abstract class LowpanProperty<T> {
+ public abstract String getName();
+
+ public abstract Class<T> getType();
+
+ public void putInMap(Map map, T value) {
+ map.put(getName(), value);
+ }
+
+ public T getFromMap(Map map) {
+ return (T) map.get(getName());
+ }
+}
diff --git a/lowpan/java/android/net/lowpan/LowpanProvision.java b/lowpan/java/android/net/lowpan/LowpanProvision.java
new file mode 100644
index 000000000000..ace1f9c05c4d
--- /dev/null
+++ b/lowpan/java/android/net/lowpan/LowpanProvision.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.lowpan;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import java.util.Map;
+
+/**
+ * Describes the information needed to describe a network
+ *
+ * @hide
+ */
+//@SystemApi
+public class LowpanProvision {
+
+ //////////////////////////////////////////////////////////////////////////
+ // Builder
+
+ /** @hide */
+ //@SystemApi
+ public static class Builder {
+ private final LowpanProvision provision = new LowpanProvision();
+
+ public Builder setLowpanIdentity(@NonNull LowpanIdentity identity) {
+ provision.mIdentity = identity;
+ return this;
+ }
+
+ public Builder setLowpanCredential(@NonNull LowpanCredential credential) {
+ provision.mCredential = credential;
+ return this;
+ }
+
+ public LowpanProvision build() {
+ return provision;
+ }
+ }
+
+ private LowpanProvision() {}
+
+ //////////////////////////////////////////////////////////////////////////
+ // Instance Variables
+
+ private LowpanIdentity mIdentity = new LowpanIdentity();
+ private LowpanCredential mCredential = null;
+
+ //////////////////////////////////////////////////////////////////////////
+ // Public Getters and Setters
+
+ @NonNull
+ public LowpanIdentity getLowpanIdentity() {
+ return mIdentity;
+ }
+
+ @Nullable
+ public LowpanCredential getLowpanCredential() {
+ return mCredential;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // LoWPAN-Internal Methods
+
+ static void addToMap(Map<String, Object> parameters, LowpanProvision provision)
+ throws LowpanException {
+ provision.mIdentity.addToMap(parameters);
+ if (provision.mCredential != null) {
+ provision.mCredential.addToMap(parameters);
+ }
+ }
+
+ void addToMap(Map<String, Object> parameters) throws LowpanException {
+ addToMap(parameters, this);
+ }
+
+ @Override
+ public String toString() {
+ StringBuffer sb = new StringBuffer();
+
+ sb.append("LowpanProvision { identity => ").append(mIdentity.toString());
+
+ if (mCredential != null) {
+ sb.append(", credential: ").append(mCredential.toString());
+ }
+
+ sb.append("}");
+
+ return sb.toString();
+ }
+};
diff --git a/lowpan/java/android/net/lowpan/LowpanScanner.java b/lowpan/java/android/net/lowpan/LowpanScanner.java
new file mode 100644
index 000000000000..754f72e3cb84
--- /dev/null
+++ b/lowpan/java/android/net/lowpan/LowpanScanner.java
@@ -0,0 +1,317 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.lowpan;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.Handler;
+import android.os.RemoteException;
+import android.os.ServiceSpecificException;
+import android.util.Log;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * LoWPAN Scanner
+ *
+ * <p>This class allows performing network (active) scans and energy (passive) scans.
+ *
+ * @see LowpanInterface
+ * @hide
+ */
+//@SystemApi
+public class LowpanScanner {
+ private static final String TAG = LowpanInterface.class.getSimpleName();
+
+ //////////////////////////////////////////////////////////////////////////
+ // Public Classes
+
+ /**
+ * Callback base class for LowpanScanner
+ *
+ * @hide
+ */
+ //@SystemApi
+ public abstract static class Callback {
+ public void onNetScanBeacon(LowpanBeaconInfo beacon) {}
+
+ public void onEnergyScanResult(LowpanEnergyScanResult result) {}
+
+ public void onScanFinished() {}
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // Instance Variables
+
+ private ILowpanInterface mBinder;
+ private Callback mCallback = null;
+ private Handler mHandler = null;
+ private List<Integer> mChannelMask = null;
+ private int mTxPower = Integer.MAX_VALUE;
+
+ //////////////////////////////////////////////////////////////////////////
+ // Constructors/Accessors and Exception Glue
+
+ LowpanScanner(@NonNull ILowpanInterface binder) {
+ mBinder = binder;
+ }
+
+ /** Sets an instance of {@link LowpanScanner.Callback} to receive events. */
+ public void setCallback(@Nullable Callback cb, @Nullable Handler handler) {
+ mCallback = cb;
+ mHandler = handler;
+ }
+
+ /** Sets an instance of {@link LowpanScanner.Callback} to receive events. */
+ public void setCallback(@Nullable Callback cb) {
+ setCallback(cb, null);
+ }
+
+ /**
+ * Sets the channel mask to use when scanning.
+ *
+ * @param mask The channel mask to use when scanning. If <code>null</code>, any previously set
+ * channel mask will be cleared and all channels not masked by the current regulatory zone
+ * will be scanned.
+ */
+ public void setChannelMask(@Nullable Collection<Integer> mask) {
+ if (mask == null) {
+ mChannelMask = null;
+ } else {
+ if (mChannelMask == null) {
+ mChannelMask = new ArrayList<>();
+ } else {
+ mChannelMask.clear();
+ }
+ mChannelMask.addAll(mask);
+ }
+ }
+
+ /**
+ * Gets the current channel mask.
+ *
+ * @return the current channel mask, or <code>null</code> if no channel mask is currently set.
+ */
+ public @Nullable Collection<Integer> getChannelMask() {
+ return mChannelMask.clone();
+ }
+
+ /**
+ * Adds a channel to the channel mask used for scanning.
+ *
+ * <p>If a channel mask was previously <code>null</code>, a new one is created containing only
+ * this channel. May be called multiple times to add additional channels ot the channel mask.
+ *
+ * @see #setChannelMask
+ * @see #getChannelMask
+ * @see #getTxPower
+ */
+ public void addChannel(int channel) {
+ if (mChannelMask == null) {
+ mChannelMask = new ArrayList<>();
+ }
+ mChannelMask.add(Integer.valueOf(channel));
+ }
+
+ /**
+ * Sets the maximum transmit power to be used for active scanning.
+ *
+ * <p>The actual transmit power used is the lesser of this value and the currently configured
+ * maximum transmit power for the interface.
+ *
+ * @see #getTxPower
+ */
+ public void setTxPower(int txPower) {
+ mTxPower = txPower;
+ }
+
+ /**
+ * Gets the maximum transmit power used for active scanning.
+ *
+ * @see #setTxPower
+ */
+ public int getTxPower() {
+ return mTxPower;
+ }
+
+ private Map<String, Object> createScanOptionMap() {
+ Map<String, Object> map = new HashMap();
+
+ if (mChannelMask != null) {
+ LowpanProperties.KEY_CHANNEL_MASK.putInMap(
+ map, mChannelMask.stream().mapToInt(i -> i).toArray());
+ }
+
+ if (mTxPower != Integer.MAX_VALUE) {
+ LowpanProperties.KEY_MAX_TX_POWER.putInMap(map, Integer.valueOf(mTxPower));
+ }
+
+ return map;
+ }
+
+ /**
+ * Start a network scan.
+ *
+ * <p>This method will return once the scan has started.
+ *
+ * @see #stopNetScan
+ */
+ public void startNetScan() throws LowpanException {
+ Map<String, Object> map = createScanOptionMap();
+
+ ILowpanNetScanCallback binderListener =
+ new ILowpanNetScanCallback.Stub() {
+ public void onNetScanBeacon(Map parameters) {
+ Callback callback = mCallback;
+ Handler handler = mHandler;
+
+ if (callback == null) {
+ return;
+ }
+
+ Runnable runnable = () -> callback.onNetScanBeacon(
+ new LowpanBeaconInfo.Builder()
+ .updateFromMap(parameters)
+ .build());
+
+ if (handler != null) {
+ handler.post(runnable);
+ } else {
+ runnable.run();
+ }
+ }
+
+ public void onNetScanFinished() {
+ Callback callback = mCallback;
+ Handler handler = mHandler;
+
+ if (callback == null) {
+ return;
+ }
+
+ Runnable runnable = () -> callback.onScanFinished();
+
+ if (handler != null) {
+ handler.post(runnable);
+ } else {
+ runnable.run();
+ }
+ }
+ };
+
+ try {
+ mBinder.startNetScan(map, binderListener);
+ } catch (ServiceSpecificException|RemoteException x) {
+ LowpanException.throwAsPublicException(x);
+ }
+ }
+
+ /**
+ * Stop a network scan currently in progress.
+ *
+ * @see #startNetScan
+ */
+ public void stopNetScan() {
+ try {
+ mBinder.stopNetScan();
+ } catch (RemoteException x) {
+ // Catch and ignore all binder exceptions
+ Log.e(TAG, x.toString());
+ }
+ }
+
+ /**
+ * Start an energy scan.
+ *
+ * <p>This method will return once the scan has started.
+ *
+ * @see #stopEnergyScan
+ */
+ public void startEnergyScan() throws LowpanException {
+ Map<String, Object> map = createScanOptionMap();
+
+ ILowpanEnergyScanCallback binderListener =
+ new ILowpanEnergyScanCallback.Stub() {
+ public void onEnergyScanResult(int channel, int rssi) {
+ Callback callback = mCallback;
+ Handler handler = mHandler;
+
+ if (callback == null) {
+ return;
+ }
+
+ Runnable runnable = () -> {
+ if (callback != null) {
+ LowpanEnergyScanResult result =
+ new LowpanEnergyScanResult();
+ result.setChannel(channel);
+ result.setMaxRssi(rssi);
+ callback.onEnergyScanResult(result);
+ }
+ };
+
+ if (handler != null) {
+ handler.post(runnable);
+ } else {
+ runnable.run();
+ }
+ }
+
+ public void onEnergyScanFinished() {
+ Callback callback = mCallback;
+ Handler handler = mHandler;
+
+ if (callback == null) {
+ return;
+ }
+
+ Runnable runnable = () -> callback.onScanFinished();
+
+ if (handler != null) {
+ handler.post(runnable);
+ } else {
+ runnable.run();
+ }
+ }
+ };
+
+ try {
+ mBinder.startEnergyScan(map, binderListener);
+ } catch (RemoteException x) {
+ LowpanException.throwAsPublicException(x);
+ } catch (ServiceSpecificException x) {
+ LowpanException.throwAsPublicException(x);
+ }
+ }
+
+ /**
+ * Stop an energy scan currently in progress.
+ *
+ * @see #startEnergyScan
+ */
+ public void stopEnergyScan() {
+ try {
+ mBinder.stopEnergyScan();
+ } catch (RemoteException x) {
+ // Catch and ignore all binder exceptions
+ Log.e(TAG, x.toString());
+ }
+ }
+}
diff --git a/lowpan/java/android/net/lowpan/package.html b/lowpan/java/android/net/lowpan/package.html
new file mode 100644
index 000000000000..342e32eefc1e
--- /dev/null
+++ b/lowpan/java/android/net/lowpan/package.html
@@ -0,0 +1,29 @@
+<HTML>
+<BODY>
+<p>@SystemApi</p>
+<!-- @hide -->
+<p>Provides classes to manage Low-power Wireless Personal Area Network (LoWPAN) functionality on the device.
+Examples of such network technologies include <a href="http://threadgroup.org/">Thread</a> and
+<a href="http://www.zigbee.org/zigbee-for-developers/network-specifications/zigbeeip/">ZigBee IP</a>.</p>
+<p>The LoWPAN APIs provide a means by which applications can communicate
+with the lower-level wireless stack that provides LoWPAN network access.</p>
+
+<p>Some APIs may require the following user permissions:</p>
+<ul>
+ <li>{@link android.Manifest.permission#ACCESS_LOWPAN_STATE}</li>
+ <li>{@link android.Manifest.permission#CHANGE_LOWPAN_STATE}</li>
+ <li>TBD</li>
+</ul>
+
+<p class="note"><strong>Note:</strong> Not all Android-powered devices provide LoWPAN functionality.
+If your application uses these APIs, declare so with a <a
+href="{@docRoot}guide/topics/manifest/uses-feature-element.html">{@code <uses-feature>}</a>
+element in the manifest file:</p>
+<pre>
+&lt;manifest ...>
+ &lt;uses-feature android:name="android.hardware.lowpan" />
+ ...
+&lt;/manifest>
+</pre>
+</BODY>
+</HTML>
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index 0b5dff227d23..20deeb1634c8 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -19,9 +19,11 @@ package android.media;
import android.Manifest;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
import android.annotation.SystemApi;
+import android.annotation.SystemService;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.bluetooth.BluetoothDevice;
@@ -58,10 +60,8 @@ import java.util.concurrent.ConcurrentHashMap;
/**
* AudioManager provides access to volume and ringer mode control.
- * <p>
- * Use <code>Context.getSystemService(Context.AUDIO_SERVICE)</code> to get
- * an instance of this class.
*/
+@SystemService(Context.AUDIO_SERVICE)
public class AudioManager {
private Context mOriginalContext;
@@ -2827,6 +2827,7 @@ public class AudioManager {
* {@link #SUCCESS} otherwise.
*/
@SystemApi
+ @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
public int registerAudioPolicy(@NonNull AudioPolicy policy) {
if (policy == null) {
throw new IllegalArgumentException("Illegal null AudioPolicy argument");
@@ -2852,6 +2853,7 @@ public class AudioManager {
* @param policy the non-null {@link AudioPolicy} to unregister.
*/
@SystemApi
+ @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
public void unregisterAudioPolicyAsync(@NonNull AudioPolicy policy) {
if (policy == null) {
throw new IllegalArgumentException("Illegal null AudioPolicy argument");
diff --git a/media/java/android/media/MediaHTTPConnection.java b/media/java/android/media/MediaHTTPConnection.java
index 228a6de6907c..dd731df0fbb0 100644
--- a/media/java/android/media/MediaHTTPConnection.java
+++ b/media/java/android/media/MediaHTTPConnection.java
@@ -136,7 +136,13 @@ public class MediaHTTPConnection extends IMediaHTTPConnection.Stub {
private void teardownConnection() {
if (mConnection != null) {
- mInputStream = null;
+ if (mInputStream != null) {
+ try {
+ mInputStream.close();
+ } catch (IOException e) {
+ }
+ mInputStream = null;
+ }
mConnection.disconnect();
mConnection = null;
@@ -298,8 +304,7 @@ public class MediaHTTPConnection extends IMediaHTTPConnection.Stub {
mCurrentOffset = offset;
} catch (IOException e) {
mTotalSize = -1;
- mInputStream = null;
- mConnection = null;
+ teardownConnection();
mCurrentOffset = -1;
throw e;
diff --git a/media/java/android/media/MediaRouter.java b/media/java/android/media/MediaRouter.java
index 87d8c64ead94..d5509c14e09b 100644
--- a/media/java/android/media/MediaRouter.java
+++ b/media/java/android/media/MediaRouter.java
@@ -20,6 +20,7 @@ import android.Manifest;
import android.annotation.DrawableRes;
import android.annotation.IntDef;
import android.annotation.NonNull;
+import android.annotation.SystemService;
import android.app.ActivityThread;
import android.content.BroadcastReceiver;
import android.content.Context;
@@ -61,6 +62,7 @@ import java.util.concurrent.CopyOnWriteArrayList;
* <p>The media router API is not thread-safe; all interactions with it must be
* done from the main thread of the process.</p>
*/
+@SystemService(Context.MEDIA_ROUTER_SERVICE)
public class MediaRouter {
private static final String TAG = "MediaRouter";
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
diff --git a/media/java/android/media/midi/MidiManager.java b/media/java/android/media/midi/MidiManager.java
index 07c8ae86adcf..a015732ddfdd 100644
--- a/media/java/android/media/midi/MidiManager.java
+++ b/media/java/android/media/midi/MidiManager.java
@@ -16,7 +16,9 @@
package android.media.midi;
+import android.annotation.SystemService;
import android.bluetooth.BluetoothDevice;
+import android.content.Context;
import android.os.Binder;
import android.os.IBinder;
import android.os.Bundle;
@@ -28,13 +30,8 @@ import java.util.concurrent.ConcurrentHashMap;
/**
* This class is the public application interface to the MIDI service.
- *
- * <p>You can obtain an instance of this class by calling
- * {@link android.content.Context#getSystemService(java.lang.String) Context.getSystemService()}.
- *
- * {@samplecode
- * MidiManager manager = (MidiManager) getSystemService(Context.MIDI_SERVICE);}
*/
+@SystemService(Context.MIDI_SERVICE)
public final class MidiManager {
private static final String TAG = "MidiManager";
diff --git a/media/java/android/media/projection/MediaProjectionManager.java b/media/java/android/media/projection/MediaProjectionManager.java
index f4a548bb5329..9f2c08e5c6ae 100644
--- a/media/java/android/media/projection/MediaProjectionManager.java
+++ b/media/java/android/media/projection/MediaProjectionManager.java
@@ -18,6 +18,7 @@ package android.media.projection;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.SystemService;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
@@ -33,14 +34,8 @@ import java.util.Map;
/**
* Manages the retrieval of certain types of {@link MediaProjection} tokens.
- *
- * <p>
- * Get an instance of this class by calling {@link
- * android.content.Context#getSystemService(java.lang.String)
- * Context.getSystemService()} with the argument {@link
- * android.content.Context#MEDIA_PROJECTION_SERVICE}.
- * </p>
*/
+@SystemService(Context.MEDIA_PROJECTION_SERVICE)
public final class MediaProjectionManager {
private static final String TAG = "MediaProjectionManager";
/** @hide */
diff --git a/media/java/android/media/session/MediaSessionManager.java b/media/java/android/media/session/MediaSessionManager.java
index 83793aeb2466..e02a4dcba9e4 100644
--- a/media/java/android/media/session/MediaSessionManager.java
+++ b/media/java/android/media/session/MediaSessionManager.java
@@ -18,7 +18,9 @@ package android.media.session;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
import android.annotation.SystemApi;
+import android.annotation.SystemService;
import android.content.ComponentName;
import android.content.Context;
import android.media.AudioManager;
@@ -42,13 +44,11 @@ import java.util.List;
* Provides support for interacting with {@link MediaSession media sessions}
* that applications have published to express their ongoing media playback
* state.
- * <p>
- * Use <code>Context.getSystemService(Context.MEDIA_SESSION_SERVICE)</code> to
- * get an instance of this class.
*
* @see MediaSession
* @see MediaController
*/
+@SystemService(Context.MEDIA_SESSION_SERVICE)
public final class MediaSessionManager {
private static final String TAG = "SessionManager";
@@ -357,6 +357,7 @@ public final class MediaSessionManager {
* @hide
*/
@SystemApi
+ @RequiresPermission(android.Manifest.permission.SET_VOLUME_KEY_LONG_PRESS_LISTENER)
public void setOnVolumeKeyLongPressListener(
OnVolumeKeyLongPressListener listener, @Nullable Handler handler) {
synchronized (mLock) {
@@ -392,6 +393,7 @@ public final class MediaSessionManager {
* @hide
*/
@SystemApi
+ @RequiresPermission(android.Manifest.permission.SET_MEDIA_KEY_LISTENER)
public void setOnMediaKeyListener(OnMediaKeyListener listener, @Nullable Handler handler) {
synchronized (mLock) {
try {
diff --git a/media/java/android/media/soundtrigger/SoundTriggerDetector.java b/media/java/android/media/soundtrigger/SoundTriggerDetector.java
index c091c84df657..7969ee757813 100644
--- a/media/java/android/media/soundtrigger/SoundTriggerDetector.java
+++ b/media/java/android/media/soundtrigger/SoundTriggerDetector.java
@@ -20,6 +20,7 @@ import static android.hardware.soundtrigger.SoundTrigger.STATUS_OK;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
import android.annotation.SystemApi;
import android.hardware.soundtrigger.IRecognitionStatusCallback;
import android.hardware.soundtrigger.SoundTrigger;
@@ -253,6 +254,7 @@ public final class SoundTriggerDetector {
* {@link Callback}.
* @return Indicates whether the call succeeded or not.
*/
+ @RequiresPermission(android.Manifest.permission.MANAGE_SOUND_TRIGGER)
public boolean startRecognition(@RecognitionFlags int recognitionFlags) {
if (DBG) {
Slog.d(TAG, "startRecognition()");
@@ -276,6 +278,7 @@ public final class SoundTriggerDetector {
/**
* Stops recognition for the associated model.
*/
+ @RequiresPermission(android.Manifest.permission.MANAGE_SOUND_TRIGGER)
public boolean stopRecognition() {
int status = STATUS_OK;
try {
diff --git a/media/java/android/media/soundtrigger/SoundTriggerManager.java b/media/java/android/media/soundtrigger/SoundTriggerManager.java
index fdd7fc2a8f19..7f8140adaed2 100644
--- a/media/java/android/media/soundtrigger/SoundTriggerManager.java
+++ b/media/java/android/media/soundtrigger/SoundTriggerManager.java
@@ -18,7 +18,9 @@ package android.media.soundtrigger;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
import android.annotation.SystemApi;
+import android.annotation.SystemService;
import android.content.Context;
import android.hardware.soundtrigger.SoundTrigger;
import android.os.Handler;
@@ -39,6 +41,7 @@ import java.util.UUID;
* @hide
*/
@SystemApi
+@SystemService(Context.SOUND_TRIGGER_SERVICE)
public final class SoundTriggerManager {
private static final boolean DBG = false;
private static final String TAG = "SoundTriggerManager";
@@ -65,6 +68,7 @@ public final class SoundTriggerManager {
/**
* Updates the given sound trigger model.
*/
+ @RequiresPermission(android.Manifest.permission.MANAGE_SOUND_TRIGGER)
public void updateModel(Model model) {
try {
mSoundTriggerService.updateSoundModel(model.getGenericSoundModel());
@@ -77,6 +81,7 @@ public final class SoundTriggerManager {
* Returns the sound trigger model represented by the given UUID. An instance of {@link Model}
* is returned.
*/
+ @RequiresPermission(android.Manifest.permission.MANAGE_SOUND_TRIGGER)
public Model getModel(UUID soundModelId) {
try {
return new Model(mSoundTriggerService.getSoundModel(
@@ -89,6 +94,7 @@ public final class SoundTriggerManager {
/**
* Deletes the sound model represented by the provided UUID.
*/
+ @RequiresPermission(android.Manifest.permission.MANAGE_SOUND_TRIGGER)
public void deleteModel(UUID soundModelId) {
try {
mSoundTriggerService.deleteSoundModel(new ParcelUuid(soundModelId));
@@ -110,6 +116,7 @@ public final class SoundTriggerManager {
* @return Instance of {@link SoundTriggerDetector} or null on error.
*/
@Nullable
+ @RequiresPermission(android.Manifest.permission.MANAGE_SOUND_TRIGGER)
public SoundTriggerDetector createSoundTriggerDetector(UUID soundModelId,
@NonNull SoundTriggerDetector.Callback callback, @Nullable Handler handler) {
if (soundModelId == null) {
diff --git a/media/java/android/media/tv/TvInputManager.java b/media/java/android/media/tv/TvInputManager.java
index 68ee02cab7a4..28fd338aabc7 100644
--- a/media/java/android/media/tv/TvInputManager.java
+++ b/media/java/android/media/tv/TvInputManager.java
@@ -21,6 +21,8 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
import android.annotation.SystemApi;
+import android.annotation.SystemService;
+import android.content.Context;
import android.content.Intent;
import android.graphics.Rect;
import android.media.PlaybackParams;
@@ -57,9 +59,7 @@ import java.util.Map;
/**
* Central system API to the overall TV input framework (TIF) architecture, which arbitrates
- * interaction between applications and the selected TV inputs. You can retrieve an instance of
- * this interface with {@link android.content.Context#getSystemService
- * Context.getSystemService(Context.TV_INPUT_SERVICE)}.
+ * interaction between applications and the selected TV inputs.
*
* <p>There are three primary parties involved in the TV input framework (TIF) architecture:
*
@@ -78,6 +78,7 @@ import java.util.Map;
* programs.
* </ul>
*/
+@SystemService(Context.TV_INPUT_SERVICE)
public final class TvInputManager {
private static final String TAG = "TvInputManager";
@@ -1516,6 +1517,7 @@ public final class TvInputManager {
* @hide
*/
@SystemApi
+ @RequiresPermission(android.Manifest.permission.CAPTURE_TV_INPUT)
public List<TvStreamConfig> getAvailableTvStreamConfigList(String inputId) {
try {
return mService.getAvailableTvStreamConfigList(inputId, mUserId);
@@ -1534,6 +1536,7 @@ public final class TvInputManager {
* @hide
*/
@SystemApi
+ @RequiresPermission(android.Manifest.permission.CAPTURE_TV_INPUT)
public boolean captureFrame(String inputId, Surface surface, TvStreamConfig config) {
try {
return mService.captureFrame(inputId, surface, config, mUserId);
diff --git a/packages/CarrierDefaultApp/res/values/strings.xml b/packages/CarrierDefaultApp/res/values/strings.xml
index fa5c3fff283f..65a7cecca20f 100644
--- a/packages/CarrierDefaultApp/res/values/strings.xml
+++ b/packages/CarrierDefaultApp/res/values/strings.xml
@@ -6,6 +6,8 @@
<string name="no_data_notification_id">Your mobile data has been deactivated</string>
<string name="portal_notification_detail">Tap to visit the %s website</string>
<string name="no_data_notification_detail">Please contact your service provider %s</string>
+ <string name="no_mobile_data_connection_title">No mobile data connection</string>
+ <string name="no_mobile_data_connection">Add data or roaming plan through %s</string>
<string name="mobile_data_status_notification_channel_name">Mobile data status</string>
<string name="action_bar_label">Sign in to mobile network</string>
<string name="ssl_error_warning">The network you&#8217;re trying to join has security issues.</string>
diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml
index 021b68bc9501..fd994b572981 100644
--- a/packages/SettingsLib/res/values/strings.xml
+++ b/packages/SettingsLib/res/values/strings.xml
@@ -64,6 +64,14 @@
<!-- Status for networks disabled from authentication failure (wrong password
or certificate). -->
<string name="wifi_disabled_password_failure">Authentication problem</string>
+
+ <!-- Status detail for a network that can't be connected to for some reason -->
+ <string name="wifi_cant_connect">Can\'t connect</string>
+ <!-- Status for a named network that can't be connected to for some reason-->
+ <string name="wifi_cant_connect_to_ap">Can\'t connect to \'<xliff:g id="ap_name">%1$s</xliff:g>\'</string>
+ <!-- Message shown when the user likely entered an incorrect password for a wifi network -->
+ <string name="wifi_check_password_try_again">Check password and try again</string>
+
<!-- Summary for the remembered network but currently not in range. -->
<string name="wifi_not_in_range">Not in range</string>
<!-- Summary for the network but no internet connection was detected. -->
@@ -94,7 +102,7 @@
<!-- Speed label for slow network speed -->
<string name="speed_label_slow">Slow</string>
<!-- Speed label for okay network speed -->
- <string name="speed_label_okay">Okay</string>
+ <string name="speed_label_okay">OK</string>
<!-- Speed label for medium network speed -->
<string name="speed_label_medium">Medium</string>
<!-- Speed label for fast network speed -->
diff --git a/packages/SettingsLib/src/com/android/settingslib/Utils.java b/packages/SettingsLib/src/com/android/settingslib/Utils.java
index 3135f1db957d..b21f2fa860b1 100644
--- a/packages/SettingsLib/src/com/android/settingslib/Utils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/Utils.java
@@ -21,6 +21,7 @@ import android.net.NetworkBadging;
import android.os.BatteryManager;
import android.os.UserManager;
import android.print.PrintManager;
+import android.provider.Settings;
import android.view.View;
import com.android.internal.util.UserIcons;
@@ -313,4 +314,20 @@ public class Utils {
"No badge resource found for badge value: " + badge);
}
}
+
+ public static int getDefaultStorageManagerDaysToRetain(Resources resources) {
+ int defaultDays = Settings.Secure.AUTOMATIC_STORAGE_MANAGER_DAYS_TO_RETAIN_DEFAULT;
+ try {
+ defaultDays =
+ resources.getInteger(
+ com.android
+ .internal
+ .R
+ .integer
+ .config_storageManagerDaystoRetainDefault);
+ } catch (Resources.NotFoundException e) {
+ // We are likely in a test environment.
+ }
+ return defaultDays;
+ }
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/applications/InterestingConfigChanges.java b/packages/SettingsLib/src/com/android/settingslib/applications/InterestingConfigChanges.java
index 82da9a38d756..e4e0f7f9e361 100644
--- a/packages/SettingsLib/src/com/android/settingslib/applications/InterestingConfigChanges.java
+++ b/packages/SettingsLib/src/com/android/settingslib/applications/InterestingConfigChanges.java
@@ -26,13 +26,13 @@ public class InterestingConfigChanges {
private int mLastDensity;
public InterestingConfigChanges() {
- this(0);
+ this(ActivityInfo.CONFIG_LOCALE
+ | ActivityInfo.CONFIG_UI_MODE | ActivityInfo.CONFIG_SCREEN_LAYOUT
+ | ActivityInfo.CONFIG_ASSETS_PATHS);
}
- public InterestingConfigChanges(int extraFlags) {
- mFlags = extraFlags | ActivityInfo.CONFIG_LOCALE
- | ActivityInfo.CONFIG_UI_MODE | ActivityInfo.CONFIG_SCREEN_LAYOUT
- | ActivityInfo.CONFIG_ASSETS_PATHS;
+ public InterestingConfigChanges(int flags) {
+ mFlags = flags;
}
public boolean applyNewConfig(Resources res) {
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
index c55280dc1c3e..0f9b2ff4d5f2 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
@@ -23,7 +23,6 @@ import android.content.pm.ApplicationInfo;
import android.content.pm.IPackageManager;
import android.content.pm.PackageManager;
import android.net.ConnectivityManager;
-import android.net.NetworkBadging;
import android.net.NetworkCapabilities;
import android.net.NetworkInfo;
import android.net.NetworkInfo.DetailedState;
@@ -83,6 +82,35 @@ public class AccessPoint implements Comparable<AccessPoint> {
*/
public static final int HIGHER_FREQ_5GHZ = 5900;
+ /**
+ * Constant value representing an unlabeled / unscored network.
+ */
+ @VisibleForTesting
+ static final int SPEED_NONE = 0;
+
+ /**
+ * Constant value representing a slow speed network connection.
+ */
+ @VisibleForTesting
+ static final int SPEED_SLOW = 5;
+
+ /**
+ * Constant value representing a medium speed network connection.
+ */
+ @VisibleForTesting
+ static final int SPEED_MEDIUM = 10;
+
+ /**
+ * Constant value representing a fast speed network connection.
+ */
+ @VisibleForTesting
+ static final int SPEED_FAST = 20;
+
+ /**
+ * Constant value representing a very fast speed network connection.
+ */
+ @VisibleForTesting
+ static final int SPEED_VERY_FAST = 30;
/**
* Experimental: we should be able to show the user the list of BSSIDs and bands
@@ -149,7 +177,7 @@ public class AccessPoint implements Comparable<AccessPoint> {
private Object mTag;
private int mRankingScore = Integer.MIN_VALUE;
- private int mBadge = NetworkBadging.BADGING_NONE;
+ private int mSpeed = AccessPoint.SPEED_NONE;
private boolean mIsScoredNetworkMetered = false;
// used to co-relate internal vs returned accesspoint.
@@ -249,7 +277,7 @@ public class AccessPoint implements Comparable<AccessPoint> {
this.mScanResultCache.clear();
this.mScanResultCache.putAll(that.mScanResultCache);
this.mId = that.mId;
- this.mBadge = that.mBadge;
+ this.mSpeed = that.mSpeed;
this.mIsScoredNetworkMetered = that.mIsScoredNetworkMetered;
this.mRankingScore = that.mRankingScore;
}
@@ -340,8 +368,8 @@ public class AccessPoint implements Comparable<AccessPoint> {
if (mRankingScore != Integer.MIN_VALUE) {
builder.append(",rankingScore=").append(mRankingScore);
}
- if (mBadge != NetworkBadging.BADGING_NONE) {
- builder.append(",badge=").append(mBadge);
+ if (mSpeed != SPEED_NONE) {
+ builder.append(",speed=").append(mSpeed);
}
builder.append(",metered=").append(isMetered());
@@ -349,7 +377,7 @@ public class AccessPoint implements Comparable<AccessPoint> {
}
/**
- * Updates the AccessPoint rankingScore, metering, and badge, returning true if the data has
+ * Updates the AccessPoint rankingScore, metering, and speed, returning true if the data has
* changed.
*
* @param scoreCache The score cache to use to retrieve scores.
@@ -364,14 +392,14 @@ public class AccessPoint implements Comparable<AccessPoint> {
}
/**
- * Updates the AccessPoint rankingScore and badge, returning true if the data has changed.
+ * Updates the AccessPoint rankingScore and speed, returning true if the data has changed.
*
* @param scoreCache The score cache to use to retrieve scores.
*/
private boolean updateScores(WifiNetworkScoreCache scoreCache) {
- int oldBadge = mBadge;
+ int oldSpeed = mSpeed;
int oldRankingScore = mRankingScore;
- mBadge = NetworkBadging.BADGING_NONE;
+ mSpeed = SPEED_NONE;
mRankingScore = Integer.MIN_VALUE;
for (ScanResult result : mScanResultCache.values()) {
@@ -383,10 +411,11 @@ public class AccessPoint implements Comparable<AccessPoint> {
if (score.hasRankingScore()) {
mRankingScore = Math.max(mRankingScore, score.calculateRankingScore(result.level));
}
- mBadge = Math.max(mBadge, score.calculateBadge(result.level));
+ // TODO(sghuman): Rename calculateBadge API
+ mSpeed = Math.max(mSpeed, score.calculateBadge(result.level));
}
- return (oldBadge != mBadge || oldRankingScore != mRankingScore);
+ return (oldSpeed != mSpeed || oldRankingScore != mRankingScore);
}
/**
@@ -643,7 +672,7 @@ public class AccessPoint implements Comparable<AccessPoint> {
// TODO(b/62354743): Standardize and international delimiter usage
final String concatenator = " / ";
- if (mBadge != NetworkBadging.BADGING_NONE) {
+ if (mSpeed != SPEED_NONE) {
summary.append(getSpeedLabel() + concatenator);
}
@@ -764,7 +793,7 @@ public class AccessPoint implements Comparable<AccessPoint> {
if (mRankingScore != Integer.MIN_VALUE) {
visibility.append(" rankingScore=").append(getRankingScore());
}
- if (mBadge != NetworkBadging.BADGING_NONE) {
+ if (mSpeed != SPEED_NONE) {
visibility.append(" speed=").append(getSpeedLabel());
}
visibility.append(String.format(" tx=%.1f,", mInfo.txSuccessRate));
@@ -1062,18 +1091,20 @@ public class AccessPoint implements Comparable<AccessPoint> {
return mRankingScore;
}
- int getBadge() { return mBadge;}
+ int getSpeed() { return mSpeed;}
@Nullable
String getSpeedLabel() {
- switch (mBadge) {
- case NetworkBadging.BADGING_4K:
+ switch (mSpeed) {
+ case SPEED_VERY_FAST:
return mContext.getString(R.string.speed_label_very_fast);
- case NetworkBadging.BADGING_HD:
+ case SPEED_FAST:
return mContext.getString(R.string.speed_label_fast);
- case NetworkBadging.BADGING_SD:
+ case SPEED_MEDIUM:
return mContext.getString(R.string.speed_label_okay);
- case NetworkBadging.BADGING_NONE:
+ case SPEED_SLOW:
+ return mContext.getString(R.string.speed_label_slow);
+ case SPEED_NONE:
default:
return null;
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPointPreference.java b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPointPreference.java
index f37590ec8c63..e7525f3edbc4 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPointPreference.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPointPreference.java
@@ -60,7 +60,7 @@ public class AccessPointPreference extends Preference {
private int mLevel;
private CharSequence mContentDescription;
private int mDefaultIconResId;
- private int mWifiBadge = NetworkBadging.BADGING_NONE;
+ private int mWifiSpeed = NetworkBadging.BADGING_NONE;
static final int[] WIFI_CONNECTION_STRENGTH = {
R.string.accessibility_no_wifi,
@@ -161,7 +161,7 @@ public class AccessPointPreference extends Preference {
safeSetDefaultIcon();
return;
}
- TronUtils.logWifiSettingsBadge(context, mWifiBadge);
+ TronUtils.logWifiSettingsBadge(context, mWifiSpeed);
// TODO(b/62355275): Revert this to N code after deleting NetworkBadging API
Drawable drawable = NetworkBadging.getWifiIcon(
@@ -223,10 +223,10 @@ public class AccessPointPreference extends Preference {
final Context context = getContext();
int level = mAccessPoint.getLevel();
- int wifiBadge = mAccessPoint.getBadge();
- if (level != mLevel || wifiBadge != mWifiBadge) {
+ int wifiSpeed = mAccessPoint.getSpeed();
+ if (level != mLevel || wifiSpeed != mWifiSpeed) {
mLevel = level;
- mWifiBadge = wifiBadge;
+ mWifiSpeed = wifiSpeed;
updateIcon(mLevel, context);
notifyChanged();
}
diff --git a/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/AccessPointTest.java b/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/AccessPointTest.java
index 9abdf88d42fb..72ac54421220 100644
--- a/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/AccessPointTest.java
+++ b/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/AccessPointTest.java
@@ -24,7 +24,6 @@ import static org.mockito.Mockito.when;
import android.content.Context;
import android.net.ConnectivityManager;
-import android.net.NetworkBadging;
import android.net.NetworkInfo;
import android.net.NetworkKey;
import android.net.RssiCurve;
@@ -330,57 +329,72 @@ public class AccessPointTest {
}
@Test
- public void testSpeedLabel_returnsVeryFastWhen4kBadgeIsSet() {
+ public void testSpeedLabel_returnsVeryFast() {
AccessPoint ap = createAccessPointWithScanResultCache();
when(mockWifiNetworkScoreCache.getScoredNetwork(any(ScanResult.class)))
.thenReturn(buildScoredNetworkWithMockBadgeCurve());
- when(mockBadgeCurve.lookupScore(anyInt())).thenReturn((byte) NetworkBadging.BADGING_4K);
+ when(mockBadgeCurve.lookupScore(anyInt())).thenReturn((byte) AccessPoint.SPEED_VERY_FAST);
ap.update(mockWifiNetworkScoreCache, true /* scoringUiEnabled */);
- assertThat(ap.getBadge()).isEqualTo(NetworkBadging.BADGING_4K);
+ assertThat(ap.getSpeed()).isEqualTo(AccessPoint.SPEED_VERY_FAST);
assertThat(ap.getSpeedLabel())
.isEqualTo(mContext.getString(R.string.speed_label_very_fast));
}
@Test
- public void testSpeedLabel_returnsFastWhenHdBadgeIsSet() {
+ public void testSpeedLabel_returnsFast() {
AccessPoint ap = createAccessPointWithScanResultCache();
when(mockWifiNetworkScoreCache.getScoredNetwork(any(ScanResult.class)))
.thenReturn(buildScoredNetworkWithMockBadgeCurve());
- when(mockBadgeCurve.lookupScore(anyInt())).thenReturn((byte) NetworkBadging.BADGING_HD);
+ when(mockBadgeCurve.lookupScore(anyInt())).thenReturn((byte) AccessPoint.SPEED_FAST);
ap.update(mockWifiNetworkScoreCache, true /* scoringUiEnabled */);
- assertThat(ap.getBadge()).isEqualTo(NetworkBadging.BADGING_HD);
+ assertThat(ap.getSpeed()).isEqualTo(AccessPoint.SPEED_FAST);
assertThat(ap.getSpeedLabel())
.isEqualTo(mContext.getString(R.string.speed_label_fast));
}
@Test
- public void testSpeedLabel_returnsOkayWhenSdBadgeIsSet() {
+ public void testSpeedLabel_returnsOkay() {
AccessPoint ap = createAccessPointWithScanResultCache();
when(mockWifiNetworkScoreCache.getScoredNetwork(any(ScanResult.class)))
.thenReturn(buildScoredNetworkWithMockBadgeCurve());
- when(mockBadgeCurve.lookupScore(anyInt())).thenReturn((byte) NetworkBadging.BADGING_SD);
+ when(mockBadgeCurve.lookupScore(anyInt())).thenReturn((byte) AccessPoint.SPEED_MEDIUM);
ap.update(mockWifiNetworkScoreCache, true /* scoringUiEnabled */);
- assertThat(ap.getBadge()).isEqualTo(NetworkBadging.BADGING_SD);
+ assertThat(ap.getSpeed()).isEqualTo(AccessPoint.SPEED_MEDIUM);
assertThat(ap.getSpeedLabel())
.isEqualTo(mContext.getString(R.string.speed_label_okay));
}
@Test
+ public void testSpeedLabel_returnsSlow() {
+ AccessPoint ap = createAccessPointWithScanResultCache();
+
+ when(mockWifiNetworkScoreCache.getScoredNetwork(any(ScanResult.class)))
+ .thenReturn(buildScoredNetworkWithMockBadgeCurve());
+ when(mockBadgeCurve.lookupScore(anyInt())).thenReturn((byte) AccessPoint.SPEED_SLOW);
+
+ ap.update(mockWifiNetworkScoreCache, true /* scoringUiEnabled */);
+
+ assertThat(ap.getSpeed()).isEqualTo(AccessPoint.SPEED_SLOW);
+ assertThat(ap.getSpeedLabel())
+ .isEqualTo(mContext.getString(R.string.speed_label_slow));
+ }
+
+ @Test
public void testSummaryString_showsSpeedLabel() {
AccessPoint ap = createAccessPointWithScanResultCache();
when(mockWifiNetworkScoreCache.getScoredNetwork(any(ScanResult.class)))
.thenReturn(buildScoredNetworkWithMockBadgeCurve());
- when(mockBadgeCurve.lookupScore(anyInt())).thenReturn((byte) NetworkBadging.BADGING_4K);
+ when(mockBadgeCurve.lookupScore(anyInt())).thenReturn((byte) AccessPoint.SPEED_VERY_FAST);
ap.update(mockWifiNetworkScoreCache, true /* scoringUiEnabled */);
@@ -394,7 +408,7 @@ public class AccessPointTest {
when(mockWifiNetworkScoreCache.getScoredNetwork(any(ScanResult.class)))
.thenReturn(buildScoredNetworkWithMockBadgeCurve());
- when(mockBadgeCurve.lookupScore(anyInt())).thenReturn((byte) NetworkBadging.BADGING_4K);
+ when(mockBadgeCurve.lookupScore(anyInt())).thenReturn((byte) AccessPoint.SPEED_VERY_FAST);
ap.update(mockWifiNetworkScoreCache, true /* scoringUiEnabled */);
diff --git a/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/WifiTrackerTest.java b/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/WifiTrackerTest.java
index 086e10cda499..46ea31993c38 100644
--- a/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/WifiTrackerTest.java
+++ b/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/WifiTrackerTest.java
@@ -37,7 +37,6 @@ import android.content.Context;
import android.content.Intent;
import android.net.ConnectivityManager;
import android.net.Network;
-import android.net.NetworkBadging;
import android.net.NetworkInfo;
import android.net.NetworkKey;
import android.net.NetworkScoreManager;
@@ -94,7 +93,7 @@ public class WifiTrackerTest {
new NetworkKey(new WifiKey('"' + SSID_1 + '"', BSSID_1));
private static final int RSSI_1 = -30;
private static final byte SCORE_1 = 10;
- private static final int BADGE_1 = NetworkBadging.BADGING_SD;
+ private static final int BADGE_1 = AccessPoint.SPEED_MEDIUM;
private static final String SSID_2 = "ssid2";
private static final String BSSID_2 = "AA:AA:AA:AA:AA:AA";
@@ -102,7 +101,7 @@ public class WifiTrackerTest {
new NetworkKey(new WifiKey('"' + SSID_2 + '"', BSSID_2));
private static final int RSSI_2 = -30;
private static final byte SCORE_2 = 15;
- private static final int BADGE_2 = NetworkBadging.BADGING_HD;
+ private static final int BADGE_2 = AccessPoint.SPEED_FAST;
private static final int CONNECTED_NETWORK_ID = 123;
private static final int CONNECTED_RSSI = -50;
@@ -511,7 +510,8 @@ public class WifiTrackerTest {
}
@Test
- public void scoreCacheUpdateScoresShouldInsertBadgeIntoAccessPoint() throws InterruptedException {
+ public void scoreCacheUpdateScoresShouldInsertSpeedIntoAccessPoint()
+ throws InterruptedException {
WifiTracker tracker = createTrackerWithImmediateBroadcastsAndInjectInitialScanResults();
updateScoresAndWaitForAccessPointsChangedCallback();
@@ -519,9 +519,9 @@ public class WifiTrackerTest {
for (AccessPoint ap : aps) {
if (ap.getSsidStr().equals(SSID_1)) {
- assertEquals(BADGE_1, ap.getBadge());
+ assertEquals(BADGE_1, ap.getSpeed());
} else if (ap.getSsidStr().equals(SSID_2)) {
- assertEquals(BADGE_2, ap.getBadge());
+ assertEquals(BADGE_2, ap.getSpeed());
}
}
}
@@ -544,7 +544,7 @@ public class WifiTrackerTest {
}
@Test
- public void noBadgesShouldBeInsertedIntoAccessPointWhenScoringUiDisabled()
+ public void noSpeedsShouldBeInsertedIntoAccessPointWhenScoringUiDisabled()
throws InterruptedException {
Settings.Global.putInt(
InstrumentationRegistry.getTargetContext().getContentResolver(),
@@ -558,9 +558,9 @@ public class WifiTrackerTest {
for (AccessPoint ap : aps) {
if (ap.getSsidStr().equals(SSID_1)) {
- assertEquals(NetworkBadging.BADGING_NONE, ap.getBadge());
+ assertEquals(AccessPoint.SPEED_NONE, ap.getSpeed());
} else if (ap.getSsidStr().equals(SSID_2)) {
- assertEquals(NetworkBadging.BADGING_NONE, ap.getBadge());
+ assertEquals(AccessPoint.SPEED_NONE, ap.getSpeed());
}
}
}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/UtilsTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/UtilsTest.java
index e42c35bc8d8b..0164f80e68f8 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/UtilsTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/UtilsTest.java
@@ -21,6 +21,12 @@ import org.robolectric.annotation.Config;
import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import android.content.res.Resources;
+
@RunWith(SettingLibRobolectricTestRunner.class)
@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
public class UtilsTest {
@@ -54,4 +60,18 @@ public class UtilsTest {
assertThat(percentage).isEqualTo(expectedPercentages[i]);
}
}
+
+ @Test
+ public void testStorageManagerDaysToRetainUsesResources() {
+ Resources resources = mock(Resources.class);
+ when(resources.getInteger(
+ eq(
+ com.android
+ .internal
+ .R
+ .integer
+ .config_storageManagerDaystoRetainDefault)))
+ .thenReturn(60);
+ assertThat(Utils.getDefaultStorageManagerDaysToRetain(resources)).isEqualTo(60);
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/Dependency.java b/packages/SystemUI/src/com/android/systemui/Dependency.java
index 5197c95ce884..73a2a43adb8f 100644
--- a/packages/SystemUI/src/com/android/systemui/Dependency.java
+++ b/packages/SystemUI/src/com/android/systemui/Dependency.java
@@ -272,6 +272,9 @@ public class Dependency extends SystemUI {
mProviders.put(TunablePaddingService.class, () -> new TunablePaddingService());
+ mProviders.put(ForegroundServiceController.class,
+ () -> new ForegroundServiceControllerImpl(mContext));
+
mProviders.put(UiOffloadThread.class, UiOffloadThread::new);
// Put all dependencies above here so the factory can override them if it wants.
diff --git a/packages/SystemUI/src/com/android/systemui/ForegroundServiceController.java b/packages/SystemUI/src/com/android/systemui/ForegroundServiceController.java
new file mode 100644
index 000000000000..a2c9ab4871c2
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/ForegroundServiceController.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the
+ * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+package com.android.systemui;
+
+import android.service.notification.StatusBarNotification;
+
+public interface ForegroundServiceController {
+ /**
+ * @param sbn notification that was just posted
+ * @param importance
+ */
+ void addNotification(StatusBarNotification sbn, int importance);
+
+ /**
+ * @param sbn notification that was just changed in some way
+ * @param newImportance
+ */
+ void updateNotification(StatusBarNotification sbn, int newImportance);
+
+ /**
+ * @param sbn notification that was just canceled
+ */
+ boolean removeNotification(StatusBarNotification sbn);
+
+ /**
+ * @param userId
+ * @return true if this user has services missing notifications and therefore needs a
+ * disclosure notification.
+ */
+ boolean isDungeonNeededForUser(int userId);
+
+ /**
+ * @param sbn
+ * @return true if sbn is the system-provided "dungeon" (list of running foreground services).
+ */
+ boolean isDungeonNotification(StatusBarNotification sbn);
+}
diff --git a/packages/SystemUI/src/com/android/systemui/ForegroundServiceControllerImpl.java b/packages/SystemUI/src/com/android/systemui/ForegroundServiceControllerImpl.java
new file mode 100644
index 000000000000..c930d567254a
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/ForegroundServiceControllerImpl.java
@@ -0,0 +1,156 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the
+ * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+package com.android.systemui;
+
+import android.app.Notification;
+import android.app.NotificationManager;
+import android.content.Context;
+import android.os.Bundle;
+import android.service.notification.StatusBarNotification;
+import android.util.ArrayMap;
+import android.util.ArraySet;
+import android.util.Log;
+import android.util.SparseArray;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.messages.nano.SystemMessageProto;
+
+import java.util.Arrays;
+
+/**
+ * Foreground service controller, a/k/a Dianne's Dungeon.
+ */
+public class ForegroundServiceControllerImpl
+ implements ForegroundServiceController {
+ private static final String TAG = "FgServiceController";
+ private static final boolean DBG = false;
+
+ private final SparseArray<UserServices> mUserServices = new SparseArray<>();
+ private final Object mMutex = new Object();
+
+ public ForegroundServiceControllerImpl(Context context) {
+ }
+
+ @Override
+ public boolean isDungeonNeededForUser(int userId) {
+ synchronized (mMutex) {
+ final UserServices services = mUserServices.get(userId);
+ if (services == null) return false;
+ return services.isDungeonNeeded();
+ }
+ }
+
+ @Override
+ public void addNotification(StatusBarNotification sbn, int importance) {
+ updateNotification(sbn, importance);
+ }
+
+ @Override
+ public boolean removeNotification(StatusBarNotification sbn) {
+ synchronized (mMutex) {
+ final UserServices userServices = mUserServices.get(sbn.getUserId());
+ if (userServices == null) {
+ if (DBG) {
+ Log.w(TAG, String.format(
+ "user %d with no known notifications got removeNotification for %s",
+ sbn.getUserId(), sbn));
+ }
+ return false;
+ }
+ if (isDungeonNotification(sbn)) {
+ // if you remove the dungeon entirely, we take that to mean there are
+ // no running services
+ userServices.setRunningServices(null);
+ return true;
+ } else {
+ // this is safe to call on any notification, not just FLAG_FOREGROUND_SERVICE
+ return userServices.removeNotification(sbn.getPackageName(), sbn.getKey());
+ }
+ }
+ }
+
+ @Override
+ public void updateNotification(StatusBarNotification sbn, int newImportance) {
+ synchronized (mMutex) {
+ UserServices userServices = mUserServices.get(sbn.getUserId());
+ if (userServices == null) {
+ userServices = new UserServices();
+ mUserServices.put(sbn.getUserId(), userServices);
+ }
+
+ if (isDungeonNotification(sbn)) {
+ final Bundle extras = sbn.getNotification().extras;
+ if (extras != null) {
+ final String[] svcs = extras.getStringArray(Notification.EXTRA_FOREGROUND_APPS);
+ userServices.setRunningServices(svcs); // null ok
+ }
+ } else {
+ userServices.removeNotification(sbn.getPackageName(), sbn.getKey());
+ if (0 != (sbn.getNotification().flags & Notification.FLAG_FOREGROUND_SERVICE)
+ && newImportance > NotificationManager.IMPORTANCE_MIN) {
+ userServices.addNotification(sbn.getPackageName(), sbn.getKey());
+ }
+ }
+ }
+ }
+
+ @Override
+ public boolean isDungeonNotification(StatusBarNotification sbn) {
+ return sbn.getId() == SystemMessageProto.SystemMessage.NOTE_FOREGROUND_SERVICES
+ && sbn.getTag() == null
+ && sbn.getPackageName().equals("android");
+ }
+
+ /**
+ * Struct to track relevant packages and notifications for a userid's foreground services.
+ */
+ private static class UserServices {
+ private String[] mRunning = null;
+ private ArrayMap<String, ArraySet<String>> mNotifications = new ArrayMap<>(1);
+ public void setRunningServices(String[] pkgs) {
+ mRunning = pkgs != null ? Arrays.copyOf(pkgs, pkgs.length) : null;
+ }
+ public void addNotification(String pkg, String key) {
+ if (mNotifications.get(pkg) == null) {
+ mNotifications.put(pkg, new ArraySet<String>());
+ }
+ mNotifications.get(pkg).add(key);
+ }
+ public boolean removeNotification(String pkg, String key) {
+ final boolean found;
+ final ArraySet<String> keys = mNotifications.get(pkg);
+ if (keys == null) {
+ found = false;
+ } else {
+ found = keys.remove(key);
+ if (keys.size() == 0) {
+ mNotifications.remove(pkg);
+ }
+ }
+ return found;
+ }
+ public boolean isDungeonNeeded() {
+ if (mRunning != null) {
+ for (String pkg : mRunning) {
+ final ArraySet<String> set = mNotifications.get(pkg);
+ if (set == null || set.size() == 0) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java b/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java
index 09fdf5acf032..3b81cc4801c2 100644
--- a/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java
+++ b/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java
@@ -92,7 +92,9 @@ public class AssistManager implements ConfigurationChangedReceiver {
mAssistDisclosure = new AssistDisclosure(context, new Handler());
registerVoiceInteractionSessionListener();
- mInterestingConfigChanges = new InterestingConfigChanges(ActivityInfo.CONFIG_ORIENTATION);
+ mInterestingConfigChanges = new InterestingConfigChanges(ActivityInfo.CONFIG_ORIENTATION
+ | ActivityInfo.CONFIG_LOCALE | ActivityInfo.CONFIG_UI_MODE
+ | ActivityInfo.CONFIG_SCREEN_LAYOUT | ActivityInfo.CONFIG_ASSETS_PATHS);
onConfigurationChanged(context.getResources().getConfiguration());
}
diff --git a/packages/SystemUI/src/com/android/systemui/fragments/FragmentHostManager.java b/packages/SystemUI/src/com/android/systemui/fragments/FragmentHostManager.java
index 4dbf6f98e3e6..871f113ac95e 100644
--- a/packages/SystemUI/src/com/android/systemui/fragments/FragmentHostManager.java
+++ b/packages/SystemUI/src/com/android/systemui/fragments/FragmentHostManager.java
@@ -50,7 +50,8 @@ public class FragmentHostManager {
private final HashMap<String, ArrayList<FragmentListener>> mListeners = new HashMap<>();
private final View mRootView;
private final InterestingConfigChanges mConfigChanges = new InterestingConfigChanges(
- ActivityInfo.CONFIG_FONT_SCALE);
+ ActivityInfo.CONFIG_FONT_SCALE | ActivityInfo.CONFIG_LOCALE
+ | ActivityInfo.CONFIG_SCREEN_LAYOUT | ActivityInfo.CONFIG_ASSETS_PATHS);
private final FragmentService mManager;
private final ExtensionFragmentManager mPlugins = new ExtensionFragmentManager();
diff --git a/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java b/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java
index 5414aad0a63f..f98310dd7aa1 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java
@@ -239,7 +239,11 @@ public class PipManager implements BasePipManager {
}
}
- loadConfigurationsAndApply(mContext.getResources().getConfiguration());
+ // Initialize the last orientation and apply the current configuration
+ Configuration initialConfig = mContext.getResources().getConfiguration();
+ mLastOrientation = initialConfig.orientation;
+ loadConfigurationsAndApply(initialConfig);
+
mMediaSessionManager =
(MediaSessionManager) mContext.getSystemService(Context.MEDIA_SESSION_SERVICE);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFooter.java b/packages/SystemUI/src/com/android/systemui/qs/QSFooter.java
index 682c56c0ef24..488fc03032fd 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFooter.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFooter.java
@@ -18,12 +18,14 @@ package com.android.systemui.qs;
import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.ACTION_QS_DATE;
+import android.app.ActivityManager;
import android.app.AlarmManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.content.res.Configuration;
import android.content.res.Resources;
+import android.graphics.PorterDuff.Mode;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.RippleDrawable;
import android.os.UserManager;
@@ -42,6 +44,7 @@ import android.widget.Toast;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto;
import com.android.keyguard.KeyguardStatusView;
+import com.android.settingslib.Utils;
import com.android.systemui.Dependency;
import com.android.systemui.FontSizeUtils;
import com.android.systemui.R;
@@ -423,6 +426,13 @@ public class QSFooter extends FrameLayout implements
@Override
public void onUserInfoChanged(String name, Drawable picture, String userAccount) {
+ if (picture != null &&
+ UserManager.get(mContext).isGuestUser(ActivityManager.getCurrentUser())) {
+ picture = picture.getConstantState().newDrawable().mutate();
+ picture.setColorFilter(
+ Utils.getColorAttr(mContext, android.R.attr.colorForeground),
+ Mode.SRC_IN);
+ }
mMultiUserAvatar.setImageDrawable(picture);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java
index d12b16b77ae5..672f2c2df06e 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java
@@ -317,7 +317,9 @@ public abstract class QSTileImpl<TState extends State> implements QSTile {
protected abstract void setListening(boolean listening);
protected void handleDestroy() {
- setListening(false);
+ if (mListeners.size() != 0) {
+ setListening(false);
+ }
mCallbacks.clear();
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/AnimationProps.java b/packages/SystemUI/src/com/android/systemui/recents/views/AnimationProps.java
index 5e87e2a75c80..716d1bcf78c2 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/AnimationProps.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/AnimationProps.java
@@ -54,7 +54,6 @@ public class AnimationProps {
public static final int FOCUS_STATE = 8;
private SparseLongArray mPropStartDelay;
- private SparseLongArray mPropInitialPlayTime;
private SparseLongArray mPropDuration;
private SparseArray<Interpolator> mPropInterpolators;
private Animator.AnimatorListener mListener;
@@ -122,10 +121,6 @@ public class AnimationProps {
animator.setStartDelay(getStartDelay(propertyType));
animator.setDuration(getDuration(propertyType));
animator.setInterpolator(getInterpolator(propertyType));
- long initialPlayTime = getInitialPlayTime(propertyType);
- if (initialPlayTime != 0) {
- animator.setCurrentPlayTime(initialPlayTime);
- }
return animator;
}
@@ -141,17 +136,6 @@ public class AnimationProps {
}
/**
- * Sets a initial play time for a specific property.
- */
- public AnimationProps setInitialPlayTime(@PropType int propertyType, int initialPlayTime) {
- if (mPropInitialPlayTime == null) {
- mPropInitialPlayTime = new SparseLongArray();
- }
- mPropInitialPlayTime.append(propertyType, initialPlayTime);
- return this;
- }
-
- /**
* Returns the start delay for a specific property.
*/
public long getStartDelay(@PropType int propertyType) {
@@ -217,20 +201,6 @@ public class AnimationProps {
}
/**
- * Returns the initial play time for a specific property, falling back to the general initial
- * play time if there is no specific property interpolator.
- */
- public long getInitialPlayTime(@PropType int propertyType) {
- if (mPropInitialPlayTime != null) {
- if (mPropInitialPlayTime.indexOfKey(propertyType) != -1) {
- return mPropInitialPlayTime.get(propertyType);
- }
- return mPropInitialPlayTime.get(ALL, 0);
- }
- return 0;
- }
-
- /**
* Sets an animator listener for this animation.
*/
public AnimationProps setListener(Animator.AnimatorListener listener) {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsEntrancePathInterpolator.java b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsEntrancePathInterpolator.java
new file mode 100644
index 000000000000..e32da2d3f6be
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsEntrancePathInterpolator.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.recents.views;
+
+import android.view.animation.PathInterpolator;
+
+/**
+ * A helper interpolator to stagger the entrance animation in recents by offsetting the start time
+ */
+public class RecentsEntrancePathInterpolator extends PathInterpolator {
+ final float mStartOffsetFraction;
+
+ /**
+ * Create an interpolator for a cubic Bezier curve with an offset play time. The end points
+ * <code>(0, 0)</code> and <code>(1, 1)</code> are assumed.
+ *
+ * @param controlX1 The x coordinate of the first control point of the cubic Bezier.
+ * @param controlY1 The y coordinate of the first control point of the cubic Bezier.
+ * @param controlX2 The x coordinate of the second control point of the cubic Bezier.
+ * @param controlY2 The y coordinate of the second control point of the cubic Bezier.
+ * @param startOffsetFraction The fraction from 0 to 1 to start the animation from
+ */
+ public RecentsEntrancePathInterpolator(float controlX1, float controlY1, float controlX2,
+ float controlY2, float startOffsetFraction) {
+ super(controlX1, controlY1, controlX2, controlY2);
+ mStartOffsetFraction = startOffsetFraction;
+ }
+
+ @Override
+ public float getInterpolation(float t) {
+ return super.getInterpolation(t + mStartOffsetFraction);
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackAnimationHelper.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackAnimationHelper.java
index f1314aba1b46..0fc68e6a96ce 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackAnimationHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackAnimationHelper.java
@@ -82,8 +82,6 @@ public class TaskStackAnimationHelper {
private static final int ENTER_FROM_HOME_ALPHA_DURATION = 100;
public static final int ENTER_FROM_HOME_TRANSLATION_DURATION = 300;
- private static final Interpolator ENTER_FROM_HOME_TRANSLATION_INTERPOLATOR =
- Interpolators.LINEAR_OUT_SLOW_IN;
private static final Interpolator ENTER_FROM_HOME_ALPHA_INTERPOLATOR = Interpolators.LINEAR;
public static final int EXIT_TO_HOME_TRANSLATION_DURATION = 200;
@@ -260,17 +258,18 @@ public class TaskStackAnimationHelper {
} else if (launchState.launchedFromHome) {
// Animate the tasks up, but offset the animations to be relative to the front-most
// task animation
+ final float startOffsetFraction = (float) (Math.min(ENTER_EXIT_NUM_ANIMATING_TASKS,
+ taskIndexFromFront) * mEnterAndExitFromHomeTranslationOffset) /
+ ENTER_FROM_HOME_TRANSLATION_DURATION;
AnimationProps taskAnimation = new AnimationProps()
- .setInitialPlayTime(AnimationProps.BOUNDS,
- Math.min(ENTER_EXIT_NUM_ANIMATING_TASKS, taskIndexFromFront) *
- mEnterAndExitFromHomeTranslationOffset)
.setStartDelay(AnimationProps.ALPHA,
Math.min(ENTER_EXIT_NUM_ANIMATING_TASKS, taskIndexFromFront) *
FRAME_OFFSET_MS)
.setDuration(AnimationProps.BOUNDS, ENTER_FROM_HOME_TRANSLATION_DURATION)
.setDuration(AnimationProps.ALPHA, ENTER_FROM_HOME_ALPHA_DURATION)
.setInterpolator(AnimationProps.BOUNDS,
- ENTER_FROM_HOME_TRANSLATION_INTERPOLATOR)
+ new RecentsEntrancePathInterpolator(0f, 0f, 0.2f, 1f,
+ startOffsetFraction))
.setInterpolator(AnimationProps.ALPHA, ENTER_FROM_HOME_ALPHA_INTERPOLATOR)
.setListener(postAnimationTrigger.decrementOnAnimationEnd());
postAnimationTrigger.increment();
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java b/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java
index f750815d663f..4022718865e0 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java
@@ -91,6 +91,9 @@ public class Divider extends SystemUI {
}
private void removeDivider() {
+ if (mView != null) {
+ mView.onDividerRemoved();
+ }
mWindowManager.remove();
}
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
index 2bda1dfb5f88..09f459b0b07b 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
@@ -162,6 +162,9 @@ public class DividerView extends FrameLayout implements OnTouchListener,
private DividerState mState;
private final SurfaceFlingerVsyncChoreographer mSfChoreographer;
+ // The view is removed or in the process of been removed from the system.
+ private boolean mRemoved;
+
private final Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
@@ -323,6 +326,11 @@ public class DividerView extends FrameLayout implements OnTouchListener,
EventBus.getDefault().unregister(this);
}
+ void onDividerRemoved() {
+ mRemoved = true;
+ mHandler.removeMessages(MSG_RESIZE_STACK);
+ }
+
@Override
public WindowInsets onApplyWindowInsets(WindowInsets insets) {
if (mStableInsets.left != insets.getStableInsetLeft()
@@ -927,6 +935,10 @@ public class DividerView extends FrameLayout implements OnTouchListener,
}
public void resizeStack(int position, int taskPosition, SnapTarget taskSnapTarget) {
+ if (mRemoved) {
+ // This divider view has been removed so shouldn't have any additional influence.
+ return;
+ }
calculateBoundsForPosition(position, mDockSide, mDockedRect);
if (mDockedRect.equals(mLastResizeRect) && !mEntranceAnimationRunning) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
index 7f2f5f62add6..c445c0dd7787 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
@@ -369,15 +369,21 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
updateShelfIconColor();
}
- private void updateShelfIconColor() {
+ @VisibleForTesting
+ void updateShelfIconColor() {
StatusBarIconView expandedIcon = mEntry.expandedIcon;
boolean isPreL = Boolean.TRUE.equals(expandedIcon.getTag(R.id.icon_is_pre_L));
boolean colorize = !isPreL || NotificationUtils.isGrayscale(expandedIcon,
NotificationColorUtil.getInstance(mContext));
int color = StatusBarIconView.NO_COLOR;
if (colorize) {
- color = mEntry.getContrastedColor(mContext, mIsLowPriority && !isExpanded(),
- getBackgroundColorWithoutTint());
+ NotificationHeaderView header = getVisibleNotificationHeader();
+ if (header != null) {
+ color = header.getOriginalIconColor();
+ } else {
+ color = mEntry.getContrastedColor(mContext, mIsLowPriority && !isExpanded(),
+ getBackgroundColorWithoutTint());
+ }
}
expandedIcon.setStaticDrawableColor(color);
}
@@ -1770,6 +1776,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
NotificationContentView showingLayout = getShowingLayout();
showingLayout.updateBackgroundColor(animated);
mPrivateLayout.updateExpandButtons(isExpandable());
+ updateShelfIconColor();
showingLayout.setDark(isDark(), false /* animate */, 0 /* delay */);
mShowingPublicInitialized = true;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java
index 1844946e75b6..531437dff492 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java
@@ -24,6 +24,8 @@ import android.content.pm.IPackageManager;
import android.content.pm.PackageManager;
import android.content.Context;
import android.graphics.drawable.Icon;
+import android.os.AsyncTask;
+import android.os.Bundle;
import android.os.RemoteException;
import android.os.SystemClock;
import android.service.notification.NotificationListenerService;
@@ -38,8 +40,11 @@ import android.widget.RemoteViews;
import android.Manifest;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.messages.nano.SystemMessageProto;
import com.android.internal.statusbar.StatusBarIcon;
import com.android.internal.util.NotificationColorUtil;
+import com.android.systemui.Dependency;
+import com.android.systemui.ForegroundServiceController;
import com.android.systemui.statusbar.notification.InflationException;
import com.android.systemui.statusbar.phone.NotificationGroupManager;
import com.android.systemui.statusbar.phone.StatusBar;
@@ -339,6 +344,7 @@ public class NotificationData {
mEntries.put(entry.notification.getKey(), entry);
}
mGroupManager.onEntryAdded(entry);
+
updateRankingAndSort(mRankingMap);
}
@@ -466,6 +472,10 @@ public class NotificationData {
Collections.sort(mSortedAndFiltered, mRankingComparator);
}
+ /**
+ * @param sbn
+ * @return true if this notification should NOT be shown right now
+ */
public boolean shouldFilterOut(StatusBarNotification sbn) {
if (!(mEnvironment.isDeviceProvisioned() ||
showNotificationEvenIfUnprovisioned(sbn))) {
@@ -487,6 +497,13 @@ public class NotificationData {
&& mGroupManager.isChildInGroupWithSummary(sbn)) {
return true;
}
+
+ final ForegroundServiceController fsc = Dependency.get(ForegroundServiceController.class);
+ if (fsc.isDungeonNotification(sbn) && !fsc.isDungeonNeededForUser(sbn.getUserId())) {
+ // this is a foreground-service disclosure for a user that does not need to show one
+ return true;
+ }
+
return false;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
index 14374b7ad787..3f1f82c6cd52 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
@@ -466,9 +466,8 @@ public class NotificationShelf extends ActivatableNotificationView implements
}
int shelfColor = icon.getStaticDrawableColor();
if (!noIcon && shelfColor != StatusBarIconView.NO_COLOR) {
- int notificationColor
- = row.getVisibleNotificationHeader().getOriginalNotificationColor();
- shelfColor = NotificationUtils.interpolateColors(notificationColor, shelfColor,
+ int iconColor = row.getVisibleNotificationHeader().getOriginalIconColor();
+ shelfColor = NotificationUtils.interpolateColors(iconColor, shelfColor,
iconState.iconAppearAmount);
}
iconState.iconColor = shelfColor;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
index 6b30991164fa..fbad937d8481 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
@@ -45,7 +45,6 @@ import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
-import android.os.PowerManager;
import android.os.RemoteException;
import android.os.UserHandle;
import android.provider.Settings;
@@ -202,8 +201,7 @@ public class NavigationBarFragment extends Fragment implements Callbacks {
IntentFilter filter = new IntentFilter(Intent.ACTION_SCREEN_OFF);
filter.addAction(Intent.ACTION_SCREEN_ON);
getContext().registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL, filter, null, null);
- PowerManager pm = getContext().getSystemService(PowerManager.class);
- notifyNavigationBarScreenOn(pm.isScreenOn());
+ notifyNavigationBarScreenOn();
}
@Override
@@ -378,8 +376,8 @@ public class NavigationBarFragment extends Fragment implements Callbacks {
((View) mNavigationBarView.getParent()).getLayoutParams());
}
- private void notifyNavigationBarScreenOn(boolean screenOn) {
- mNavigationBarView.notifyScreenOn(screenOn);
+ private void notifyNavigationBarScreenOn() {
+ mNavigationBarView.notifyScreenOn();
}
private void prepareNavigationBarView() {
@@ -604,10 +602,6 @@ public class NavigationBarFragment extends Fragment implements Callbacks {
return mNavigationBarMode == MODE_SEMI_TRANSPARENT;
}
- public void onKeyguardOccludedChanged(boolean keyguardOccluded) {
- mNavigationBarView.onKeyguardOccludedChanged(keyguardOccluded);
- }
-
public void disableAnimationsDuringHide(long delay) {
mNavigationBarView.setLayoutTransitionsEnabled(false);
mNavigationBarView.postDelayed(() -> mNavigationBarView.setLayoutTransitionsEnabled(true),
@@ -663,10 +657,9 @@ public class NavigationBarFragment extends Fragment implements Callbacks {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
- if (Intent.ACTION_SCREEN_OFF.equals(action)) {
- notifyNavigationBarScreenOn(false);
- } else if (Intent.ACTION_SCREEN_ON.equals(action)) {
- notifyNavigationBarScreenOn(true);
+ if (Intent.ACTION_SCREEN_OFF.equals(action)
+ || Intent.ACTION_SCREEN_ON.equals(action)) {
+ notifyNavigationBarScreenOn();
}
}
};
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
index 8d9d4610f1d4..cb3222d6d287 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
@@ -74,7 +74,6 @@ public class NavigationBarView extends FrameLayout implements PluginListener<Nav
View[] mRotatedViews = new View[4];
boolean mVertical;
- boolean mScreenOn;
private int mCurrentRotation = -1;
boolean mShowMenu;
@@ -367,8 +366,7 @@ public class NavigationBarView extends FrameLayout implements PluginListener<Nav
super.setLayoutDirection(layoutDirection);
}
- public void notifyScreenOn(boolean screenOn) {
- mScreenOn = screenOn;
+ public void notifyScreenOn() {
setDisabledFlags(mDisabledFlags, true);
}
@@ -634,9 +632,6 @@ public class NavigationBarView extends FrameLayout implements PluginListener<Nav
getHomeButton().setVertical(mVertical);
}
- public void onKeyguardOccludedChanged(boolean keyguardOccluded) {
- }
-
private void updateTaskSwitchHelper() {
if (mGestureHelper == null) return;
boolean isRtl = (getLayoutDirection() == View.LAYOUT_DIRECTION_RTL);
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 3326b3f581d7..a3c6e96f606b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -99,14 +99,11 @@ import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.SystemClock;
import android.os.SystemProperties;
-import android.os.SystemService;
import android.os.Trace;
import android.os.UserHandle;
import android.os.UserManager;
import android.os.Vibrator;
import android.provider.Settings;
-import android.service.dreams.DreamService;
-import android.service.dreams.IDreamManager;
import android.service.notification.NotificationListenerService;
import android.service.notification.NotificationListenerService.RankingMap;
import android.service.notification.StatusBarNotification;
@@ -120,7 +117,6 @@ import android.util.Log;
import android.util.Slog;
import android.util.SparseArray;
import android.util.SparseBooleanArray;
-import android.view.ContextThemeWrapper;
import android.view.Display;
import android.view.IWindowManager;
import android.view.KeyEvent;
@@ -161,6 +157,7 @@ import com.android.systemui.DejankUtils;
import com.android.systemui.DemoMode;
import com.android.systemui.Dependency;
import com.android.systemui.EventLogTags;
+import com.android.systemui.ForegroundServiceController;
import com.android.systemui.Interpolators;
import com.android.systemui.Prefs;
import com.android.systemui.R;
@@ -486,6 +483,7 @@ public class StatusBar extends SystemUI implements DemoMode,
int mSystemUiVisibility = View.SYSTEM_UI_FLAG_VISIBLE;
private final Rect mLastFullscreenStackBounds = new Rect();
private final Rect mLastDockedStackBounds = new Rect();
+ private final Rect mTmpRect = new Rect();
// last value sent to window manager
private int mLastDispatchedSystemUiVisibility = ~View.SYSTEM_UI_FLAG_VISIBLE;
@@ -736,6 +734,7 @@ public class StatusBar extends SystemUI implements DemoMode,
private boolean mClearAllEnabled;
@Nullable private View mAmbientIndicationContainer;
private ColorExtractor mColorExtractor;
+ private ForegroundServiceController mForegroundServiceController;
private void recycleAllVisibilityObjects(ArraySet<NotificationVisibility> array) {
final int N = array.size();
@@ -785,6 +784,9 @@ public class StatusBar extends SystemUI implements DemoMode,
mColorExtractor.addOnColorsChangedListener(this);
mWindowManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
+
+ mForegroundServiceController = Dependency.get(ForegroundServiceController.class);
+
mDisplay = mWindowManager.getDefaultDisplay();
updateDisplaySize();
@@ -1412,20 +1414,33 @@ public class StatusBar extends SystemUI implements DemoMode,
int numChildren = mStackScroller.getChildCount();
final ArrayList<View> viewsToHide = new ArrayList<View>(numChildren);
+ final ArrayList<ExpandableNotificationRow> viewsToRemove = new ArrayList<>(numChildren);
for (int i = 0; i < numChildren; i++) {
final View child = mStackScroller.getChildAt(i);
if (child instanceof ExpandableNotificationRow) {
+ ExpandableNotificationRow row = (ExpandableNotificationRow) child;
+ boolean parentVisible = false;
+ boolean hasClipBounds = child.getClipBounds(mTmpRect);
if (mStackScroller.canChildBeDismissed(child)) {
- if (child.getVisibility() == View.VISIBLE) {
+ viewsToRemove.add(row);
+ if (child.getVisibility() == View.VISIBLE
+ && (!hasClipBounds || mTmpRect.height() > 0)) {
viewsToHide.add(child);
+ parentVisible = true;
}
+ } else if (child.getVisibility() == View.VISIBLE
+ && (!hasClipBounds || mTmpRect.height() > 0)) {
+ parentVisible = true;
}
- ExpandableNotificationRow row = (ExpandableNotificationRow) child;
List<ExpandableNotificationRow> children = row.getNotificationChildren();
- if (row.areChildrenExpanded() && children != null) {
+ if (children != null) {
for (ExpandableNotificationRow childRow : children) {
- if (mStackScroller.canChildBeDismissed(childRow)) {
- if (childRow.getVisibility() == View.VISIBLE) {
+ viewsToRemove.add(childRow);
+ if (parentVisible && row.areChildrenExpanded()
+ && mStackScroller.canChildBeDismissed(childRow)) {
+ hasClipBounds = childRow.getClipBounds(mTmpRect);
+ if (childRow.getVisibility() == View.VISIBLE
+ && (!hasClipBounds || mTmpRect.height() > 0)) {
viewsToHide.add(childRow);
}
}
@@ -1433,7 +1448,7 @@ public class StatusBar extends SystemUI implements DemoMode,
}
}
}
- if (viewsToHide.isEmpty()) {
+ if (viewsToRemove.isEmpty()) {
animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_NONE);
return;
}
@@ -1442,6 +1457,13 @@ public class StatusBar extends SystemUI implements DemoMode,
@Override
public void run() {
mStackScroller.setDismissAllInProgress(false);
+ for (ExpandableNotificationRow rowToRemove : viewsToRemove) {
+ if (mStackScroller.canChildBeDismissed(rowToRemove)) {
+ removeNotification(rowToRemove.getEntry().key, null);
+ } else {
+ rowToRemove.resetTranslation();
+ }
+ }
try {
mBarService.onClearAllNotifications(mCurrentUserId);
} catch (Exception ex) { }
@@ -1618,6 +1640,10 @@ public class StatusBar extends SystemUI implements DemoMode,
}
}
abortExistingInflation(key);
+
+ mForegroundServiceController.addNotification(notification,
+ mNotificationData.getImportance(key));
+
mPendingNotifications.put(key, shadeEntry);
}
@@ -1756,6 +1782,10 @@ public class StatusBar extends SystemUI implements DemoMode,
return;
}
+ if (entry != null) {
+ mForegroundServiceController.removeNotification(entry.notification);
+ }
+
if (entry != null && entry.row != null) {
entry.row.setRemoved();
mStackScroller.cleanUpViewState(entry.row);
@@ -3610,6 +3640,12 @@ public class StatusBar extends SystemUI implements DemoMode,
// Do it after DismissAction has been processed to conserve the needed ordering.
mHandler.post(this::runPostCollapseRunnables);
}
+ } else if (isInLaunchTransition() && mNotificationPanel.isLaunchTransitionFinished()) {
+
+ // We are not dismissing the shade, but the launch transition is already finished,
+ // so nobody will call readyForKeyguardDone anymore. Post it such that
+ // keyguardDonePending gets called first.
+ mHandler.post(mStatusBarKeyguardViewManager::readyForKeyguardDone);
}
return deferred;
}, cancelAction, afterKeyguardGone);
@@ -3859,10 +3895,6 @@ public class StatusBar extends SystemUI implements DemoMode,
}
}
- public void onKeyguardOccludedChanged(boolean keyguardOccluded) {
- mNavigationBar.onKeyguardOccludedChanged(keyguardOccluded);
- }
-
// State logging
private void logStateToEventlog() {
@@ -6944,6 +6976,9 @@ public class StatusBar extends SystemUI implements DemoMode,
entry.updateIcons(mContext, n);
inflateViews(entry, mStackScroller);
+ mForegroundServiceController.updateNotification(notification,
+ mNotificationData.getImportance(key));
+
boolean shouldPeek = shouldPeek(entry, notification);
boolean alertAgain = alertAgain(entry, n);
@@ -6961,6 +6996,7 @@ public class StatusBar extends SystemUI implements DemoMode,
boolean isForCurrentUser = isNotificationForCurrentProfiles(notification);
Log.d(TAG, "notification is " + (isForCurrentUser ? "" : "not ") + "for you");
}
+
setAreThereNotifications();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
index 5c3c43bffa70..7d69a349f01d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -279,9 +279,6 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
}
public void setOccluded(boolean occluded, boolean animate) {
- if (occluded != mOccluded) {
- mStatusBar.onKeyguardOccludedChanged(occluded);
- }
if (occluded && !mOccluded && mShowing) {
if (mStatusBar.isInLaunchTransition()) {
mOccluded = true;
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogComponent.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogComponent.java
index e86a34a56f17..f6d36e855964 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogComponent.java
@@ -60,7 +60,8 @@ public class VolumeDialogComponent implements VolumeComponent, TunerService.Tuna
private final Context mContext;
private final VolumeDialogControllerImpl mController;
private final InterestingConfigChanges mConfigChanges = new InterestingConfigChanges(
- ActivityInfo.CONFIG_FONT_SCALE);
+ ActivityInfo.CONFIG_FONT_SCALE | ActivityInfo.CONFIG_LOCALE
+ | ActivityInfo.CONFIG_ASSETS_PATHS);
private final Extension mExtension;
private VolumeDialog mDialog;
private VolumePolicy mVolumePolicy = new VolumePolicy(
diff --git a/packages/SystemUI/tests/src/com/android/systemui/ForegroundServiceControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/ForegroundServiceControllerTest.java
new file mode 100644
index 000000000000..1f5255a0e869
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/ForegroundServiceControllerTest.java
@@ -0,0 +1,296 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui;
+
+import android.annotation.UserIdInt;
+import android.app.Notification;
+import android.app.NotificationManager;
+import android.os.Bundle;
+import android.os.UserHandle;
+import android.service.notification.StatusBarNotification;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import com.android.internal.messages.nano.SystemMessageProto;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class ForegroundServiceControllerTest extends SysuiTestCase {
+ public static @UserIdInt int USERID_ONE = 10; // UserManagerService.MIN_USER_ID;
+ public static @UserIdInt int USERID_TWO = USERID_ONE + 1;
+
+ private ForegroundServiceController fsc;
+
+ @Before
+ public void setUp() throws Exception {
+ fsc = new ForegroundServiceControllerImpl(mContext);
+ }
+
+ @Test
+ public void testNotificationCRUD() {
+ StatusBarNotification sbn_user1_app1_fg = makeMockFgSBN(USERID_ONE, "com.example.app1");
+ StatusBarNotification sbn_user2_app2_fg = makeMockFgSBN(USERID_TWO, "com.example.app2");
+ StatusBarNotification sbn_user1_app3_fg = makeMockFgSBN(USERID_ONE, "com.example.app3");
+ StatusBarNotification sbn_user1_app1 = makeMockSBN(USERID_ONE, "com.example.app1",
+ 5000, "monkeys", Notification.FLAG_AUTO_CANCEL);
+ StatusBarNotification sbn_user2_app1 = makeMockSBN(USERID_TWO, "com.example.app1",
+ 5000, "monkeys", Notification.FLAG_AUTO_CANCEL);
+
+ assertFalse(fsc.removeNotification(sbn_user1_app3_fg));
+ assertFalse(fsc.removeNotification(sbn_user2_app2_fg));
+ assertFalse(fsc.removeNotification(sbn_user1_app1_fg));
+ assertFalse(fsc.removeNotification(sbn_user1_app1));
+ assertFalse(fsc.removeNotification(sbn_user2_app1));
+
+ fsc.addNotification(sbn_user1_app1_fg, NotificationManager.IMPORTANCE_DEFAULT);
+ fsc.addNotification(sbn_user2_app2_fg, NotificationManager.IMPORTANCE_DEFAULT);
+ fsc.addNotification(sbn_user1_app3_fg, NotificationManager.IMPORTANCE_DEFAULT);
+ fsc.addNotification(sbn_user1_app1, NotificationManager.IMPORTANCE_DEFAULT);
+ fsc.addNotification(sbn_user2_app1, NotificationManager.IMPORTANCE_DEFAULT);
+
+ // these are never added to the tracker
+ assertFalse(fsc.removeNotification(sbn_user1_app1));
+ assertFalse(fsc.removeNotification(sbn_user2_app1));
+
+ fsc.updateNotification(sbn_user1_app1, NotificationManager.IMPORTANCE_DEFAULT);
+ fsc.updateNotification(sbn_user2_app1, NotificationManager.IMPORTANCE_DEFAULT);
+ // should still not be there
+ assertFalse(fsc.removeNotification(sbn_user1_app1));
+ assertFalse(fsc.removeNotification(sbn_user2_app1));
+
+ fsc.updateNotification(sbn_user2_app2_fg, NotificationManager.IMPORTANCE_DEFAULT);
+ fsc.updateNotification(sbn_user1_app3_fg, NotificationManager.IMPORTANCE_DEFAULT);
+ fsc.updateNotification(sbn_user1_app1_fg, NotificationManager.IMPORTANCE_DEFAULT);
+
+ assertTrue(fsc.removeNotification(sbn_user1_app3_fg));
+ assertFalse(fsc.removeNotification(sbn_user1_app3_fg));
+
+ assertTrue(fsc.removeNotification(sbn_user2_app2_fg));
+ assertFalse(fsc.removeNotification(sbn_user2_app2_fg));
+
+ assertTrue(fsc.removeNotification(sbn_user1_app1_fg));
+ assertFalse(fsc.removeNotification(sbn_user1_app1_fg));
+
+ assertFalse(fsc.removeNotification(sbn_user1_app1));
+ assertFalse(fsc.removeNotification(sbn_user2_app1));
+ }
+
+ @Test
+ public void testDungeonPredicate() {
+ StatusBarNotification sbn_user1_app1 = makeMockSBN(USERID_ONE, "com.example.app1",
+ 5000, "monkeys", Notification.FLAG_AUTO_CANCEL);
+ StatusBarNotification sbn_user1_dungeon = makeMockSBN(USERID_ONE, "android",
+ SystemMessageProto.SystemMessage.NOTE_FOREGROUND_SERVICES,
+ null, Notification.FLAG_NO_CLEAR);
+
+ assertTrue(fsc.isDungeonNotification(sbn_user1_dungeon));
+ assertFalse(fsc.isDungeonNotification(sbn_user1_app1));
+ }
+
+ @Test
+ public void testDungeonCRUD() {
+ StatusBarNotification sbn_user1_app1 = makeMockSBN(USERID_ONE, "com.example.app1",
+ 5000, "monkeys", Notification.FLAG_AUTO_CANCEL);
+ StatusBarNotification sbn_user1_dungeon = makeMockSBN(USERID_ONE, "android",
+ SystemMessageProto.SystemMessage.NOTE_FOREGROUND_SERVICES,
+ null, Notification.FLAG_NO_CLEAR);
+
+ fsc.addNotification(sbn_user1_app1, NotificationManager.IMPORTANCE_DEFAULT);
+ fsc.addNotification(sbn_user1_dungeon, NotificationManager.IMPORTANCE_DEFAULT);
+
+ fsc.removeNotification(sbn_user1_dungeon);
+ assertFalse(fsc.removeNotification(sbn_user1_app1));
+ }
+
+ @Test
+ public void testNeedsDungeonAfterRemovingUnrelatedNotification() {
+ final String PKG1 = "com.example.app100";
+
+ StatusBarNotification sbn_user1_app1 = makeMockSBN(USERID_ONE, PKG1,
+ 5000, "monkeys", Notification.FLAG_AUTO_CANCEL);
+ StatusBarNotification sbn_user1_app1_fg = makeMockFgSBN(USERID_ONE, PKG1);
+
+ // first add a normal notification
+ fsc.addNotification(sbn_user1_app1, NotificationManager.IMPORTANCE_DEFAULT);
+ // nothing required yet
+ assertFalse(fsc.isDungeonNeededForUser(USERID_ONE));
+ // now the app starts a fg service
+ fsc.addNotification(makeMockDungeon(USERID_ONE, new String[]{ PKG1 }),
+ NotificationManager.IMPORTANCE_DEFAULT);
+ assertTrue(fsc.isDungeonNeededForUser(USERID_ONE)); // should be required!
+ // add the fg notification
+ fsc.addNotification(sbn_user1_app1_fg, NotificationManager.IMPORTANCE_DEFAULT);
+ assertFalse(fsc.isDungeonNeededForUser(USERID_ONE)); // app1 has got it covered
+ // remove the boring notification
+ fsc.removeNotification(sbn_user1_app1);
+ assertFalse(fsc.isDungeonNeededForUser(USERID_ONE)); // app1 has STILL got it covered
+ assertTrue(fsc.removeNotification(sbn_user1_app1_fg));
+ assertTrue(fsc.isDungeonNeededForUser(USERID_ONE)); // should be required!
+ }
+
+ @Test
+ public void testSimpleAddRemove() {
+ final String PKG1 = "com.example.app1";
+ final String PKG2 = "com.example.app2";
+
+ StatusBarNotification sbn_user1_app1 = makeMockSBN(USERID_ONE, PKG1,
+ 5000, "monkeys", Notification.FLAG_AUTO_CANCEL);
+ fsc.addNotification(sbn_user1_app1, NotificationManager.IMPORTANCE_DEFAULT);
+
+ // no services are "running"
+ fsc.addNotification(makeMockDungeon(USERID_ONE, null),
+ NotificationManager.IMPORTANCE_DEFAULT);
+
+ assertFalse(fsc.isDungeonNeededForUser(USERID_ONE));
+ assertFalse(fsc.isDungeonNeededForUser(USERID_TWO));
+
+ fsc.updateNotification(makeMockDungeon(USERID_ONE, new String[]{PKG1}),
+ NotificationManager.IMPORTANCE_DEFAULT);
+ assertTrue(fsc.isDungeonNeededForUser(USERID_ONE)); // should be required!
+ assertFalse(fsc.isDungeonNeededForUser(USERID_TWO));
+
+ // switch to different package
+ fsc.updateNotification(makeMockDungeon(USERID_ONE, new String[]{PKG2}),
+ NotificationManager.IMPORTANCE_DEFAULT);
+ assertTrue(fsc.isDungeonNeededForUser(USERID_ONE));
+ assertFalse(fsc.isDungeonNeededForUser(USERID_TWO));
+
+ fsc.updateNotification(makeMockDungeon(USERID_TWO, new String[]{PKG1}),
+ NotificationManager.IMPORTANCE_DEFAULT);
+ assertTrue(fsc.isDungeonNeededForUser(USERID_ONE));
+ assertTrue(fsc.isDungeonNeededForUser(USERID_TWO)); // finally user2 needs one too
+
+ fsc.updateNotification(makeMockDungeon(USERID_ONE, new String[]{PKG2, PKG1}),
+ NotificationManager.IMPORTANCE_DEFAULT);
+ assertTrue(fsc.isDungeonNeededForUser(USERID_ONE));
+ assertTrue(fsc.isDungeonNeededForUser(USERID_TWO));
+
+ fsc.removeNotification(makeMockDungeon(USERID_ONE, null /*unused*/));
+ assertFalse(fsc.isDungeonNeededForUser(USERID_ONE));
+ assertTrue(fsc.isDungeonNeededForUser(USERID_TWO));
+
+ fsc.removeNotification(makeMockDungeon(USERID_TWO, null /*unused*/));
+ assertFalse(fsc.isDungeonNeededForUser(USERID_ONE));
+ assertFalse(fsc.isDungeonNeededForUser(USERID_TWO));
+ }
+
+ @Test
+ public void testDungeonBasic() {
+ final String PKG1 = "com.example.app0";
+
+ StatusBarNotification sbn_user1_app1 = makeMockSBN(USERID_ONE, PKG1,
+ 5000, "monkeys", Notification.FLAG_AUTO_CANCEL);
+ StatusBarNotification sbn_user1_app1_fg = makeMockFgSBN(USERID_ONE, PKG1);
+
+ fsc.addNotification(sbn_user1_app1, NotificationManager.IMPORTANCE_DEFAULT); // not fg
+ fsc.addNotification(makeMockDungeon(USERID_ONE, new String[]{ PKG1 }),
+ NotificationManager.IMPORTANCE_DEFAULT);
+ assertTrue(fsc.isDungeonNeededForUser(USERID_ONE)); // should be required!
+ fsc.addNotification(sbn_user1_app1_fg, NotificationManager.IMPORTANCE_DEFAULT);
+ assertFalse(fsc.isDungeonNeededForUser(USERID_ONE)); // app1 has got it covered
+ assertFalse(fsc.isDungeonNeededForUser(USERID_TWO));
+
+ // let's take out the other notification and see what happens.
+
+ fsc.removeNotification(sbn_user1_app1);
+ assertFalse(fsc.isDungeonNeededForUser(USERID_ONE)); // still covered by sbn_user1_app1_fg
+ assertFalse(fsc.isDungeonNeededForUser(USERID_TWO));
+
+ // let's attempt to downgrade the notification from FLAG_FOREGROUND and see what we get
+ StatusBarNotification sbn_user1_app1_fg_sneaky = makeMockFgSBN(USERID_ONE, PKG1);
+ sbn_user1_app1_fg_sneaky.getNotification().flags = 0;
+ fsc.updateNotification(sbn_user1_app1_fg_sneaky, NotificationManager.IMPORTANCE_DEFAULT);
+ assertTrue(fsc.isDungeonNeededForUser(USERID_ONE)); // should be required!
+ assertFalse(fsc.isDungeonNeededForUser(USERID_TWO));
+
+ // ok, ok, we'll put it back
+ sbn_user1_app1_fg_sneaky.getNotification().flags = Notification.FLAG_FOREGROUND_SERVICE;
+ fsc.updateNotification(sbn_user1_app1_fg, NotificationManager.IMPORTANCE_DEFAULT);
+ assertFalse(fsc.isDungeonNeededForUser(USERID_ONE));
+ assertFalse(fsc.isDungeonNeededForUser(USERID_TWO));
+
+ assertTrue(fsc.removeNotification(sbn_user1_app1_fg_sneaky));
+ assertTrue(fsc.isDungeonNeededForUser(USERID_ONE)); // should be required!
+ assertFalse(fsc.isDungeonNeededForUser(USERID_TWO));
+
+ // now let's test an upgrade
+ fsc.addNotification(sbn_user1_app1, NotificationManager.IMPORTANCE_DEFAULT);
+ assertTrue(fsc.isDungeonNeededForUser(USERID_ONE));
+ assertFalse(fsc.isDungeonNeededForUser(USERID_TWO));
+ sbn_user1_app1.getNotification().flags |= Notification.FLAG_FOREGROUND_SERVICE;
+ fsc.updateNotification(sbn_user1_app1,
+ NotificationManager.IMPORTANCE_DEFAULT); // this is now a fg notification
+
+ assertFalse(fsc.isDungeonNeededForUser(USERID_TWO));
+ assertFalse(fsc.isDungeonNeededForUser(USERID_ONE));
+
+ // remove it, make sure we're out of compliance again
+ assertTrue(fsc.removeNotification(sbn_user1_app1)); // was fg, should return true
+ assertFalse(fsc.removeNotification(sbn_user1_app1));
+ assertFalse(fsc.isDungeonNeededForUser(USERID_TWO));
+ assertTrue(fsc.isDungeonNeededForUser(USERID_ONE));
+
+ // finally, let's turn off the service
+ fsc.addNotification(makeMockDungeon(USERID_ONE, null),
+ NotificationManager.IMPORTANCE_DEFAULT);
+
+ assertFalse(fsc.isDungeonNeededForUser(USERID_ONE));
+ assertFalse(fsc.isDungeonNeededForUser(USERID_TWO));
+ }
+
+ private StatusBarNotification makeMockSBN(int userid, String pkg, int id, String tag,
+ int flags) {
+ final Notification n = mock(Notification.class);
+ n.flags = flags;
+ return makeMockSBN(userid, pkg, id, tag, n);
+ }
+ private StatusBarNotification makeMockSBN(int userid, String pkg, int id, String tag,
+ Notification n) {
+ final StatusBarNotification sbn = mock(StatusBarNotification.class);
+ when(sbn.getNotification()).thenReturn(n);
+ when(sbn.getId()).thenReturn(id);
+ when(sbn.getPackageName()).thenReturn(pkg);
+ when(sbn.getTag()).thenReturn(null);
+ when(sbn.getUserId()).thenReturn(userid);
+ when(sbn.getUser()).thenReturn(new UserHandle(userid));
+ when(sbn.getKey()).thenReturn("MOCK:"+userid+"|"+pkg+"|"+id+"|"+tag);
+ return sbn;
+ }
+ private StatusBarNotification makeMockFgSBN(int userid, String pkg) {
+ return makeMockSBN(userid, pkg, 1000, "foo", Notification.FLAG_FOREGROUND_SERVICE);
+ }
+ private StatusBarNotification makeMockDungeon(int userid, String[] pkgs) {
+ final Notification n = mock(Notification.class);
+ n.flags = Notification.FLAG_ONGOING_EVENT;
+ final Bundle extras = new Bundle();
+ if (pkgs != null) extras.putStringArray(Notification.EXTRA_FOREGROUND_APPS, pkgs);
+ n.extras = extras;
+ final StatusBarNotification sbn = makeMockSBN(userid, "android",
+ SystemMessageProto.SystemMessage.NOTE_FOREGROUND_SERVICES,
+ null, n);
+ sbn.getNotification().extras = extras;
+ return sbn;
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/ExpandableNotificationRowTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/ExpandableNotificationRowTest.java
index 628630182ad1..99b664ad9580 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/ExpandableNotificationRowTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/ExpandableNotificationRowTest.java
@@ -18,6 +18,7 @@ package com.android.systemui.statusbar;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import android.content.Context;
@@ -88,5 +89,11 @@ public class ExpandableNotificationRowTest extends SysuiTestCase {
verify(mockContainer).reInflateViews(any(), any());
}
-
+ @Test
+ public void testIconColorShouldBeUpdatedWhenSensitive() throws Exception {
+ ExpandableNotificationRow row = spy(mNotificationTestHelper.createRow());
+ row.setSensitive(true, true);
+ row.setHideSensitive(true, false, 0, 0);
+ verify(row).updateShelfIconColor();
+ }
}
diff --git a/proto/src/metrics_constants.proto b/proto/src/metrics_constants.proto
index 57885fa06715..e1070561a7df 100644
--- a/proto/src/metrics_constants.proto
+++ b/proto/src/metrics_constants.proto
@@ -4079,6 +4079,12 @@ message MetricsEvent {
// OS: O DR
BLUETOOTH_DEVICE_DETAILS = 1009;
+ // OPEN: Settings > credential pages - prompt for key guard configuration confirmation
+ CONFIGURE_KEYGUARD_DIALOG = 1010;
+
+ // Open: Settings > Search > No Result View
+ SETTINGS_SEARCH_NO_RESULT = 1011;
+
// Add new aosp constants above this line.
// END OF AOSP CONSTANTS
}
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index 980a7d41200f..073d7b20ed64 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -774,20 +774,29 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
break;
}
- final AutofillValue currentValue = viewState.getCurrentValue();
- if (currentValue == null || currentValue.isEmpty()) {
- if (sDebug) {
- Slog.d(TAG, "showSaveLocked(): empty value for required " + id );
+ AutofillValue value = viewState.getCurrentValue();
+ if (value == null || value.isEmpty()) {
+ final AutofillValue initialValue = getValueFromContexts(id);
+ if (initialValue != null) {
+ if (sDebug) {
+ Slog.d(TAG, "Value of required field " + id + " didn't change; "
+ + "using initial value (" + initialValue + ") instead");
+ }
+ value = initialValue;
+ } else {
+ if (sDebug) {
+ Slog.d(TAG, "showSaveLocked(): empty value for required " + id );
+ }
+ allRequiredAreNotEmpty = false;
+ break;
}
- allRequiredAreNotEmpty = false;
- break;
}
final AutofillValue filledValue = viewState.getAutofilledValue();
- if (!currentValue.equals(filledValue)) {
+ if (!value.equals(filledValue)) {
if (sDebug) {
Slog.d(TAG, "showSaveLocked(): found a change on required " + id + ": "
- + filledValue + " => " + currentValue);
+ + filledValue + " => " + value);
}
atLeastOneChanged = true;
}
@@ -845,6 +854,31 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
}
/**
+ * Gets the latest non-empty value for the given id in the autofill contexts.
+ */
+ @Nullable
+ private AutofillValue getValueFromContexts(AutofillId id) {
+ AutofillValue value = null;
+ final int numContexts = mContexts.size();
+ for (int i = 0; i < numContexts; i++) {
+ final FillContext context = mContexts.get(i);
+ // TODO: create a function that gets just one node so it doesn't create an array
+ // unnecessarily
+ final ViewNode[] nodes = context.findViewNodesByAutofillIds(id);
+ if (nodes != null) {
+ AutofillValue candidate = nodes[0].getAutofillValue();
+ if (sDebug) {
+ Slog.d(TAG, "getValueFromContexts(" + id + ") at " + i + ": " + candidate);
+ }
+ if (candidate != null && !candidate.isEmpty()) {
+ value = candidate;
+ }
+ }
+ }
+ return value;
+ }
+
+ /**
* Calls service when user requested save.
*/
void callSaveLocked() {
@@ -1009,7 +1043,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
|| action == ACTION_VIEW_ENTERED) {
if (sVerbose) Slog.v(TAG, "Creating viewState for " + id + " on " + action);
boolean isIgnored = isIgnoredLocked(id);
- viewState = new ViewState(this, id, value, this,
+ viewState = new ViewState(this, id, this,
isIgnored ? ViewState.STATE_IGNORED : ViewState.STATE_INITIAL);
mViewStates.put(id, viewState);
if (isIgnored) {
@@ -1307,7 +1341,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
if (viewState != null) {
viewState.setState(state);
} else {
- viewState = new ViewState(this, id, null, this, state);
+ viewState = new ViewState(this, id, this, state);
if (sVerbose) {
Slog.v(TAG, "Adding autofillable view with id " + id + " and state " + state);
}
@@ -1370,10 +1404,16 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
}
}
+ @Override
+ public String toString() {
+ return "Session: [id=" + id + ", pkg=" + mPackageName + "]";
+ }
+
void dumpLocked(String prefix, PrintWriter pw) {
final String prefix2 = prefix + " ";
pw.print(prefix); pw.print("id: "); pw.println(id);
pw.print(prefix); pw.print("uid: "); pw.println(uid);
+ pw.print(prefix); pw.print("mPackagename: "); pw.println(mPackageName);
pw.print(prefix); pw.print("mActivityToken: "); pw.println(mActivityToken);
pw.print(prefix); pw.print("mResponses: ");
if (mResponses == null) {
diff --git a/services/autofill/java/com/android/server/autofill/ViewState.java b/services/autofill/java/com/android/server/autofill/ViewState.java
index cd8f4a59526f..51659bb8c8b3 100644
--- a/services/autofill/java/com/android/server/autofill/ViewState.java
+++ b/services/autofill/java/com/android/server/autofill/ViewState.java
@@ -74,16 +74,14 @@ final class ViewState {
private final Session mSession;
private FillResponse mResponse;
- private AutofillValue mInitialValue;
private AutofillValue mCurrentValue;
private AutofillValue mAutofilledValue;
private Rect mVirtualBounds;
private int mState;
- ViewState(Session session, AutofillId id, AutofillValue value, Listener listener, int state) {
+ ViewState(Session session, AutofillId id, Listener listener, int state) {
mSession = session;
this.id = id;
- mInitialValue = value;
mListener = listener;
mState = state;
}
@@ -118,11 +116,6 @@ final class ViewState {
}
@Nullable
- AutofillValue getInitialValue() {
- return mInitialValue;
- }
-
- @Nullable
FillResponse getResponse() {
return mResponse;
}
@@ -189,8 +182,8 @@ final class ViewState {
@Override
public String toString() {
- return "ViewState: [id=" + id + ", initialValue=" + mInitialValue
- + ", currentValue=" + mCurrentValue + ", autofilledValue=" + mAutofilledValue
+ return "ViewState: [id=" + id + ", currentValue=" + mCurrentValue
+ + ", autofilledValue=" + mAutofilledValue
+ ", bounds=" + mVirtualBounds + ", state=" + getStateAsString() + "]";
}
@@ -207,7 +200,6 @@ final class ViewState {
pw.println(mResponse.getRequestId());
}
}
- pw.print(prefix); pw.print("initialValue:" ); pw.println(mInitialValue);
pw.print(prefix); pw.print("currentValue:" ); pw.println(mCurrentValue);
pw.print(prefix); pw.print("autofilledValue:" ); pw.println(mAutofilledValue);
pw.print(prefix); pw.print("virtualBounds:" ); pw.println(mVirtualBounds);
diff --git a/services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java b/services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java
index c3d550549a3f..8ffe8f547eac 100644
--- a/services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java
+++ b/services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java
@@ -332,6 +332,10 @@ public final class AutoFillUI {
@android.annotation.UiThread
private void hideSaveUiUiThread(@Nullable AutoFillUiCallback callback) {
+ if (sVerbose) {
+ Slog.v(TAG, "hideSaveUiUiThread(): mSaveUi=" + mSaveUi + ", callback=" + callback
+ + ", mCallback=" + mCallback);
+ }
if (mSaveUi != null && (callback == null || callback == mCallback)) {
mSaveUi.destroy();
mSaveUi = null;
diff --git a/services/autofill/java/com/android/server/autofill/ui/FillUi.java b/services/autofill/java/com/android/server/autofill/ui/FillUi.java
index d566d3d608b4..e9c98e94c860 100644
--- a/services/autofill/java/com/android/server/autofill/ui/FillUi.java
+++ b/services/autofill/java/com/android/server/autofill/ui/FillUi.java
@@ -398,6 +398,12 @@ final class FillUi {
} catch (WindowManager.BadTokenException e) {
if (sDebug) Slog.d(TAG, "Filed with with token " + params.token + " gone.");
mCallback.onDestroy();
+ } catch (IllegalStateException e) {
+ // WM throws an ISE if mContentView was added twice; this should never happen -
+ // since show() and hide() are always called in the UIThread - but when it does,
+ // it should not crash the system.
+ Slog.e(TAG, "Exception showing window " + params, e);
+ mCallback.onDestroy();
}
}
@@ -405,10 +411,18 @@ final class FillUi {
* Hides the window.
*/
void hide() {
- if (mShowing) {
- mContentView.setOnTouchListener(null);
- mWm.removeView(mContentView);
- mShowing = false;
+ try {
+ if (mShowing) {
+ mContentView.setOnTouchListener(null);
+ mWm.removeView(mContentView);
+ mShowing = false;
+ }
+ } catch (IllegalStateException e) {
+ // WM might thrown an ISE when removing the mContentView; this should never
+ // happen - since show() and hide() are always called in the UIThread - but if it
+ // does, it should not crash the system.
+ Slog.e(TAG, "Exception hiding window ", e);
+ mCallback.onDestroy();
}
}
@@ -489,7 +503,7 @@ final class FillUi {
final String value = item.getValue();
// No value, i.e. null, matches any filter
if (value == null
- || value.toLowerCase().contains(constraintLowerCase)) {
+ || value.toLowerCase().startsWith(constraintLowerCase)) {
filteredItems.add(item);
}
}
diff --git a/services/autofill/java/com/android/server/autofill/ui/SaveUi.java b/services/autofill/java/com/android/server/autofill/ui/SaveUi.java
index d25ffced7797..491af91cbc36 100644
--- a/services/autofill/java/com/android/server/autofill/ui/SaveUi.java
+++ b/services/autofill/java/com/android/server/autofill/ui/SaveUi.java
@@ -17,6 +17,7 @@
package com.android.server.autofill.ui;
import static com.android.server.autofill.Helper.sDebug;
+import static com.android.server.autofill.Helper.sVerbose;
import android.annotation.NonNull;
import android.app.Dialog;
@@ -63,7 +64,7 @@ final class SaveUi {
@Override
public void onSave() {
- if (sDebug) Slog.d(TAG, "onSave(): " + mDone);
+ if (sDebug) Slog.d(TAG, "OneTimeListener.onSave(): " + mDone);
if (mDone) {
return;
}
@@ -73,7 +74,7 @@ final class SaveUi {
@Override
public void onCancel(IntentSender listener) {
- if (sDebug) Slog.d(TAG, "onCancel(): " + mDone);
+ if (sDebug) Slog.d(TAG, "OneTimeListener.onCancel(): " + mDone);
if (mDone) {
return;
}
@@ -83,7 +84,7 @@ final class SaveUi {
@Override
public void onDestroy() {
- if (sDebug) Slog.d(TAG, "onDestroy(): " + mDone);
+ if (sDebug) Slog.d(TAG, "OneTimeListener.onDestroy(): " + mDone);
if (mDone) {
return;
}
@@ -158,9 +159,8 @@ final class SaveUi {
subTitleView.setVisibility(View.VISIBLE);
}
- Slog.i(TAG, "Showing save dialog: " + mTitle);
if (sDebug) {
- Slog.d(TAG, "SubTitle: " + mSubTitle);
+ Slog.d(TAG, "on constructor: title=" + mTitle + ", subTitle=" + mSubTitle);
}
final TextView noButton = view.findViewById(R.id.autofill_save_no);
@@ -169,15 +169,15 @@ final class SaveUi {
} else {
noButton.setText(R.string.autofill_save_no);
}
- noButton.setOnClickListener((v) -> mListener.onCancel(
- info.getNegativeActionListener()));
+ View.OnClickListener cancelListener =
+ (v) -> mListener.onCancel(info.getNegativeActionListener());
+ noButton.setOnClickListener(cancelListener);
final View yesButton = view.findViewById(R.id.autofill_save_yes);
yesButton.setOnClickListener((v) -> mListener.onSave());
final View closeButton = view.findViewById(R.id.autofill_save_close);
- closeButton.setOnClickListener((v) -> mListener.onCancel(
- info.getNegativeActionListener()));
+ closeButton.setOnClickListener(cancelListener);
mDialog = new Dialog(context, R.style.Theme_DeviceDefault_Light_Panel);
mDialog.setContentView(view);
@@ -195,13 +195,16 @@ final class SaveUi {
params.width = WindowManager.LayoutParams.MATCH_PARENT;
params.accessibilityTitle = context.getString(R.string.autofill_save_accessibility_title);
+ Slog.i(TAG, "Showing save dialog: " + mTitle);
mDialog.show();
}
void destroy() {
+ if (sDebug) Slog.d(TAG, "destroy()");
throwIfDestroyed();
mListener.onDestroy();
mHandler.removeCallbacksAndMessages(mListener);
+ if (sVerbose) Slog.v(TAG, "destroy(): dismissing dialog");
mDialog.dismiss();
mDestroyed = true;
}
@@ -212,6 +215,11 @@ final class SaveUi {
}
}
+ @Override
+ public String toString() {
+ return mTitle == null ? "NO TITLE" : mTitle.toString();
+ }
+
void dump(PrintWriter pw, String prefix) {
pw.print(prefix); pw.print("title: "); pw.println(mTitle);
pw.print(prefix); pw.print("subtitle: "); pw.println(mSubTitle);
diff --git a/services/core/java/com/android/server/GestureLauncherService.java b/services/core/java/com/android/server/GestureLauncherService.java
index 47f157da8790..b408da85425d 100644
--- a/services/core/java/com/android/server/GestureLauncherService.java
+++ b/services/core/java/com/android/server/GestureLauncherService.java
@@ -320,7 +320,8 @@ public class GestureLauncherService extends SystemService {
public static boolean isCameraLiftTriggerSettingEnabled(Context context, int userId) {
return isCameraLiftTriggerEnabled(context.getResources())
&& (Settings.Secure.getIntForUser(context.getContentResolver(),
- Settings.Secure.CAMERA_LIFT_TRIGGER_ENABLED, 0, userId) != 0);
+ Settings.Secure.CAMERA_LIFT_TRIGGER_ENABLED,
+ Settings.Secure.CAMERA_LIFT_TRIGGER_ENABLED_DEFAULT, userId) != 0);
}
/**
diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java
index 4a78a7bc4b51..e4a2c2f20762 100644
--- a/services/core/java/com/android/server/accounts/AccountManagerService.java
+++ b/services/core/java/com/android/server/accounts/AccountManagerService.java
@@ -23,8 +23,10 @@ import android.accounts.AccountAndUser;
import android.accounts.AccountAuthenticatorResponse;
import android.accounts.AccountManager;
import android.accounts.AccountManagerInternal;
+import android.accounts.AccountManagerResponse;
import android.accounts.AuthenticatorDescription;
import android.accounts.CantAddAccountActivity;
+import android.accounts.ChooseAccountActivity;
import android.accounts.GrantCredentialsPermissionActivity;
import android.accounts.IAccountAuthenticator;
import android.accounts.IAccountAuthenticatorResponse;
@@ -71,6 +73,7 @@ import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
import android.os.Parcel;
+import android.os.Parcelable;
import android.os.Process;
import android.os.RemoteCallback;
import android.os.RemoteException;
@@ -4043,6 +4046,7 @@ public class AccountManagerService
private volatile int mCurrentAccount = 0;
private final int mCallingUid;
private final String mPackageName;
+ private final boolean mIncludeManagedNotVisible;
public GetAccountsByTypeAndFeatureSession(
UserAccounts accounts,
@@ -4050,19 +4054,21 @@ public class AccountManagerService
String type,
String[] features,
int callingUid,
- String packageName) {
+ String packageName,
+ boolean includeManagedNotVisible) {
super(accounts, response, type, false /* expectActivityLaunch */,
true /* stripAuthTokenFromResult */, null /* accountName */,
false /* authDetailsRequired */);
mCallingUid = callingUid;
mFeatures = features;
mPackageName = packageName;
+ mIncludeManagedNotVisible = includeManagedNotVisible;
}
@Override
public void run() throws RemoteException {
mAccountsOfType = getAccountsFromCache(mAccounts, mAccountType,
- mCallingUid, mPackageName, false /* include managed not visible*/);
+ mCallingUid, mPackageName, mIncludeManagedNotVisible);
// check whether each account matches the requested features
mAccountsWithFeatures = new ArrayList<>(mAccountsOfType.length);
mCurrentAccount = 0;
@@ -4423,10 +4429,120 @@ public class AccountManagerService
&& (type != null && !isAccountManagedByCaller(type, callingUid, userId))) {
return EMPTY_ACCOUNT_ARRAY;
}
+ if (!UserHandle.isSameApp(callingUid, Process.SYSTEM_UID) && type == null) {
+ return getAccountsAsUserForPackage(type, userId,
+ packageName, packageUid, opPackageName, false /* includeUserManagedNotVisible */);
+ }
return getAccountsAsUserForPackage(type, userId,
packageName, packageUid, opPackageName, true /* includeUserManagedNotVisible */);
}
+ private boolean needToStartChooseAccountActivity(Account[] accounts, String callingPackage) {
+ if (accounts.length < 1) return false;
+ if (accounts.length > 1) return true;
+ Account account = accounts[0];
+ UserAccounts userAccounts = getUserAccounts(UserHandle.getCallingUserId());
+ int visibility = resolveAccountVisibility(account, callingPackage, userAccounts);
+ if (visibility == AccountManager.VISIBILITY_USER_MANAGED_NOT_VISIBLE) return true;
+ return false;
+ }
+
+ private void startChooseAccountActivityWithAccounts(
+ IAccountManagerResponse response, Account[] accounts) {
+ Intent intent = new Intent(mContext, ChooseAccountActivity.class);
+ intent.putExtra(AccountManager.KEY_ACCOUNTS, accounts);
+ intent.putExtra(AccountManager.KEY_ACCOUNT_MANAGER_RESPONSE,
+ new AccountManagerResponse(response));
+
+ mContext.startActivityAsUser(intent, UserHandle.of(UserHandle.getCallingUserId()));
+ }
+
+ private void handleGetAccountsResult(
+ IAccountManagerResponse response,
+ Account[] accounts,
+ String callingPackage) {
+
+ if (needToStartChooseAccountActivity(accounts, callingPackage)) {
+ startChooseAccountActivityWithAccounts(response, accounts);
+ return;
+ }
+ if (accounts.length == 1) {
+ Bundle bundle = new Bundle();
+ bundle.putString(AccountManager.KEY_ACCOUNT_NAME, accounts[0].name);
+ bundle.putString(AccountManager.KEY_ACCOUNT_TYPE, accounts[0].type);
+ onResult(response, bundle);
+ return;
+ }
+ // No qualified account exists, return an empty Bundle.
+ onResult(response, new Bundle());
+ }
+
+ @Override
+ public void getAccountByTypeAndFeatures(
+ IAccountManagerResponse response,
+ String accountType,
+ String[] features,
+ String opPackageName) {
+
+ int callingUid = Binder.getCallingUid();
+ mAppOpsManager.checkPackage(callingUid, opPackageName);
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ Log.v(TAG, "getAccount: accountType " + accountType
+ + ", response " + response
+ + ", features " + Arrays.toString(features)
+ + ", caller's uid " + callingUid
+ + ", pid " + Binder.getCallingPid());
+ }
+ if (response == null) throw new IllegalArgumentException("response is null");
+ if (accountType == null) throw new IllegalArgumentException("accountType is null");
+
+ int userId = UserHandle.getCallingUserId();
+
+ long identityToken = clearCallingIdentity();
+ try {
+ UserAccounts userAccounts = getUserAccounts(userId);
+ if (ArrayUtils.isEmpty(features)) {
+ Account[] accountsWithManagedNotVisible = getAccountsFromCache(
+ userAccounts, accountType, callingUid, opPackageName,
+ true /* include managed not visible */);
+ handleGetAccountsResult(
+ response, accountsWithManagedNotVisible, opPackageName);
+ return;
+ }
+
+ IAccountManagerResponse retrieveAccountsResponse =
+ new IAccountManagerResponse.Stub() {
+ @Override
+ public void onResult(Bundle value) throws RemoteException {
+ Parcelable[] parcelables = value.getParcelableArray(
+ AccountManager.KEY_ACCOUNTS);
+ Account[] accounts = new Account[parcelables.length];
+ for (int i = 0; i < parcelables.length; i++) {
+ accounts[i] = (Account) parcelables[i];
+ }
+ handleGetAccountsResult(
+ response, accounts, opPackageName);
+ }
+
+ @Override
+ public void onError(int errorCode, String errorMessage)
+ throws RemoteException {
+ // Will not be called in this case.
+ }
+ };
+ new GetAccountsByTypeAndFeatureSession(
+ userAccounts,
+ retrieveAccountsResponse,
+ accountType,
+ features,
+ callingUid,
+ opPackageName,
+ true /* include managed not visible */).bind();
+ } finally {
+ restoreCallingIdentity(identityToken);
+ }
+ }
+
@Override
public void getAccountsByFeatures(
IAccountManagerResponse response,
@@ -4459,6 +4575,7 @@ public class AccountManagerService
}
return;
}
+
long identityToken = clearCallingIdentity();
try {
UserAccounts userAccounts = getUserAccounts(userId);
@@ -4476,7 +4593,8 @@ public class AccountManagerService
type,
features,
callingUid,
- opPackageName).bind();
+ opPackageName,
+ false /* include managed not visible */).bind();
} finally {
restoreCallingIdentity(identityToken);
}
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index 2680b425ff3c..bad7091429a2 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -162,7 +162,7 @@ public final class ActiveServices {
/**
* Information about an app that is currently running one or more foreground services.
- * (This mapps directly to the running apps we show in the notification.)
+ * (This maps directly to the running apps we show in the notification.)
*/
static final class ActiveForegroundApp {
String mPackageName;
@@ -813,6 +813,7 @@ public final class ActiveServices {
String title;
String msg;
String[] pkgs;
+ long oldestStartTime = System.currentTimeMillis(); // now
if (active.size() == 1) {
intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
intent.setData(Uri.fromParts("package", active.get(0).mPackageName, null));
@@ -820,11 +821,13 @@ public final class ActiveServices {
R.string.foreground_service_app_in_background, active.get(0).mLabel);
msg = context.getString(R.string.foreground_service_tap_for_details);
pkgs = new String[] { active.get(0).mPackageName };
+ oldestStartTime = active.get(0).mStartTime;
} else {
intent = new Intent(Settings.ACTION_FOREGROUND_SERVICES_SETTINGS);
pkgs = new String[active.size()];
for (int i = 0; i < active.size(); i++) {
pkgs[i] = active.get(i).mPackageName;
+ oldestStartTime = Math.min(oldestStartTime, active.get(i).mStartTime);
}
intent.putExtra("packages", pkgs);
title = context.getString(
@@ -841,9 +844,10 @@ public final class ActiveServices {
new Notification.Builder(context,
SystemNotificationChannels.FOREGROUND_SERVICE)
.addExtras(notificationBundle)
- .setSmallIcon(R.drawable.ic_check_circle_24px)
+ .setSmallIcon(R.drawable.stat_sys_vitals)
.setOngoing(true)
- .setShowWhen(false)
+ .setShowWhen(oldestStartTime > 0)
+ .setWhen(oldestStartTime)
.setColor(context.getColor(
com.android.internal.R.color.system_notification_accent_color))
.setContentTitle(title)
diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java
index c20221bfe4aa..06ab75a8fb40 100644
--- a/services/core/java/com/android/server/am/BatteryStatsService.java
+++ b/services/core/java/com/android/server/am/BatteryStatsService.java
@@ -188,6 +188,7 @@ public final class BatteryStatsService extends IBatteryStats.Stub
}
private native int getPlatformLowPowerStats(ByteBuffer outBuffer);
+ private native int getSubsystemLowPowerStats(ByteBuffer outBuffer);
private CharsetDecoder mDecoderStat = StandardCharsets.UTF_8
.newDecoder()
.onMalformedInput(CodingErrorAction.REPLACE)
@@ -219,6 +220,28 @@ public final class BatteryStatsService extends IBatteryStats.Stub
}
}
+ @Override
+ public String getSubsystemLowPowerStats() {
+ Slog.d(TAG, "begin getSubsystemLowPowerStats");
+ try {
+ mUtf8BufferStat.clear();
+ mUtf16BufferStat.clear();
+ mDecoderStat.reset();
+ int bytesWritten = getSubsystemLowPowerStats(mUtf8BufferStat);
+ if (bytesWritten < 0) {
+ return null;
+ } else if (bytesWritten == 0) {
+ return "Empty";
+ }
+ mUtf8BufferStat.limit(bytesWritten);
+ mDecoderStat.decode(mUtf8BufferStat, mUtf16BufferStat, true);
+ mUtf16BufferStat.flip();
+ return mUtf16BufferStat.toString();
+ } finally {
+ Slog.d(TAG, "end getSubsystemLowPowerStats");
+ }
+ }
+
BatteryStatsService(File systemDir, Handler handler) {
// Our handler here will be accessing the disk, use a different thread than
// what the ActivityManagerService gave us (no I/O on that one!).
diff --git a/services/core/java/com/android/server/am/TaskChangeNotificationController.java b/services/core/java/com/android/server/am/TaskChangeNotificationController.java
index ea9ff592d6e1..82971696d670 100644
--- a/services/core/java/com/android/server/am/TaskChangeNotificationController.java
+++ b/services/core/java/com/android/server/am/TaskChangeNotificationController.java
@@ -16,7 +16,6 @@
package com.android.server.am;
-import android.app.ActivityManager;
import android.app.ActivityManager.TaskSnapshot;
import android.app.ITaskStackListener;
import android.app.ActivityManager.TaskDescription;
@@ -31,27 +30,27 @@ import android.os.RemoteException;
import java.util.ArrayList;
class TaskChangeNotificationController {
- static final int LOG_STACK_STATE_MSG = 1;
- static final int NOTIFY_TASK_STACK_CHANGE_LISTENERS_MSG = 2;
- static final int NOTIFY_ACTIVITY_PINNED_LISTENERS_MSG = 3;
- static final int NOTIFY_PINNED_ACTIVITY_RESTART_ATTEMPT_LISTENERS_MSG = 4;
- static final int NOTIFY_PINNED_STACK_ANIMATION_ENDED_LISTENERS_MSG = 5;
- static final int NOTIFY_FORCED_RESIZABLE_MSG = 6;
- static final int NOTIFY_ACTIVITY_DISMISSING_DOCKED_STACK_MSG = 7;
- static final int NOTIFY_TASK_ADDED_LISTENERS_MSG = 8;
- static final int NOTIFY_TASK_REMOVED_LISTENERS_MSG = 9;
- static final int NOTIFY_TASK_MOVED_TO_FRONT_LISTENERS_MSG = 10;
- static final int NOTIFY_TASK_DESCRIPTION_CHANGED_LISTENERS_MSG = 11;
- static final int NOTIFY_ACTIVITY_REQUESTED_ORIENTATION_CHANGED_LISTENERS = 12;
- static final int NOTIFY_TASK_REMOVAL_STARTED_LISTENERS = 13;
- static final int NOTIFY_TASK_PROFILE_LOCKED_LISTENERS_MSG = 14;
- static final int NOTIFY_TASK_SNAPSHOT_CHANGED_LISTENERS_MSG = 15;
- static final int NOTIFY_PINNED_STACK_ANIMATION_STARTED_LISTENERS_MSG = 16;
- static final int NOTIFY_ACTIVITY_UNPINNED_LISTENERS_MSG = 17;
- static final int NOTIFY_ACTIVITY_LAUNCH_ON_SECONDARY_DISPLAY_FAILED_MSG = 18;
+ private static final int LOG_STACK_STATE_MSG = 1;
+ private static final int NOTIFY_TASK_STACK_CHANGE_LISTENERS_MSG = 2;
+ private static final int NOTIFY_ACTIVITY_PINNED_LISTENERS_MSG = 3;
+ private static final int NOTIFY_PINNED_ACTIVITY_RESTART_ATTEMPT_LISTENERS_MSG = 4;
+ private static final int NOTIFY_PINNED_STACK_ANIMATION_ENDED_LISTENERS_MSG = 5;
+ private static final int NOTIFY_FORCED_RESIZABLE_MSG = 6;
+ private static final int NOTIFY_ACTIVITY_DISMISSING_DOCKED_STACK_MSG = 7;
+ private static final int NOTIFY_TASK_ADDED_LISTENERS_MSG = 8;
+ private static final int NOTIFY_TASK_REMOVED_LISTENERS_MSG = 9;
+ private static final int NOTIFY_TASK_MOVED_TO_FRONT_LISTENERS_MSG = 10;
+ private static final int NOTIFY_TASK_DESCRIPTION_CHANGED_LISTENERS_MSG = 11;
+ private static final int NOTIFY_ACTIVITY_REQUESTED_ORIENTATION_CHANGED_LISTENERS = 12;
+ private static final int NOTIFY_TASK_REMOVAL_STARTED_LISTENERS = 13;
+ private static final int NOTIFY_TASK_PROFILE_LOCKED_LISTENERS_MSG = 14;
+ private static final int NOTIFY_TASK_SNAPSHOT_CHANGED_LISTENERS_MSG = 15;
+ private static final int NOTIFY_PINNED_STACK_ANIMATION_STARTED_LISTENERS_MSG = 16;
+ private static final int NOTIFY_ACTIVITY_UNPINNED_LISTENERS_MSG = 17;
+ private static final int NOTIFY_ACTIVITY_LAUNCH_ON_SECONDARY_DISPLAY_FAILED_MSG = 18;
// Delay in notifying task stack change listeners (in millis)
- static final int NOTIFY_TASK_STACK_CHANGE_LISTENERS_DELAY = 100;
+ private static final int NOTIFY_TASK_STACK_CHANGE_LISTENERS_DELAY = 100;
private final ActivityManagerService mService;
private final ActivityStackSupervisor mStackSupervisor;
@@ -242,7 +241,7 @@ class TaskChangeNotificationController {
}
}
- void forAllRemoteListeners(TaskStackConsumer callback, Message message) {
+ private void forAllRemoteListeners(TaskStackConsumer callback, Message message) {
synchronized (mService) {
for (int i = mRemoteTaskStackListeners.beginBroadcast() - 1; i >= 0; i--) {
try {
@@ -256,7 +255,7 @@ class TaskChangeNotificationController {
}
}
- void forAllLocalListeners(TaskStackConsumer callback, Message message) {
+ private void forAllLocalListeners(TaskStackConsumer callback, Message message) {
synchronized (mService) {
for (int i = mLocalTaskStackListeners.size() - 1; i >= 0; i--) {
try {
@@ -329,8 +328,9 @@ class TaskChangeNotificationController {
void notifyActivityDismissingDockedStack() {
mHandler.removeMessages(NOTIFY_ACTIVITY_DISMISSING_DOCKED_STACK_MSG);
- final Message message = mHandler.obtainMessage(NOTIFY_ACTIVITY_DISMISSING_DOCKED_STACK_MSG);
- forAllLocalListeners(mNotifyActivityDismissingDockedStack, message);
+ final Message msg = mHandler.obtainMessage(NOTIFY_ACTIVITY_DISMISSING_DOCKED_STACK_MSG);
+ forAllLocalListeners(mNotifyActivityDismissingDockedStack, msg);
+ msg.sendToTarget();
}
void notifyActivityForcedResizable(int taskId, int reason, String packageName) {
diff --git a/services/core/java/com/android/server/connectivity/tethering/OffloadController.java b/services/core/java/com/android/server/connectivity/tethering/OffloadController.java
index c64e70516abc..cb50e9fdbfed 100644
--- a/services/core/java/com/android/server/connectivity/tethering/OffloadController.java
+++ b/services/core/java/com/android/server/connectivity/tethering/OffloadController.java
@@ -20,10 +20,15 @@ import static android.provider.Settings.Global.TETHER_OFFLOAD_DISABLED;
import android.content.ContentResolver;
import android.net.LinkProperties;
+import android.net.RouteInfo;
import android.net.util.SharedLog;
import android.os.Handler;
import android.provider.Settings;
+import java.net.Inet4Address;
+import java.net.InetAddress;
+import java.util.ArrayList;
+
/**
* A class to encapsulate the business logic of programming the tethering
* hardware offload interface.
@@ -92,8 +97,12 @@ public class OffloadController {
public void setUpstreamLinkProperties(LinkProperties lp) {
if (!started()) return;
- // TODO: setUpstreamParameters().
- mUpstreamLinkProperties = lp;
+ mUpstreamLinkProperties = (lp != null) ? new LinkProperties(lp) : null;
+ // TODO: examine return code and decide what to do if programming
+ // upstream parameters fails (probably just wait for a subsequent
+ // onOffloadEvent() callback to tell us offload is available again and
+ // then reapply all state).
+ pushUpstreamParameters();
}
// TODO: public void addDownStream(...)
@@ -106,4 +115,40 @@ public class OffloadController {
private boolean started() {
return mConfigInitialized && mControlInitialized;
}
+
+ private boolean pushUpstreamParameters() {
+ if (mUpstreamLinkProperties == null) {
+ return mHwInterface.setUpstreamParameters(null, null, null, null);
+ }
+
+ // A stacked interface cannot be an upstream for hardware offload.
+ // Consequently, we examine only the primary interface name, look at
+ // getAddresses() rather than getAllAddresses(), and check getRoutes()
+ // rather than getAllRoutes().
+ final String iface = mUpstreamLinkProperties.getInterfaceName();
+ final ArrayList<String> v6gateways = new ArrayList<>();
+ String v4addr = null;
+ String v4gateway = null;
+
+ for (InetAddress ip : mUpstreamLinkProperties.getAddresses()) {
+ if (ip instanceof Inet4Address) {
+ v4addr = ip.getHostAddress();
+ break;
+ }
+ }
+
+ // Find the gateway addresses of all default routes of either address family.
+ for (RouteInfo ri : mUpstreamLinkProperties.getRoutes()) {
+ if (!ri.hasGateway()) continue;
+
+ final String gateway = ri.getGateway().getHostAddress();
+ if (ri.isIPv4Default()) {
+ v4gateway = gateway;
+ } else if (ri.isIPv6Default()) {
+ v6gateways.add(gateway);
+ }
+ }
+
+ return mHwInterface.setUpstreamParameters(iface, v4addr, v4gateway, v6gateways);
+ }
}
diff --git a/services/core/java/com/android/server/connectivity/tethering/OffloadHardwareInterface.java b/services/core/java/com/android/server/connectivity/tethering/OffloadHardwareInterface.java
index 0429ab3dca92..3ecf0d1d0c71 100644
--- a/services/core/java/com/android/server/connectivity/tethering/OffloadHardwareInterface.java
+++ b/services/core/java/com/android/server/connectivity/tethering/OffloadHardwareInterface.java
@@ -23,6 +23,8 @@ import android.os.Handler;
import android.os.RemoteException;
import android.net.util.SharedLog;
+import java.util.ArrayList;
+
/**
* Capture tethering dependencies, for injection.
@@ -103,6 +105,25 @@ public class OffloadHardwareInterface {
mControlCallback = null;
}
+ public boolean setUpstreamParameters(
+ String iface, String v4addr, String v4gateway, ArrayList<String> v6gws) {
+ final CbResults results = new CbResults();
+ try {
+ mOffloadControl.setUpstreamParameters(
+ iface, v4addr, v4gateway, v6gws,
+ (boolean success, String errMsg) -> {
+ results.success = success;
+ results.errMsg = errMsg;
+ });
+ } catch (RemoteException e) {
+ mLog.e("failed to setUpstreamParameters: " + e);
+ return false;
+ }
+
+ if (!results.success) mLog.e("setUpstreamParameters failed: " + results.errMsg);
+ return results.success;
+ }
+
private static class TetheringOffloadCallback extends ITetheringOffloadCallback.Stub {
public final Handler handler;
public final ControlCallback controlCb;
diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java
index 9dc317ad38ac..e82724db27f7 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController.java
@@ -104,6 +104,11 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
// Trigger proximity if distance is less than 5 cm.
private static final float TYPICAL_PROXIMITY_THRESHOLD = 5.0f;
+ // State machine constants for tracking initial brightness ramp skipping when enabled.
+ private static final int RAMP_STATE_SKIP_NONE = 0;
+ private static final int RAMP_STATE_SKIP_INITIAL = 1;
+ private static final int RAMP_STATE_SKIP_AUTOBRIGHT = 2;
+
private static final int REPORTED_TO_POLICY_SCREEN_OFF = 0;
private static final int REPORTED_TO_POLICY_SCREEN_TURNING_ON = 1;
private static final int REPORTED_TO_POLICY_SCREEN_ON = 2;
@@ -239,6 +244,9 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
// Screen state we reported to policy. Must be one of REPORTED_TO_POLICY_SCREEN_* fields.
private int mReportedScreenStateToPolicy;
+ // If the last recorded screen state was dozing or not.
+ private boolean mDozing;
+
// Remembers whether certain kinds of brightness adjustments
// were recently applied so that we can decide how to transition.
private boolean mAppliedAutoBrightness;
@@ -249,6 +257,15 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
private final int mBrightnessRampRateFast;
private final int mBrightnessRampRateSlow;
+ // Whether or not to skip the initial brightness ramps into STATE_ON.
+ private final boolean mSkipScreenOnBrightnessRamp;
+
+ // A record of state for skipping brightness ramps.
+ private int mSkipRampState = RAMP_STATE_SKIP_NONE;
+
+ // The first autobrightness value set when entering RAMP_STATE_SKIP_INITIAL.
+ private int mInitialAutoBrightness;
+
// The controller for the automatic brightness level.
private AutomaticBrightnessController mAutomaticBrightnessController;
@@ -312,6 +329,8 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
com.android.internal.R.integer.config_brightness_ramp_rate_fast);
mBrightnessRampRateSlow = resources.getInteger(
com.android.internal.R.integer.config_brightness_ramp_rate_slow);
+ mSkipScreenOnBrightnessRamp = resources.getBoolean(
+ com.android.internal.R.bool.config_skipScreenOnBrightnessRamp);
int lightSensorRate = resources.getInteger(
com.android.internal.R.integer.config_autoBrightnessLightSensorRate);
@@ -731,8 +750,29 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
// Animate the screen brightness when the screen is on or dozing.
// Skip the animation when the screen is off or suspended or transition to/from VR.
if (!mPendingScreenOff) {
+ if (mSkipScreenOnBrightnessRamp) {
+
+ if (state == Display.STATE_ON) {
+ if (mSkipRampState == RAMP_STATE_SKIP_NONE && mDozing) {
+ mInitialAutoBrightness = brightness;
+ mSkipRampState = RAMP_STATE_SKIP_INITIAL;
+ } else if (mSkipRampState == RAMP_STATE_SKIP_INITIAL
+ && mUseSoftwareAutoBrightnessConfig
+ && brightness != mInitialAutoBrightness) {
+ mSkipRampState = RAMP_STATE_SKIP_AUTOBRIGHT;
+ } else if (mSkipRampState == RAMP_STATE_SKIP_AUTOBRIGHT) {
+ mSkipRampState = RAMP_STATE_SKIP_NONE;
+ }
+ } else {
+ mSkipRampState = RAMP_STATE_SKIP_NONE;
+ }
+ }
+
boolean wasOrWillBeInVr = (state == Display.STATE_VR || oldState == Display.STATE_VR);
- if ((state == Display.STATE_ON || state == Display.STATE_DOZE) && !wasOrWillBeInVr) {
+ if ((state == Display.STATE_ON
+ && mSkipRampState == RAMP_STATE_SKIP_NONE
+ || state == Display.STATE_DOZE)
+ && !wasOrWillBeInVr) {
animateScreenBrightness(brightness,
slowChange ? mBrightnessRampRateSlow : mBrightnessRampRateFast);
} else {
@@ -790,6 +830,9 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
mUnfinishedBusiness = false;
mCallbacks.releaseSuspendBlocker();
}
+
+ // Record if dozing for future comparison.
+ mDozing = state != Display.STATE_ON;
}
@Override
diff --git a/services/core/java/com/android/server/dreams/DreamManagerService.java b/services/core/java/com/android/server/dreams/DreamManagerService.java
index 1b984a418257..dbccc0765b73 100644
--- a/services/core/java/com/android/server/dreams/DreamManagerService.java
+++ b/services/core/java/com/android/server/dreams/DreamManagerService.java
@@ -86,7 +86,6 @@ public final class DreamManagerService extends SystemService {
private boolean mCurrentDreamCanDoze;
private boolean mCurrentDreamIsDozing;
private boolean mCurrentDreamIsWaking;
- private Runnable mStopDreamRunnable;
private int mCurrentDreamDozeScreenState = Display.STATE_UNKNOWN;
private int mCurrentDreamDozeScreenBrightness = PowerManager.BRIGHTNESS_DEFAULT;
@@ -350,11 +349,6 @@ public final class DreamManagerService extends SystemService {
private void startDreamLocked(final ComponentName name,
final boolean isTest, final boolean canDoze, final int userId) {
- if (mStopDreamRunnable != null) {
- mHandler.removeCallbacks(mStopDreamRunnable);
- mStopDreamRunnable = null;
- }
-
if (Objects.equal(mCurrentDreamName, name)
&& mCurrentDreamIsTest == isTest
&& mCurrentDreamCanDoze == canDoze
@@ -392,15 +386,13 @@ public final class DreamManagerService extends SystemService {
mCurrentDreamIsWaking = true;
}
- mStopDreamRunnable = new Runnable() {
+ mHandler.post(new Runnable() {
@Override
public void run() {
Slog.i(TAG, "Performing gentle wake from dream.");
mController.stopDream(immediate);
- mStopDreamRunnable = null;
}
- };
- mHandler.post(mStopDreamRunnable);
+ });
}
}
diff --git a/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java b/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java
index ac7b763600a7..d1aecb1b8d1d 100644
--- a/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java
+++ b/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java
@@ -936,7 +936,7 @@ final class DefaultPermissionGrantPolicy {
// permissions if the version on the system image does not declare them.
if (!isDefaultPhoneOrSms && pkg.isUpdatedSystemApp()) {
PackageSetting sysPs = mService.mSettings.getDisabledSystemPkgLPr(pkg.packageName);
- if (sysPs != null) {
+ if (sysPs != null && sysPs.pkg != null) {
if (sysPs.pkg.requestedPermissions.isEmpty()) {
return;
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 8bd1f790e524..66c870c502c4 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -14952,7 +14952,7 @@ public class PackageManagerService extends IPackageManager.Stub
*
* @return true if verification should be performed
*/
- private boolean isVerificationEnabled(int userId, int installFlags) {
+ private boolean isVerificationEnabled(int userId, int installFlags, int installerUid) {
if (!DEFAULT_VERIFY_ENABLE) {
return false;
}
@@ -14973,6 +14973,23 @@ public class PackageManagerService extends IPackageManager.Stub
android.provider.Settings.Global.PACKAGE_VERIFIER_INCLUDE_ADB, 1) == 0) {
return false;
}
+ } else {
+ // only when not installed from ADB, skip verification for instant apps when
+ // the installer and verifier are the same.
+ if ((installFlags & PackageManager.INSTALL_INSTANT_APP) != 0) {
+ if (mInstantAppInstallerActivity != null
+ && mInstantAppInstallerActivity.packageName.equals(
+ mRequiredVerifierPackage)) {
+ try {
+ mContext.getSystemService(AppOpsManager.class)
+ .checkPackage(installerUid, mRequiredVerifierPackage);
+ if (DEBUG_VERIFY) {
+ Slog.i(TAG, "disable verification for instant app");
+ }
+ return false;
+ } catch (SecurityException ignore) { }
+ }
+ }
}
if (ensureVerifyAppsEnabled) {
@@ -15807,8 +15824,11 @@ public class PackageManagerService extends IPackageManager.Stub
final int requiredUid = mRequiredVerifierPackage == null ? -1
: getPackageUid(mRequiredVerifierPackage, MATCH_DEBUG_TRIAGED_MISSING,
verifierUser.getIdentifier());
+ final int installerUid =
+ verificationInfo == null ? -1 : verificationInfo.installerUid;
if (!origin.existing && requiredUid != -1
- && isVerificationEnabled(verifierUser.getIdentifier(), installFlags)) {
+ && isVerificationEnabled(
+ verifierUser.getIdentifier(), installFlags, installerUid)) {
final Intent verification = new Intent(
Intent.ACTION_PACKAGE_NEEDS_VERIFICATION);
verification.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index b1154227b204..a64ab438feed 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -223,6 +223,7 @@ public class UserManagerService extends IUserManager.Stub {
// Tron counters
private static final String TRON_GUEST_CREATED = "users_guest_created";
private static final String TRON_USER_CREATED = "users_user_created";
+ private static final String TRON_DEMO_CREATED = "users_demo_created";
private final Context mContext;
private final PackageManagerService mPm;
@@ -2523,7 +2524,8 @@ public class UserManagerService extends IUserManager.Stub {
addedIntent.putExtra(Intent.EXTRA_USER_HANDLE, userId);
mContext.sendBroadcastAsUser(addedIntent, UserHandle.ALL,
android.Manifest.permission.MANAGE_USERS);
- MetricsLogger.count(mContext, isGuest ? TRON_GUEST_CREATED : TRON_USER_CREATED, 1);
+ MetricsLogger.count(mContext, isGuest ? TRON_GUEST_CREATED
+ : (isDemo ? TRON_DEMO_CREATED : TRON_USER_CREATED), 1);
} finally {
Binder.restoreCallingIdentity(ident);
}
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 8eebb10d266d..f46aeac81073 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -7692,6 +7692,8 @@ public class PhoneWindowManager implements WindowManagerPolicy {
break;
case HapticFeedbackConstants.CONTEXT_CLICK:
return VibrationEffect.get(VibrationEffect.EFFECT_TICK);
+ case HapticFeedbackConstants.VIRTUAL_KEY_RELEASE:
+ return VibrationEffect.get(VibrationEffect.EFFECT_TICK);
default:
return null;
}
diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java
index 525e0ff1e8dd..71ecaf61da48 100644
--- a/services/core/java/com/android/server/wm/AppWindowToken.java
+++ b/services/core/java/com/android/server/wm/AppWindowToken.java
@@ -1107,7 +1107,7 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree
mAppAnimator.lastFreezeDuration = 0;
mService.mAppsFreezingScreen++;
if (mService.mAppsFreezingScreen == 1) {
- mService.startFreezingDisplayLocked(false, 0, 0);
+ mService.startFreezingDisplayLocked(false, 0, 0, getDisplayContent());
mService.mH.removeMessages(H.APP_FREEZE_TIMEOUT);
mService.mH.sendEmptyMessageDelayed(H.APP_FREEZE_TIMEOUT, 2000);
}
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index b5476d7e056b..a8e0d761afc3 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -987,7 +987,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
}
if (!rotateSeamlessly) {
- mService.startFreezingDisplayLocked(inTransaction, anim[0], anim[1]);
+ mService.startFreezingDisplayLocked(inTransaction, anim[0], anim[1], this);
// startFreezingDisplayLocked can reset the ScreenRotationAnimation.
screenRotationAnimation = mService.mAnimator.getScreenRotationAnimationLocked(
mDisplayId);
@@ -1162,6 +1162,8 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
final int dh = displayInfo.logicalHeight;
config.orientation = (dw <= dh) ? Configuration.ORIENTATION_PORTRAIT :
Configuration.ORIENTATION_LANDSCAPE;
+ config.setRotation(displayInfo.rotation);
+
config.screenWidthDp =
(int)(mService.mPolicy.getConfigDisplayWidth(dw, dh, displayInfo.rotation,
config.uiMode, mDisplayId) / mDisplayMetrics.density);
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotController.java b/services/core/java/com/android/server/wm/TaskSnapshotController.java
index 1f7ef5014d36..bf8fabd326db 100644
--- a/services/core/java/com/android/server/wm/TaskSnapshotController.java
+++ b/services/core/java/com/android/server/wm/TaskSnapshotController.java
@@ -17,15 +17,13 @@
package com.android.server.wm;
import static android.app.ActivityManager.ENABLE_TASK_SNAPSHOTS;
-import static android.graphics.Bitmap.Config.ARGB_8888;
-import static android.graphics.Bitmap.Config.HARDWARE;
import android.annotation.Nullable;
import android.app.ActivityManager;
import android.app.ActivityManager.StackId;
import android.app.ActivityManager.TaskSnapshot;
+import android.content.pm.PackageManager;
import android.graphics.Bitmap;
-import android.graphics.Canvas;
import android.graphics.GraphicBuffer;
import android.graphics.Rect;
import android.os.Environment;
@@ -89,9 +87,16 @@ class TaskSnapshotController {
private final ArraySet<Task> mTmpTasks = new ArraySet<>();
private final Handler mHandler = new Handler();
+ /**
+ * Flag indicating whether we are running on an Android TV device.
+ */
+ private final boolean mIsRunningOnTv;
+
TaskSnapshotController(WindowManagerService service) {
mService = service;
mCache = new TaskSnapshotCache(mService, mLoader);
+ mIsRunningOnTv = mService.mContext.getPackageManager().hasSystemFeature(
+ PackageManager.FEATURE_LEANBACK);
}
void systemReady() {
@@ -112,7 +117,7 @@ class TaskSnapshotController {
}
private void handleClosingApps(ArraySet<AppWindowToken> closingApps) {
- if (!ENABLE_TASK_SNAPSHOTS || ActivityManager.isLowRamDeviceStatic()) {
+ if (shouldDisableSnapshots()) {
return;
}
@@ -188,6 +193,10 @@ class TaskSnapshotController {
1f /* scale */);
}
+ private boolean shouldDisableSnapshots() {
+ return !ENABLE_TASK_SNAPSHOTS || ActivityManager.isLowRamDeviceStatic() || mIsRunningOnTv;
+ }
+
private Rect minRect(Rect rect1, Rect rect2) {
return new Rect(Math.min(rect1.left, rect2.left),
Math.min(rect1.top, rect2.top),
@@ -301,7 +310,7 @@ class TaskSnapshotController {
* Called when screen is being turned off.
*/
void screenTurningOff(ScreenOffListener listener) {
- if (!ENABLE_TASK_SNAPSHOTS || ActivityManager.isLowRamDeviceStatic()) {
+ if (shouldDisableSnapshots()) {
listener.onScreenOff();
return;
}
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 9d1b3d9ed81a..4b066c0cad6e 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -20,7 +20,6 @@ import static android.Manifest.permission.MANAGE_APP_TOKENS;
import static android.Manifest.permission.READ_FRAME_BUFFER;
import static android.Manifest.permission.REGISTER_WINDOW_MANAGER_LISTENERS;
import static android.app.ActivityManager.DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT;
-import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
import static android.app.AppOpsManager.OP_SYSTEM_ALERT_WINDOW;
import static android.app.StatusBarManager.DISABLE_MASK;
import static android.app.admin.DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED;
@@ -33,6 +32,7 @@ import static android.os.Process.THREAD_PRIORITY_DISPLAY;
import static android.os.Process.myPid;
import static android.os.UserHandle.USER_NULL;
import static android.view.Display.DEFAULT_DISPLAY;
+import static android.view.Display.INVALID_DISPLAY;
import static android.view.WindowManager.DOCKED_INVALID;
import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW;
import static android.view.WindowManager.LayoutParams.FIRST_SUB_WINDOW;
@@ -601,7 +601,7 @@ public class WindowManagerService extends IWindowManager.Stub
final UnknownAppVisibilityController mUnknownAppVisibilityController =
new UnknownAppVisibilityController(this);
- final TaskSnapshotController mTaskSnapshotController = new TaskSnapshotController(this);
+ final TaskSnapshotController mTaskSnapshotController;
boolean mIsTouchDevice;
@@ -724,6 +724,9 @@ public class WindowManagerService extends IWindowManager.Stub
// For frozen screen animations.
private int mExitAnimId, mEnterAnimId;
+ // The display that the rotation animation is applying to.
+ private int mFrozenDisplayId;
+
/** Skip repeated AppWindowTokens initialization. Note that AppWindowsToken's version of this
* is a long initialized to Long.MIN_VALUE so that it doesn't match this value on startup. */
int mTransactionSequence;
@@ -989,6 +992,7 @@ public class WindowManagerService extends IWindowManager.Stub
mWindowPlacerLocked = new WindowSurfacePlacer(this);
mPolicy = policy;
+ mTaskSnapshotController = new TaskSnapshotController(this);
LocalServices.addService(WindowManagerPolicy.class, mPolicy);
@@ -2449,7 +2453,7 @@ public class WindowManagerService extends IWindowManager.Stub
} else {
mPolicy.selectRotationAnimationLw(anim);
}
- startFreezingDisplayLocked(false, anim[0], anim[1]);
+ startFreezingDisplayLocked(false, anim[0], anim[1], displayContent);
config = new Configuration(mTempConfiguration);
}
}
@@ -5555,7 +5559,7 @@ public class WindowManagerService extends IWindowManager.Stub
if (configChanged) {
mWaitingForConfig = true;
startFreezingDisplayLocked(false /* inTransaction */, 0 /* exitAnim */,
- 0 /* enterAnim */);
+ 0 /* enterAnim */, displayContent);
mH.obtainMessage(H.SEND_NEW_CONFIGURATION, displayId).sendToTarget();
}
@@ -5862,6 +5866,12 @@ public class WindowManagerService extends IWindowManager.Stub
}
void startFreezingDisplayLocked(boolean inTransaction, int exitAnim, int enterAnim) {
+ startFreezingDisplayLocked(inTransaction, exitAnim, enterAnim,
+ getDefaultDisplayContentLocked());
+ }
+
+ void startFreezingDisplayLocked(boolean inTransaction, int exitAnim, int enterAnim,
+ DisplayContent displayContent) {
if (mDisplayFrozen) {
return;
}
@@ -5882,6 +5892,10 @@ public class WindowManagerService extends IWindowManager.Stub
mDisplayFreezeTime = SystemClock.elapsedRealtime();
mLastFinishedFreezeSource = null;
+ // {@link mDisplayFrozen} prevents us from freezing on multiple displays at the same time.
+ // As a result, we only track the display that has initially froze the screen.
+ mFrozenDisplayId = displayContent.getDisplayId();
+
mInputMonitor.freezeInputDispatchingLw();
// Clear the last input window -- that is just used for
@@ -5901,10 +5915,8 @@ public class WindowManagerService extends IWindowManager.Stub
if (CUSTOM_SCREEN_ROTATION) {
mExitAnimId = exitAnim;
mEnterAnimId = enterAnim;
- final DisplayContent displayContent = getDefaultDisplayContentLocked();
- final int displayId = displayContent.getDisplayId();
ScreenRotationAnimation screenRotationAnimation =
- mAnimator.getScreenRotationAnimationLocked(displayId);
+ mAnimator.getScreenRotationAnimationLocked(mFrozenDisplayId);
if (screenRotationAnimation != null) {
screenRotationAnimation.kill();
}
@@ -5915,8 +5927,10 @@ public class WindowManagerService extends IWindowManager.Stub
// TODO(multidisplay): rotation on main screen only.
displayContent.updateDisplayInfo();
screenRotationAnimation = new ScreenRotationAnimation(mContext, displayContent,
- mFxSession, inTransaction, mPolicy.isDefaultOrientationForced(), isSecure, this);
- mAnimator.setScreenRotationAnimationLocked(displayId, screenRotationAnimation);
+ mFxSession, inTransaction, mPolicy.isDefaultOrientationForced(), isSecure,
+ this);
+ mAnimator.setScreenRotationAnimationLocked(mFrozenDisplayId,
+ screenRotationAnimation);
}
}
@@ -5940,6 +5954,13 @@ public class WindowManagerService extends IWindowManager.Stub
if (DEBUG_ORIENTATION) Slog.d(TAG_WM,
"stopFreezingDisplayLocked: Unfreezing now");
+ final DisplayContent displayContent = mRoot.getDisplayContent(mFrozenDisplayId);
+
+ // We must make a local copy of the displayId as it can be potentially overwritten later on
+ // in this method. For example, {@link startFreezingDisplayLocked} may be called as a result
+ // of update rotation, but we reference the frozen display after that call in this method.
+ final int displayId = mFrozenDisplayId;
+ mFrozenDisplayId = INVALID_DISPLAY;
mDisplayFrozen = false;
mLastDisplayFreezeDuration = (int)(SystemClock.elapsedRealtime() - mDisplayFreezeTime);
StringBuilder sb = new StringBuilder(128);
@@ -5958,8 +5979,6 @@ public class WindowManagerService extends IWindowManager.Stub
boolean updateRotation = false;
- final DisplayContent displayContent = getDefaultDisplayContentLocked();
- final int displayId = displayContent.getDisplayId();
ScreenRotationAnimation screenRotationAnimation =
mAnimator.getScreenRotationAnimationLocked(displayId);
if (CUSTOM_SCREEN_ROTATION && screenRotationAnimation != null
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index f74948f8e7f0..1d08c2ec9151 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -2231,15 +2231,14 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
mWinAnimator.applyEnterAnimationLocked();
}
- if (isConfigChanged()) {
- final Configuration globalConfig = mService.mRoot.getConfiguration();
- final Configuration overrideConfig = getMergedOverrideConfiguration();
- mergedConfiguration.setConfiguration(globalConfig, overrideConfig);
- if (DEBUG_CONFIGURATION) Slog.i(TAG, "Window " + this
- + " visible with new global config: " + globalConfig
- + " merged override config: " + overrideConfig);
- mLastReportedConfiguration.setTo(getConfiguration());
- }
+ // always report back the new configuration
+ final Configuration globalConfig = mService.mRoot.getConfiguration();
+ final Configuration overrideConfig = getMergedOverrideConfiguration();
+ mergedConfiguration.setConfiguration(globalConfig, overrideConfig);
+ if (DEBUG_CONFIGURATION) Slog.i(TAG, "Window " + this
+ + " reporting new global config: " + globalConfig
+ + " merged override config: " + overrideConfig);
+ mLastReportedConfiguration.setTo(getConfiguration());
}
void adjustStartingWindowFlags() {
diff --git a/services/core/jni/Android.mk b/services/core/jni/Android.mk
index 362dd9fbb17a..a3d28bbd3754 100644
--- a/services/core/jni/Android.mk
+++ b/services/core/jni/Android.mk
@@ -95,6 +95,7 @@ LOCAL_SHARED_LIBRARIES += \
android.hardware.ir@1.0 \
android.hardware.light@2.0 \
android.hardware.power@1.0 \
+ android.hardware.power@1.1 \
android.hardware.tetheroffload.config@1.0 \
android.hardware.thermal@1.0 \
android.hardware.tv.cec@1.0 \
diff --git a/services/core/jni/com_android_server_am_BatteryStatsService.cpp b/services/core/jni/com_android_server_am_BatteryStatsService.cpp
index 57bb9fedc135..37ae78254ce2 100644
--- a/services/core/jni/com_android_server_am_BatteryStatsService.cpp
+++ b/services/core/jni/com_android_server_am_BatteryStatsService.cpp
@@ -29,6 +29,7 @@
#include <unistd.h>
#include <android/hardware/power/1.0/IPower.h>
+#include <android/hardware/power/1.1/IPower.h>
#include <android_runtime/AndroidRuntime.h>
#include <jni.h>
@@ -46,6 +47,8 @@ using android::hardware::power::V1_0::IPower;
using android::hardware::power::V1_0::PowerStatePlatformSleepState;
using android::hardware::power::V1_0::PowerStateVoter;
using android::hardware::power::V1_0::Status;
+using android::hardware::power::V1_1::PowerStateSubsystem;
+using android::hardware::power::V1_1::PowerStateSubsystemSleepState;
using android::hardware::hidl_vec;
namespace android
@@ -263,9 +266,105 @@ static jint getPlatformLowPowerStats(JNIEnv* env, jobject /* clazz */, jobject o
return total_added;
}
+static jint getSubsystemLowPowerStats(JNIEnv* env, jobject /* clazz */, jobject outBuf) {
+ char *output = (char*)env->GetDirectBufferAddress(outBuf);
+ char *offset = output;
+ int remaining = (int)env->GetDirectBufferCapacity(outBuf);
+ int total_added = -1;
+
+ //This is a IPower 1.1 API
+ sp<android::hardware::power::V1_1::IPower> gPowerHal_1_1 = nullptr;
+
+ if (outBuf == NULL) {
+ jniThrowException(env, "java/lang/NullPointerException", "null argument");
+ return -1;
+ }
+
+ {
+ std::lock_guard<std::mutex> lock(gPowerHalMutex);
+ if (!getPowerHal()) {
+ ALOGE("Power Hal not loaded");
+ return -1;
+ }
+
+ //Trying to cast to 1.1, this will succeed only for devices supporting 1.1
+ gPowerHal_1_1 = android::hardware::power::V1_1::IPower::castFrom(gPowerHal);
+ if (gPowerHal_1_1 == nullptr) {
+ //This device does not support IPower@1.1, exiting gracefully
+ return 0;
+ }
+
+ Return<void> ret = gPowerHal_1_1->getSubsystemLowPowerStats(
+ [&offset, &remaining, &total_added](hidl_vec<PowerStateSubsystem> subsystems,
+ Status status) {
+
+ if (status != Status::SUCCESS)
+ return;
+
+ for (size_t i = 0; i < subsystems.size(); i++) {
+ int added;
+ const PowerStateSubsystem &subsystem = subsystems[i];
+
+ added = snprintf(offset, remaining,
+ "subsystem_%zu name=%s ", i + 1, subsystem.name.c_str());
+ if (added < 0) {
+ break;
+ }
+
+ if (added > remaining) {
+ added = remaining;
+ }
+
+ offset += added;
+ remaining -= added;
+ total_added += added;
+
+ for (size_t j = 0; j < subsystem.states.size(); j++) {
+ const PowerStateSubsystemSleepState& state = subsystem.states[j];
+ added = snprintf(offset, remaining,
+ "state_%zu name=%s time=%" PRIu64 " count=%" PRIu64 " last entry TS(ms)=%" PRIu64 " ",
+ j + 1, state.name.c_str(), state.residencyInMsecSinceBoot,
+ state.totalTransitions, state.lastEntryTimestampMs);
+ if (added < 0) {
+ break;
+ }
+
+ if (added > remaining) {
+ added = remaining;
+ }
+
+ offset += added;
+ remaining -= added;
+ total_added += added;
+ }
+
+ if (remaining <= 0) {
+ /* rewrite NULL character*/
+ offset--;
+ total_added--;
+ ALOGE("PowerHal: buffer not enough");
+ break;
+ }
+ }
+ }
+ );
+
+ if (!ret.isOk()) {
+ ALOGE("getSubsystemLowPowerStats() failed: power HAL service not available");
+ gPowerHal = nullptr;
+ return -1;
+ }
+ }
+
+ *offset = 0;
+ total_added += 1;
+ return total_added;
+}
+
static const JNINativeMethod method_table[] = {
{ "nativeWaitWakeup", "(Ljava/nio/ByteBuffer;)I", (void*)nativeWaitWakeup },
{ "getPlatformLowPowerStats", "(Ljava/nio/ByteBuffer;)I", (void*)getPlatformLowPowerStats },
+ { "getSubsystemLowPowerStats", "(Ljava/nio/ByteBuffer;)I", (void*)getSubsystemLowPowerStats },
};
int register_android_server_BatteryStatsService(JNIEnv *env)
diff --git a/services/tests/servicestests/AndroidManifest.xml b/services/tests/servicestests/AndroidManifest.xml
index 686dad4a8340..e12032d8d4c0 100644
--- a/services/tests/servicestests/AndroidManifest.xml
+++ b/services/tests/servicestests/AndroidManifest.xml
@@ -52,6 +52,10 @@
<uses-permission android:name="android.permission.CHANGE_COMPONENT_ENABLED_STATE" />
<uses-permission android:name="android.permission.DELETE_PACKAGES" />
+ <!-- Uses API introduced in O (26) -->
+ <uses-sdk android:minSdkVersion="1"
+ android:targetSdkVersion="26"/>
+
<application>
<uses-library android:name="android.test.runner" />
diff --git a/services/tests/servicestests/src/com/android/server/accounts/AccountManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/accounts/AccountManagerServiceTest.java
index 36e9b3f8a9e4..791d3e997f3b 100644
--- a/services/tests/servicestests/src/com/android/server/accounts/AccountManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/accounts/AccountManagerServiceTest.java
@@ -1484,6 +1484,31 @@ public class AccountManagerServiceTest extends AndroidTestCase {
}
@SmallTest
+ public void testGetAccountsByTypeForPackageWhenTypeIsNull() throws Exception {
+ unlockSystemUser();
+ HashMap<String, Integer> visibility1 = new HashMap<>();
+ visibility1.put(AccountManagerServiceTestFixtures.CALLER_PACKAGE,
+ AccountManager.VISIBILITY_USER_MANAGED_VISIBLE);
+
+ HashMap<String, Integer> visibility2 = new HashMap<>();
+ visibility2.put(AccountManagerServiceTestFixtures.CALLER_PACKAGE,
+ AccountManager.VISIBILITY_USER_MANAGED_NOT_VISIBLE);
+
+ mAms.addAccountExplicitlyWithVisibility(
+ AccountManagerServiceTestFixtures.ACCOUNT_SUCCESS, "P11", null, visibility1);
+ mAms.addAccountExplicitlyWithVisibility(
+ AccountManagerServiceTestFixtures.ACCOUNT_INTERVENE, "P12", null, visibility2);
+
+ Account[] accounts = mAms.getAccountsByTypeForPackage(
+ null, "otherPackageName",
+ AccountManagerServiceTestFixtures.CALLER_PACKAGE);
+ // Only get the USER_MANAGED_NOT_VISIBLE account.
+ assertEquals(1, accounts.length);
+ assertEquals(AccountManagerServiceTestFixtures.ACCOUNT_NAME_SUCCESS, accounts[0].name);
+ assertEquals(AccountManagerServiceTestFixtures.ACCOUNT_TYPE_1, accounts[0].type);
+ }
+
+ @SmallTest
public void testGetAuthTokenLabelWithNullAccountType() throws Exception {
unlockSystemUser();
try {
@@ -2341,6 +2366,224 @@ public class AccountManagerServiceTest extends AndroidTestCase {
}
@SmallTest
+ public void testGetAccountByTypeAndFeaturesWithNullResponse() throws Exception {
+ unlockSystemUser();
+ try {
+ mAms.getAccountByTypeAndFeatures(
+ null, // response
+ AccountManagerServiceTestFixtures.ACCOUNT_TYPE_1,
+ AccountManagerServiceTestFixtures.ACCOUNT_FEATURES,
+ "testpackage"); // opPackageName
+ fail("IllegalArgumentException expected. But no exception was thrown.");
+ } catch (IllegalArgumentException e) {
+ // IllegalArgumentException is expected.
+ }
+ }
+
+ @SmallTest
+ public void testGetAccountByTypeAndFeaturesWithNullAccountType() throws Exception {
+ unlockSystemUser();
+ try {
+ mAms.getAccountByTypeAndFeatures(
+ mMockAccountManagerResponse, // response
+ null, // accountType
+ AccountManagerServiceTestFixtures.ACCOUNT_FEATURES,
+ "testpackage"); // opPackageName
+ fail("IllegalArgumentException expected. But no exception was thrown.");
+ } catch (IllegalArgumentException e) {
+ // IllegalArgumentException is expected.
+ }
+ }
+
+ @SmallTest
+ public void testGetAccountByTypeAndFeaturesWithNoFeaturesAndNoAccount() throws Exception {
+ unlockSystemUser();
+ mAms.getAccountByTypeAndFeatures(
+ mMockAccountManagerResponse,
+ AccountManagerServiceTestFixtures.ACCOUNT_TYPE_1,
+ null,
+ "testpackage");
+ verify(mMockAccountManagerResponse).onResult(mBundleCaptor.capture());
+ Bundle result = mBundleCaptor.getValue();
+ String accountName = result.getString(AccountManager.KEY_ACCOUNT_NAME);
+ String accountType = result.getString(AccountManager.KEY_ACCOUNT_TYPE);
+ assertEquals(null, accountName);
+ assertEquals(null, accountType);
+ }
+
+ @SmallTest
+ public void testGetAccountByTypeAndFeaturesWithNoFeaturesAndOneVisibleAccount()
+ throws Exception {
+ unlockSystemUser();
+ mAms.addAccountExplicitly(AccountManagerServiceTestFixtures.ACCOUNT_SUCCESS, "p11", null);
+ mAms.getAccountByTypeAndFeatures(
+ mMockAccountManagerResponse,
+ AccountManagerServiceTestFixtures.ACCOUNT_TYPE_1,
+ null,
+ "testpackage");
+ verify(mMockAccountManagerResponse).onResult(mBundleCaptor.capture());
+ Bundle result = mBundleCaptor.getValue();
+ String accountName = result.getString(AccountManager.KEY_ACCOUNT_NAME);
+ String accountType = result.getString(AccountManager.KEY_ACCOUNT_TYPE);
+ assertEquals(AccountManagerServiceTestFixtures.ACCOUNT_NAME_SUCCESS, accountName);
+ assertEquals(AccountManagerServiceTestFixtures.ACCOUNT_TYPE_1, accountType);
+ }
+
+ @SmallTest
+ public void testGetAccountByTypeAndFeaturesWithNoFeaturesAndOneNotVisibleAccount()
+ throws Exception {
+ unlockSystemUser();
+ HashMap<String, Integer> visibility = new HashMap<>();
+ visibility.put(AccountManagerServiceTestFixtures.CALLER_PACKAGE,
+ AccountManager.VISIBILITY_USER_MANAGED_NOT_VISIBLE);
+ mAms.addAccountExplicitlyWithVisibility(
+ AccountManagerServiceTestFixtures.ACCOUNT_SUCCESS, "p11", null, visibility);
+ mAms.getAccountByTypeAndFeatures(
+ mMockAccountManagerResponse,
+ AccountManagerServiceTestFixtures.ACCOUNT_TYPE_1,
+ null,
+ AccountManagerServiceTestFixtures.CALLER_PACKAGE);
+ verify(mMockContext).startActivityAsUser(mIntentCaptor.capture(), eq(UserHandle.SYSTEM));
+ Intent intent = mIntentCaptor.getValue();
+ Account[] accounts = (Account[]) intent.getExtra(AccountManager.KEY_ACCOUNTS);
+ assertEquals(1, accounts.length);
+ assertEquals(AccountManagerServiceTestFixtures.ACCOUNT_SUCCESS, accounts[0]);
+ }
+
+ @SmallTest
+ public void testGetAccountByTypeAndFeaturesWithNoFeaturesAndTwoAccounts() throws Exception {
+ unlockSystemUser();
+ mAms.addAccountExplicitly(AccountManagerServiceTestFixtures.ACCOUNT_SUCCESS, "p11", null);
+ mAms.addAccountExplicitly(AccountManagerServiceTestFixtures.ACCOUNT_INTERVENE, "p12", null);
+
+ mAms.getAccountByTypeAndFeatures(
+ mMockAccountManagerResponse,
+ AccountManagerServiceTestFixtures.ACCOUNT_TYPE_1,
+ null,
+ "testpackage");
+ verify(mMockContext).startActivityAsUser(mIntentCaptor.capture(), eq(UserHandle.SYSTEM));
+ Intent intent = mIntentCaptor.getValue();
+ Account[] accounts = (Account[]) intent.getExtra(AccountManager.KEY_ACCOUNTS);
+ assertEquals(2, accounts.length);
+ if (accounts[0].equals(AccountManagerServiceTestFixtures.ACCOUNT_SUCCESS)) {
+ assertEquals(AccountManagerServiceTestFixtures.ACCOUNT_SUCCESS, accounts[0]);
+ assertEquals(AccountManagerServiceTestFixtures.ACCOUNT_INTERVENE, accounts[1]);
+ } else {
+ assertEquals(AccountManagerServiceTestFixtures.ACCOUNT_INTERVENE, accounts[0]);
+ assertEquals(AccountManagerServiceTestFixtures.ACCOUNT_SUCCESS, accounts[1]);
+ }
+ }
+
+ @SmallTest
+ public void testGetAccountByTypeAndFeaturesWithFeaturesAndNoAccount() throws Exception {
+ unlockSystemUser();
+ final CountDownLatch latch = new CountDownLatch(1);
+ mAms.getAccountByTypeAndFeatures(
+ mMockAccountManagerResponse,
+ AccountManagerServiceTestFixtures.ACCOUNT_TYPE_1,
+ AccountManagerServiceTestFixtures.ACCOUNT_FEATURES,
+ "testpackage");
+ waitForLatch(latch);
+ verify(mMockAccountManagerResponse).onResult(mBundleCaptor.capture());
+ Bundle result = mBundleCaptor.getValue();
+ String accountName = result.getString(AccountManager.KEY_ACCOUNT_NAME);
+ String accountType = result.getString(AccountManager.KEY_ACCOUNT_TYPE);
+ assertEquals(null, accountName);
+ assertEquals(null, accountType);
+ }
+
+ @SmallTest
+ public void testGetAccountByTypeAndFeaturesWithFeaturesAndNoQualifiedAccount()
+ throws Exception {
+ unlockSystemUser();
+ mAms.addAccountExplicitly(AccountManagerServiceTestFixtures.ACCOUNT_INTERVENE, "p12", null);
+ final CountDownLatch latch = new CountDownLatch(1);
+ mAms.getAccountByTypeAndFeatures(
+ mMockAccountManagerResponse,
+ AccountManagerServiceTestFixtures.ACCOUNT_TYPE_1,
+ AccountManagerServiceTestFixtures.ACCOUNT_FEATURES,
+ "testpackage");
+ waitForLatch(latch);
+ verify(mMockAccountManagerResponse).onResult(mBundleCaptor.capture());
+ Bundle result = mBundleCaptor.getValue();
+ String accountName = result.getString(AccountManager.KEY_ACCOUNT_NAME);
+ String accountType = result.getString(AccountManager.KEY_ACCOUNT_TYPE);
+ assertEquals(null, accountName);
+ assertEquals(null, accountType);
+ }
+
+ @SmallTest
+ public void testGetAccountByTypeAndFeaturesWithFeaturesAndOneQualifiedAccount()
+ throws Exception {
+ unlockSystemUser();
+ mAms.addAccountExplicitly(AccountManagerServiceTestFixtures.ACCOUNT_SUCCESS, "p11", null);
+ mAms.addAccountExplicitly(AccountManagerServiceTestFixtures.ACCOUNT_INTERVENE, "p12", null);
+ final CountDownLatch latch = new CountDownLatch(1);
+ mAms.getAccountByTypeAndFeatures(
+ mMockAccountManagerResponse,
+ AccountManagerServiceTestFixtures.ACCOUNT_TYPE_1,
+ AccountManagerServiceTestFixtures.ACCOUNT_FEATURES,
+ "testpackage");
+ waitForLatch(latch);
+ verify(mMockAccountManagerResponse).onResult(mBundleCaptor.capture());
+ Bundle result = mBundleCaptor.getValue();
+ String accountName = result.getString(AccountManager.KEY_ACCOUNT_NAME);
+ String accountType = result.getString(AccountManager.KEY_ACCOUNT_TYPE);
+ assertEquals(AccountManagerServiceTestFixtures.ACCOUNT_NAME_SUCCESS, accountName);
+ assertEquals(AccountManagerServiceTestFixtures.ACCOUNT_TYPE_1, accountType);
+ }
+
+ @SmallTest
+ public void testGetAccountByTypeAndFeaturesWithFeaturesAndOneQualifiedNotVisibleAccount()
+ throws Exception {
+ unlockSystemUser();
+ HashMap<String, Integer> visibility = new HashMap<>();
+ visibility.put(AccountManagerServiceTestFixtures.CALLER_PACKAGE,
+ AccountManager.VISIBILITY_USER_MANAGED_NOT_VISIBLE);
+ mAms.addAccountExplicitlyWithVisibility(
+ AccountManagerServiceTestFixtures.ACCOUNT_SUCCESS, "p11", null, visibility);
+ final CountDownLatch latch = new CountDownLatch(1);
+ mAms.getAccountByTypeAndFeatures(
+ mMockAccountManagerResponse,
+ AccountManagerServiceTestFixtures.ACCOUNT_TYPE_1,
+ AccountManagerServiceTestFixtures.ACCOUNT_FEATURES,
+ AccountManagerServiceTestFixtures.CALLER_PACKAGE);
+ waitForLatch(latch);
+ verify(mMockContext).startActivityAsUser(mIntentCaptor.capture(), eq(UserHandle.SYSTEM));
+ Intent intent = mIntentCaptor.getValue();
+ Account[] accounts = (Account[]) intent.getExtra(AccountManager.KEY_ACCOUNTS);
+ assertEquals(1, accounts.length);
+ assertEquals(AccountManagerServiceTestFixtures.ACCOUNT_SUCCESS, accounts[0]);
+ }
+
+ @SmallTest
+ public void testGetAccountByTypeAndFeaturesWithFeaturesAndTwoQualifiedAccount()
+ throws Exception {
+ unlockSystemUser();
+ mAms.addAccountExplicitly(AccountManagerServiceTestFixtures.ACCOUNT_SUCCESS, "p11", null);
+ mAms.addAccountExplicitly(AccountManagerServiceTestFixtures.ACCOUNT_SUCCESS_2, "p12", null);
+ mAms.addAccountExplicitly(AccountManagerServiceTestFixtures.ACCOUNT_INTERVENE, "p13", null);
+ final CountDownLatch latch = new CountDownLatch(1);
+ mAms.getAccountByTypeAndFeatures(
+ mMockAccountManagerResponse,
+ AccountManagerServiceTestFixtures.ACCOUNT_TYPE_1,
+ AccountManagerServiceTestFixtures.ACCOUNT_FEATURES,
+ "testpackage");
+ waitForLatch(latch);
+ verify(mMockContext).startActivityAsUser(mIntentCaptor.capture(), eq(UserHandle.SYSTEM));
+ Intent intent = mIntentCaptor.getValue();
+ Account[] accounts = (Account[]) intent.getExtra(AccountManager.KEY_ACCOUNTS);
+ assertEquals(2, accounts.length);
+ if (accounts[0].equals(AccountManagerServiceTestFixtures.ACCOUNT_SUCCESS)) {
+ assertEquals(AccountManagerServiceTestFixtures.ACCOUNT_SUCCESS, accounts[0]);
+ assertEquals(AccountManagerServiceTestFixtures.ACCOUNT_SUCCESS_2, accounts[1]);
+ } else {
+ assertEquals(AccountManagerServiceTestFixtures.ACCOUNT_SUCCESS_2, accounts[0]);
+ assertEquals(AccountManagerServiceTestFixtures.ACCOUNT_SUCCESS, accounts[1]);
+ }
+ }
+
+ @SmallTest
public void testGetAccountsByFeaturesWithNullResponse() throws Exception {
unlockSystemUser();
try {
diff --git a/services/tests/servicestests/src/com/android/server/accounts/AccountManagerServiceTestFixtures.java b/services/tests/servicestests/src/com/android/server/accounts/AccountManagerServiceTestFixtures.java
index d176a0d56fb1..73f30d9f9e79 100644
--- a/services/tests/servicestests/src/com/android/server/accounts/AccountManagerServiceTestFixtures.java
+++ b/services/tests/servicestests/src/com/android/server/accounts/AccountManagerServiceTestFixtures.java
@@ -34,6 +34,7 @@ public final class AccountManagerServiceTestFixtures {
public static final String KEY_OPTIONS_BUNDLE =
"account_manager_service_test:option_bundle_key";
public static final String ACCOUNT_NAME_SUCCESS = "success_on_return@fixture.com";
+ public static final String ACCOUNT_NAME_SUCCESS_2 = "success_on_return_2@fixture.com";
public static final String ACCOUNT_NAME_INTERVENE = "intervene@fixture.com";
public static final String ACCOUNT_NAME_ERROR = "error@fixture.com";
@@ -69,6 +70,8 @@ public final class AccountManagerServiceTestFixtures {
public static final Account ACCOUNT_SUCCESS =
new Account(ACCOUNT_NAME_SUCCESS, ACCOUNT_TYPE_1);
+ public static final Account ACCOUNT_SUCCESS_2 =
+ new Account(ACCOUNT_NAME_SUCCESS_2, ACCOUNT_TYPE_1);
public static final Account ACCOUNT_INTERVENE =
new Account(ACCOUNT_NAME_INTERVENE, ACCOUNT_TYPE_1);
public static final Account ACCOUNT_ERROR =
diff --git a/services/tests/servicestests/src/com/android/server/accounts/TestAccountType1Authenticator.java b/services/tests/servicestests/src/com/android/server/accounts/TestAccountType1Authenticator.java
index eb839a2668f7..8106364477d9 100644
--- a/services/tests/servicestests/src/com/android/server/accounts/TestAccountType1Authenticator.java
+++ b/services/tests/servicestests/src/com/android/server/accounts/TestAccountType1Authenticator.java
@@ -242,6 +242,8 @@ public class TestAccountType1Authenticator extends AbstractAccountAuthenticator
if (account.name.equals(AccountManagerServiceTestFixtures.ACCOUNT_NAME_SUCCESS)) {
// fill bundle with true.
result.putBoolean(AccountManager.KEY_BOOLEAN_RESULT, true);
+ } else if (account.name.equals(AccountManagerServiceTestFixtures.ACCOUNT_NAME_SUCCESS_2)) {
+ result.putBoolean(AccountManager.KEY_BOOLEAN_RESULT, true);
} else if (account.name.equals(AccountManagerServiceTestFixtures.ACCOUNT_NAME_INTERVENE)) {
// fill bundle with false.
result.putBoolean(AccountManager.KEY_BOOLEAN_RESULT, false);
diff --git a/telecomm/java/android/telecom/TelecomManager.java b/telecomm/java/android/telecom/TelecomManager.java
index 7a35cd3ac5c7..331328d63841 100644
--- a/telecomm/java/android/telecom/TelecomManager.java
+++ b/telecomm/java/android/telecom/TelecomManager.java
@@ -17,7 +17,9 @@ package android.telecom;
import android.Manifest;
import android.annotation.RequiresPermission;
import android.annotation.SuppressAutoDoc;
+import android.annotation.SuppressLint;
import android.annotation.SystemApi;
+import android.annotation.SystemService;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
@@ -48,6 +50,7 @@ import java.util.List;
* descriptions.
*/
@SuppressAutoDoc
+@SystemService(Context.TELECOM_SERVICE)
public class TelecomManager {
/**
@@ -763,6 +766,10 @@ public class TelecomManager {
* @hide
*/
@SystemApi
+ @RequiresPermission(anyOf = {
+ android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE,
+ android.Manifest.permission.READ_PHONE_STATE
+ })
public List<PhoneAccountHandle> getPhoneAccountsSupportingScheme(String uriScheme) {
try {
if (isServiceConnected()) {
@@ -844,6 +851,7 @@ public class TelecomManager {
* @hide
*/
@SystemApi
+ @SuppressLint("Doclava125")
public List<PhoneAccountHandle> getPhoneAccountsForPackage() {
try {
if (isServiceConnected()) {
@@ -971,6 +979,7 @@ public class TelecomManager {
* @hide
*/
@SystemApi
+ @SuppressLint("Doclava125")
public void clearPhoneAccounts() {
clearAccounts();
}
@@ -980,6 +989,7 @@ public class TelecomManager {
* @hide
*/
@SystemApi
+ @SuppressLint("Doclava125")
public void clearAccounts() {
try {
if (isServiceConnected()) {
@@ -1011,6 +1021,7 @@ public class TelecomManager {
* @hide
*/
@SystemApi
+ @SuppressLint("Doclava125")
public ComponentName getDefaultPhoneApp() {
try {
if (isServiceConnected()) {
@@ -1227,6 +1238,10 @@ public class TelecomManager {
* @hide
*/
@SystemApi
+ @RequiresPermission(anyOf = {
+ android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE,
+ android.Manifest.permission.READ_PHONE_STATE
+ })
public boolean isRinging() {
try {
if (isServiceConnected()) {
@@ -1245,6 +1260,7 @@ public class TelecomManager {
* @hide
*/
@SystemApi
+ @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
public boolean endCall() {
try {
if (isServiceConnected()) {
@@ -1324,6 +1340,10 @@ public class TelecomManager {
* @hide
*/
@SystemApi
+ @RequiresPermission(anyOf = {
+ android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE,
+ android.Manifest.permission.READ_PHONE_STATE
+ })
public boolean isTtySupported() {
try {
if (isServiceConnected()) {
@@ -1602,6 +1622,7 @@ public class TelecomManager {
* @hide
*/
@SystemApi
+ @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
public void enablePhoneAccount(PhoneAccountHandle handle, boolean isEnabled) {
ITelecomService service = getTelecomService();
if (service != null) {
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 9781fb16c2bb..237ed47cace1 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -18,7 +18,10 @@ package android.telephony;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
+import android.annotation.SuppressLint;
import android.annotation.SystemApi;
+import android.annotation.SystemService;
import android.content.Context;
import android.os.PersistableBundle;
import android.os.RemoteException;
@@ -29,14 +32,8 @@ import com.android.internal.telephony.ICarrierConfigLoader;
/**
* Provides access to telephony configuration values that are carrier-specific.
- * <p>
- * Users should obtain an instance of this class by calling
- * {@code mContext.getSystemService(Context.CARRIER_CONFIG_SERVICE);}
- * </p>
- *
- * @see Context#getSystemService
- * @see Context#CARRIER_CONFIG_SERVICE
*/
+@SystemService(Context.CARRIER_CONFIG_SERVICE)
public class CarrierConfigManager {
private final static String TAG = "CarrierConfigManager";
@@ -1797,6 +1794,7 @@ public class CarrierConfigManager {
* @hide
*/
@SystemApi
+ @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
public void updateConfigForPhoneId(int phoneId, String simState) {
try {
ICarrierConfigLoader loader = getICarrierConfigLoader();
@@ -1818,6 +1816,7 @@ public class CarrierConfigManager {
*/
@NonNull
@SystemApi
+ @SuppressLint("Doclava125")
public static PersistableBundle getDefaultConfig() {
return new PersistableBundle(sDefaults);
}
diff --git a/telephony/java/android/telephony/SmsManager.java b/telephony/java/android/telephony/SmsManager.java
index 7d4d90bb75ab..1eac263133e5 100644
--- a/telephony/java/android/telephony/SmsManager.java
+++ b/telephony/java/android/telephony/SmsManager.java
@@ -16,6 +16,7 @@
package android.telephony;
+import android.annotation.RequiresPermission;
import android.annotation.SystemApi;
import android.app.ActivityThread;
import android.app.PendingIntent;
@@ -346,6 +347,7 @@ public final class SmsManager {
* @hide
*/
@SystemApi
+ @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
public void sendTextMessageWithoutPersisting(
String destinationAddress, String scAddress, String text,
PendingIntent sentIntent, PendingIntent deliveryIntent) {
@@ -530,6 +532,7 @@ public final class SmsManager {
* @hide
**/
@SystemApi
+ @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
public void sendMultipartTextMessageWithoutPersisting(
String destinationAddress, String scAddress, List<String> parts,
List<PendingIntent> sentIntents, List<PendingIntent> deliveryIntents) {
diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java
index 77525ff50040..0d1764b7a80a 100644
--- a/telephony/java/android/telephony/SubscriptionManager.java
+++ b/telephony/java/android/telephony/SubscriptionManager.java
@@ -18,6 +18,7 @@ package android.telephony;
import android.annotation.NonNull;
import android.annotation.SdkConstant;
+import android.annotation.SystemService;
import android.annotation.SdkConstant.SdkConstantType;
import android.content.Context;
import android.content.Intent;
@@ -41,13 +42,11 @@ import java.util.List;
/**
* SubscriptionManager is the application interface to SubscriptionController
* and provides information about the current Telephony Subscriptions.
- * * <p>
- * You do not instantiate this class directly; instead, you retrieve
- * a reference to an instance through {@link #from}.
* <p>
* All SDK public methods require android.Manifest.permission.READ_PHONE_STATE unless otherwise
* specified.
*/
+@SystemService(Context.TELEPHONY_SUBSCRIPTION_SERVICE)
public class SubscriptionManager {
private static final String LOG_TAG = "SubscriptionManager";
private static final boolean DBG = false;
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 37c86a768ae7..74327cef6bd3 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -22,8 +22,10 @@ import android.annotation.IntDef;
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
import android.annotation.SdkConstant;
+import android.annotation.SuppressLint;
import android.annotation.SdkConstant.SdkConstantType;
import android.annotation.SystemApi;
+import android.annotation.SystemService;
import android.annotation.WorkerThread;
import android.app.ActivityThread;
import android.app.PendingIntent;
@@ -80,11 +82,6 @@ import java.util.regex.Pattern;
* types of subscriber information. Applications can also register
* a listener to receive notification of telephony state changes.
* <p>
- * You do not instantiate this class directly; instead, you retrieve
- * a reference to an instance through
- * {@link android.content.Context#getSystemService
- * Context.getSystemService(Context.TELEPHONY_SERVICE)}.
- *
* The returned TelephonyManager will use the default subscription for all calls.
* To call an API for a specific subscription, use {@link #createForSubscriptionId(int)}. e.g.
* <code>
@@ -97,6 +94,7 @@ import java.util.regex.Pattern;
* its manifest file. Where permissions apply, they are noted in the
* the methods through which you access the protected information.
*/
+@SystemService(Context.TELEPHONY_SERVICE)
public class TelephonyManager {
private static final String TAG = "TelephonyManager";
@@ -2746,8 +2744,8 @@ public class TelephonyManager {
* be implemented instead.
*/
@SystemApi
+ @SuppressLint("Doclava125")
public void setVisualVoicemailEnabled(PhoneAccountHandle phoneAccountHandle, boolean enabled){
-
}
/**
@@ -2761,6 +2759,7 @@ public class TelephonyManager {
*/
@SystemApi
@RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
+ @SuppressLint("Doclava125")
public boolean isVisualVoicemailEnabled(PhoneAccountHandle phoneAccountHandle){
return false;
}
@@ -2779,6 +2778,7 @@ public class TelephonyManager {
* @hide
*/
@SystemApi
+ @SuppressLint("Doclava125")
@Nullable
public Bundle getVisualVoicemailSettings(){
try {
@@ -4956,12 +4956,14 @@ public class TelephonyManager {
/** @hide */
@SystemApi
+ @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
public String getCdmaMdn() {
return getCdmaMdn(getSubId());
}
/** @hide */
@SystemApi
+ @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
public String getCdmaMdn(int subId) {
try {
ITelephony telephony = getITelephony();
@@ -4977,12 +4979,14 @@ public class TelephonyManager {
/** @hide */
@SystemApi
+ @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
public String getCdmaMin() {
return getCdmaMin(getSubId());
}
/** @hide */
@SystemApi
+ @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
public String getCdmaMin(int subId) {
try {
ITelephony telephony = getITelephony();
@@ -4998,6 +5002,7 @@ public class TelephonyManager {
/** @hide */
@SystemApi
+ @SuppressLint("Doclava125")
public int checkCarrierPrivilegesForPackage(String pkgName) {
try {
ITelephony telephony = getITelephony();
@@ -5013,6 +5018,7 @@ public class TelephonyManager {
/** @hide */
@SystemApi
+ @SuppressLint("Doclava125")
public int checkCarrierPrivilegesForPackageAnyPhone(String pkgName) {
try {
ITelephony telephony = getITelephony();
@@ -5064,6 +5070,7 @@ public class TelephonyManager {
/** @hide */
@SystemApi
+ @SuppressLint("Doclava125")
public void dial(String number) {
try {
ITelephony telephony = getITelephony();
@@ -5076,6 +5083,7 @@ public class TelephonyManager {
/** @hide */
@SystemApi
+ @RequiresPermission(android.Manifest.permission.CALL_PHONE)
public void call(String callingPackage, String number) {
try {
ITelephony telephony = getITelephony();
@@ -5088,6 +5096,7 @@ public class TelephonyManager {
/** @hide */
@SystemApi
+ @RequiresPermission(android.Manifest.permission.CALL_PHONE)
public boolean endCall() {
try {
ITelephony telephony = getITelephony();
@@ -5101,6 +5110,7 @@ public class TelephonyManager {
/** @hide */
@SystemApi
+ @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
public void answerRingingCall() {
try {
ITelephony telephony = getITelephony();
@@ -5113,6 +5123,7 @@ public class TelephonyManager {
/** @hide */
@SystemApi
+ @SuppressLint("Doclava125")
public void silenceRinger() {
try {
getTelecomService().silenceRinger(getOpPackageName());
@@ -5123,6 +5134,10 @@ public class TelephonyManager {
/** @hide */
@SystemApi
+ @RequiresPermission(anyOf = {
+ android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE,
+ android.Manifest.permission.READ_PHONE_STATE
+ })
public boolean isOffhook() {
try {
ITelephony telephony = getITelephony();
@@ -5136,6 +5151,10 @@ public class TelephonyManager {
/** @hide */
@SystemApi
+ @RequiresPermission(anyOf = {
+ android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE,
+ android.Manifest.permission.READ_PHONE_STATE
+ })
public boolean isRinging() {
try {
ITelephony telephony = getITelephony();
@@ -5149,6 +5168,10 @@ public class TelephonyManager {
/** @hide */
@SystemApi
+ @RequiresPermission(anyOf = {
+ android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE,
+ android.Manifest.permission.READ_PHONE_STATE
+ })
public boolean isIdle() {
try {
ITelephony telephony = getITelephony();
@@ -5162,6 +5185,10 @@ public class TelephonyManager {
/** @hide */
@SystemApi
+ @RequiresPermission(anyOf = {
+ android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE,
+ android.Manifest.permission.READ_PHONE_STATE
+ })
public boolean isRadioOn() {
try {
ITelephony telephony = getITelephony();
@@ -5175,6 +5202,7 @@ public class TelephonyManager {
/** @hide */
@SystemApi
+ @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
public boolean supplyPin(String pin) {
try {
ITelephony telephony = getITelephony();
@@ -5188,6 +5216,7 @@ public class TelephonyManager {
/** @hide */
@SystemApi
+ @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
public boolean supplyPuk(String puk, String pin) {
try {
ITelephony telephony = getITelephony();
@@ -5201,6 +5230,7 @@ public class TelephonyManager {
/** @hide */
@SystemApi
+ @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
public int[] supplyPinReportResult(String pin) {
try {
ITelephony telephony = getITelephony();
@@ -5214,6 +5244,7 @@ public class TelephonyManager {
/** @hide */
@SystemApi
+ @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
public int[] supplyPukReportResult(String puk, String pin) {
try {
ITelephony telephony = getITelephony();
@@ -5333,6 +5364,7 @@ public class TelephonyManager {
/** @hide */
@SystemApi
+ @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
public boolean handlePinMmi(String dialString) {
try {
ITelephony telephony = getITelephony();
@@ -5346,6 +5378,7 @@ public class TelephonyManager {
/** @hide */
@SystemApi
+ @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
public boolean handlePinMmiForSubscriber(int subId, String dialString) {
try {
ITelephony telephony = getITelephony();
@@ -5359,6 +5392,7 @@ public class TelephonyManager {
/** @hide */
@SystemApi
+ @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
public void toggleRadioOnOff() {
try {
ITelephony telephony = getITelephony();
@@ -5371,6 +5405,7 @@ public class TelephonyManager {
/** @hide */
@SystemApi
+ @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
public boolean setRadio(boolean turnOn) {
try {
ITelephony telephony = getITelephony();
@@ -5384,6 +5419,7 @@ public class TelephonyManager {
/** @hide */
@SystemApi
+ @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
public boolean setRadioPower(boolean turnOn) {
try {
ITelephony telephony = getITelephony();
@@ -5397,6 +5433,7 @@ public class TelephonyManager {
/** @hide */
@SystemApi
+ @SuppressLint("Doclava125")
public void updateServiceLocation() {
try {
ITelephony telephony = getITelephony();
@@ -5409,6 +5446,7 @@ public class TelephonyManager {
/** @hide */
@SystemApi
+ @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
public boolean enableDataConnectivity() {
try {
ITelephony telephony = getITelephony();
@@ -5422,6 +5460,7 @@ public class TelephonyManager {
/** @hide */
@SystemApi
+ @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
public boolean disableDataConnectivity() {
try {
ITelephony telephony = getITelephony();
@@ -5473,12 +5512,14 @@ public class TelephonyManager {
*
* @see #hasCarrierPrivileges
*/
+ @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
public void setDataEnabled(boolean enable) {
setDataEnabled(getSubId(SubscriptionManager.getDefaultDataSubscriptionId()), enable);
}
/** @hide */
@SystemApi
+ @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
public void setDataEnabled(int subId, boolean enable) {
try {
Log.d(TAG, "setDataEnabled: enabled=" + enable);
@@ -5568,6 +5609,7 @@ public class TelephonyManager {
/** @hide */
@SystemApi
+ @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
public void enableVideoCalling(boolean enable) {
try {
ITelephony telephony = getITelephony();
@@ -5580,6 +5622,10 @@ public class TelephonyManager {
/** @hide */
@SystemApi
+ @RequiresPermission(anyOf = {
+ android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE,
+ android.Manifest.permission.READ_PHONE_STATE
+ })
public boolean isVideoCallingEnabled() {
try {
ITelephony telephony = getITelephony();
@@ -6488,6 +6534,7 @@ public class TelephonyManager {
* @hide
*/
@SystemApi
+ @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
public List<TelephonyHistogram> getTelephonyHistograms() {
try {
ITelephony service = getITelephony();
@@ -6515,6 +6562,7 @@ public class TelephonyManager {
* @hide
*/
@SystemApi
+ @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
public int setAllowedCarriers(int slotIndex, List<CarrierIdentifier> carriers) {
try {
ITelephony service = getITelephony();
@@ -6533,9 +6581,6 @@ public class TelephonyManager {
* Get the allowed carrier list for slotIndex.
* Require system privileges. In the future we may add this to carrier APIs.
*
- * <p>Requires Permission:
- * {@link android.Manifest.permission#READ_PRIVILEGED_PHONE_STATE}
- *
* <p>This method returns valid data on devices with {@link
* android.content.pm.PackageManager#FEATURE_TELEPHONY_CARRIERLOCK} enabled.
*
@@ -6544,6 +6589,7 @@ public class TelephonyManager {
* @hide
*/
@SystemApi
+ @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
public List<CarrierIdentifier> getAllowedCarriers(int slotIndex) {
try {
ITelephony service = getITelephony();
diff --git a/tests/net/java/com/android/server/connectivity/tethering/OffloadControllerTest.java b/tests/net/java/com/android/server/connectivity/tethering/OffloadControllerTest.java
index fb7971e1e104..c535c455e7a8 100644
--- a/tests/net/java/com/android/server/connectivity/tethering/OffloadControllerTest.java
+++ b/tests/net/java/com/android/server/connectivity/tethering/OffloadControllerTest.java
@@ -17,15 +17,22 @@
package com.android.server.connectivity.tethering;
import static android.provider.Settings.Global.TETHER_OFFLOAD_DISABLED;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyObject;
+import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.inOrder;
import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.when;
import android.content.Context;
+import android.net.LinkAddress;
+import android.net.LinkProperties;
+import android.net.RouteInfo;
import android.net.util.SharedLog;
import android.provider.Settings;
import android.provider.Settings.SettingNotFoundException;
@@ -35,9 +42,13 @@ import android.support.test.runner.AndroidJUnit4;
import android.test.mock.MockContentResolver;
import com.android.internal.util.test.FakeSettingsProvider;
+import java.net.InetAddress;
+import java.util.ArrayList;
+
import org.junit.Before;
import org.junit.runner.RunWith;
import org.junit.Test;
+import org.mockito.ArgumentCaptor;
import org.mockito.InOrder;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
@@ -49,6 +60,7 @@ public class OffloadControllerTest {
@Mock private OffloadHardwareInterface mHardware;
@Mock private Context mContext;
+ final ArgumentCaptor<ArrayList> mStringArrayCaptor = ArgumentCaptor.forClass(ArrayList.class);
private MockContentResolver mContentResolver;
@Before public void setUp() throws Exception {
@@ -114,4 +126,87 @@ public class OffloadControllerTest {
inOrder.verify(mHardware, never()).initOffloadControl(anyObject());
inOrder.verifyNoMoreInteractions();
}
+
+ @Test
+ public void testSetUpstreamLinkPropertiesWorking() throws Exception {
+ setupFunctioningHardwareInterface();
+ final OffloadController offload =
+ new OffloadController(null, mHardware, mContentResolver, new SharedLog("test"));
+ offload.start();
+
+ final InOrder inOrder = inOrder(mHardware);
+ inOrder.verify(mHardware, times(1)).initOffloadConfig();
+ inOrder.verify(mHardware, times(1)).initOffloadControl(
+ any(OffloadHardwareInterface.ControlCallback.class));
+ inOrder.verifyNoMoreInteractions();
+
+ offload.setUpstreamLinkProperties(null);
+ inOrder.verify(mHardware, times(1)).setUpstreamParameters(
+ eq(null), eq(null), eq(null), eq(null));
+ inOrder.verifyNoMoreInteractions();
+ reset(mHardware);
+
+ final LinkProperties lp = new LinkProperties();
+
+ final String testIfName = "rmnet_data17";
+ lp.setInterfaceName(testIfName);
+ offload.setUpstreamLinkProperties(lp);
+ inOrder.verify(mHardware, times(1)).setUpstreamParameters(
+ eq(testIfName), eq(null), eq(null), mStringArrayCaptor.capture());
+ assertTrue(mStringArrayCaptor.getValue().isEmpty());
+ inOrder.verifyNoMoreInteractions();
+
+ final String ipv4Addr = "192.0.2.5";
+ final String linkAddr = ipv4Addr + "/24";
+ lp.addLinkAddress(new LinkAddress(linkAddr));
+ offload.setUpstreamLinkProperties(lp);
+ inOrder.verify(mHardware, times(1)).setUpstreamParameters(
+ eq(testIfName), eq(ipv4Addr), eq(null), mStringArrayCaptor.capture());
+ assertTrue(mStringArrayCaptor.getValue().isEmpty());
+ inOrder.verifyNoMoreInteractions();
+
+ final String ipv4Gateway = "192.0.2.1";
+ lp.addRoute(new RouteInfo(InetAddress.getByName(ipv4Gateway)));
+ offload.setUpstreamLinkProperties(lp);
+ inOrder.verify(mHardware, times(1)).setUpstreamParameters(
+ eq(testIfName), eq(ipv4Addr), eq(ipv4Gateway), mStringArrayCaptor.capture());
+ assertTrue(mStringArrayCaptor.getValue().isEmpty());
+ inOrder.verifyNoMoreInteractions();
+
+ final String ipv6Gw1 = "fe80::cafe";
+ lp.addRoute(new RouteInfo(InetAddress.getByName(ipv6Gw1)));
+ offload.setUpstreamLinkProperties(lp);
+ inOrder.verify(mHardware, times(1)).setUpstreamParameters(
+ eq(testIfName), eq(ipv4Addr), eq(ipv4Gateway), mStringArrayCaptor.capture());
+ ArrayList<String> v6gws = mStringArrayCaptor.getValue();
+ assertEquals(1, v6gws.size());
+ assertTrue(v6gws.contains(ipv6Gw1));
+ inOrder.verifyNoMoreInteractions();
+
+ final String ipv6Gw2 = "fe80::d00d";
+ lp.addRoute(new RouteInfo(InetAddress.getByName(ipv6Gw2)));
+ offload.setUpstreamLinkProperties(lp);
+ inOrder.verify(mHardware, times(1)).setUpstreamParameters(
+ eq(testIfName), eq(ipv4Addr), eq(ipv4Gateway), mStringArrayCaptor.capture());
+ v6gws = mStringArrayCaptor.getValue();
+ assertEquals(2, v6gws.size());
+ assertTrue(v6gws.contains(ipv6Gw1));
+ assertTrue(v6gws.contains(ipv6Gw2));
+ inOrder.verifyNoMoreInteractions();
+
+ final LinkProperties stacked = new LinkProperties();
+ stacked.setInterfaceName("stacked");
+ stacked.addLinkAddress(new LinkAddress("192.0.2.129/25"));
+ stacked.addRoute(new RouteInfo(InetAddress.getByName("192.0.2.254")));
+ stacked.addRoute(new RouteInfo(InetAddress.getByName("fe80::bad:f00")));
+ assertTrue(lp.addStackedLink(stacked));
+ offload.setUpstreamLinkProperties(lp);
+ inOrder.verify(mHardware, times(1)).setUpstreamParameters(
+ eq(testIfName), eq(ipv4Addr), eq(ipv4Gateway), mStringArrayCaptor.capture());
+ v6gws = mStringArrayCaptor.getValue();
+ assertEquals(2, v6gws.size());
+ assertTrue(v6gws.contains(ipv6Gw1));
+ assertTrue(v6gws.contains(ipv6Gw2));
+ inOrder.verifyNoMoreInteractions();
+ }
}
diff --git a/tools/aapt2/ResourceParser_test.cpp b/tools/aapt2/ResourceParser_test.cpp
index 5352ca8679b3..c6382b177f42 100644
--- a/tools/aapt2/ResourceParser_test.cpp
+++ b/tools/aapt2/ResourceParser_test.cpp
@@ -843,4 +843,9 @@ TEST_F(ResourceParserTest, ParseElementWithNoValue) {
EXPECT_THAT(*str->value, Eq(""));
}
+TEST_F(ResourceParserTest, ParsePlatformIndependentNewline) {
+ std::string input = R"(<string name="foo">%1$s %n %2$s</string>)";
+ ASSERT_TRUE(TestParse(input));
+}
+
} // namespace aapt
diff --git a/tools/aapt2/integration-tests/AppOne/AndroidManifest.xml b/tools/aapt2/integration-tests/AppOne/AndroidManifest.xml
index 1a4067fb0b22..a5f202dd22fc 100644
--- a/tools/aapt2/integration-tests/AppOne/AndroidManifest.xml
+++ b/tools/aapt2/integration-tests/AppOne/AndroidManifest.xml
@@ -19,4 +19,11 @@
<uses-sdk android:minSdkVersion="21" />
<uses-permission-sdk-23 android:name="android.permission.TEST" android:maxSdkVersion="22" />
+
+ <application>
+ <activity android:name=".MyActivity">
+ <layout android:defaultHeight="500dp"
+ android:defaultWidth="600dp" />
+ </activity>
+ </application>
</manifest>
diff --git a/tools/aapt2/link/ManifestFixer.cpp b/tools/aapt2/link/ManifestFixer.cpp
index 53c66a628568..99fd95be2571 100644
--- a/tools/aapt2/link/ManifestFixer.cpp
+++ b/tools/aapt2/link/ManifestFixer.cpp
@@ -326,7 +326,10 @@ bool ManifestFixer::BuildRules(xml::XmlActionExecutor* executor,
uses_static_library_action.Action(RequiredAndroidAttribute("certDigest"));
application_action["meta-data"] = meta_data_action;
+
application_action["activity"] = component_action;
+ application_action["activity"]["layout"];
+
application_action["activity-alias"] = component_action;
application_action["service"] = component_action;
application_action["receiver"] = component_action;
diff --git a/tools/aapt2/util/Util.cpp b/tools/aapt2/util/Util.cpp
index cf2232254ec4..28e952e25a67 100644
--- a/tools/aapt2/util/Util.cpp
+++ b/tools/aapt2/util/Util.cpp
@@ -203,7 +203,7 @@ bool VerifyJavaStringFormat(const StringPiece& str) {
if (*c == '%' && c + 1 < end) {
c++;
- if (*c == '%') {
+ if (*c == '%' || *c == 'n') {
c++;
continue;
}
diff --git a/wifi/java/android/net/wifi/RttManager.java b/wifi/java/android/net/wifi/RttManager.java
index b133a44d0117..a4b3bf2a3019 100644
--- a/wifi/java/android/net/wifi/RttManager.java
+++ b/wifi/java/android/net/wifi/RttManager.java
@@ -1,7 +1,10 @@
package android.net.wifi;
import android.annotation.NonNull;
+import android.annotation.RequiresPermission;
+import android.annotation.SuppressLint;
import android.annotation.SystemApi;
+import android.annotation.SystemService;
import android.content.Context;
import android.os.Bundle;
import android.os.Handler;
@@ -20,6 +23,7 @@ import com.android.internal.util.Protocol;
/** @hide */
@SystemApi
+@SystemService(Context.WIFI_RTT_SERVICE)
public class RttManager {
private static final boolean DBG = false;
@@ -167,6 +171,7 @@ public class RttManager {
/** @deprecated Use the new {@link android.net.wifi.RttManager#getRttCapabilities()} API.*/
@Deprecated
+ @SuppressLint("Doclava125")
public Capabilities getCapabilities() {
return new Capabilities();
}
@@ -990,7 +995,7 @@ public class RttManager {
* @exception throw IllegalArgumentException when params are illegal
* throw IllegalStateException when RttCapabilities do not exist
*/
-
+ @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE)
public void startRanging(RttParams[] params, RttListener listener) {
int index = 0;
for(RttParams rttParam : params) {
@@ -1006,6 +1011,7 @@ public class RttManager {
0, putListener(listener), parcelableParams);
}
+ @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE)
public void stopRanging(RttListener listener) {
validateChannel();
mAsyncChannel.sendMessage(CMD_OP_STOP_RANGING, 0, removeListener(listener));
@@ -1039,6 +1045,7 @@ public class RttManager {
* @param callback Callback for responder enabling/disabling result.
* @throws IllegalArgumentException If {@code callback} is null.
*/
+ @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE)
public void enableResponder(ResponderCallback callback) {
if (callback == null) {
throw new IllegalArgumentException("callback cannot be null");
@@ -1058,6 +1065,7 @@ public class RttManager {
* @param callback The same callback used for enabling responder.
* @throws IllegalArgumentException If {@code callback} is null.
*/
+ @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE)
public void disableResponder(ResponderCallback callback) {
if (callback == null) {
throw new IllegalArgumentException("callback cannot be null");
diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java
index f7333e281982..91fc2f7ce773 100644
--- a/wifi/java/android/net/wifi/WifiConfiguration.java
+++ b/wifi/java/android/net/wifi/WifiConfiguration.java
@@ -67,6 +67,8 @@ public class WifiConfiguration implements Parcelable {
public static final String updateIdentiferVarName = "update_identifier";
/** {@hide} */
public static final int INVALID_NETWORK_ID = -1;
+ /** {@hide} */
+ public static final int LOCAL_ONLY_NETWORK_ID = -2;
/** {@hide} */
private String mPasspointManagementObjectTree;
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index 58df4ee227f2..c89a9a458393 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -17,9 +17,12 @@
package android.net.wifi;
import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
import android.annotation.SdkConstant;
+import android.annotation.SuppressLint;
import android.annotation.SdkConstant.SdkConstantType;
import android.annotation.SystemApi;
+import android.annotation.SystemService;
import android.content.Context;
import android.content.pm.ParceledListSlice;
import android.net.ConnectivityManager;
@@ -56,27 +59,30 @@ import java.util.concurrent.CountDownLatch;
/**
* This class provides the primary API for managing all aspects of Wi-Fi
- * connectivity. Get an instance of this class by calling
- * {@link android.content.Context#getSystemService(String) Context.getSystemService(Context.WIFI_SERVICE)}.
- * On releases before NYC, it should only be obtained from an application context, and not from
- * any other derived context to avoid memory leaks within the calling process.
-
+ * connectivity.
+ * <p>
+ * On releases before {@link android.os.Build.VERSION_CODES#N}, this object
+ * should only be obtained from an {@linkplain Context#getApplicationContext()
+ * application context}, and not from any other derived context to avoid memory
+ * leaks within the calling process.
+ * <p>
* It deals with several categories of items:
* <ul>
- * <li>The list of configured networks. The list can be viewed and updated,
- * and attributes of individual entries can be modified.</li>
+ * <li>The list of configured networks. The list can be viewed and updated, and
+ * attributes of individual entries can be modified.</li>
* <li>The currently active Wi-Fi network, if any. Connectivity can be
- * established or torn down, and dynamic information about the state of
- * the network can be queried.</li>
- * <li>Results of access point scans, containing enough information to
- * make decisions about what access point to connect to.</li>
- * <li>It defines the names of various Intent actions that are broadcast
- * upon any sort of change in Wi-Fi state.
+ * established or torn down, and dynamic information about the state of the
+ * network can be queried.</li>
+ * <li>Results of access point scans, containing enough information to make
+ * decisions about what access point to connect to.</li>
+ * <li>It defines the names of various Intent actions that are broadcast upon
+ * any sort of change in Wi-Fi state.
* </ul>
- * This is the API to use when performing Wi-Fi specific operations. To
- * perform operations that pertain to network connectivity at an abstract
- * level, use {@link android.net.ConnectivityManager}.
+ * This is the API to use when performing Wi-Fi specific operations. To perform
+ * operations that pertain to network connectivity at an abstract level, use
+ * {@link android.net.ConnectivityManager}.
*/
+@SystemService(Context.WIFI_SERVICE)
public class WifiManager {
private static final String TAG = "WifiManager";
@@ -966,6 +972,7 @@ public class WifiManager {
/** @hide */
@SystemApi
+ @RequiresPermission(android.Manifest.permission.READ_WIFI_CREDENTIAL)
public List<WifiConfiguration> getPrivilegedConfiguredNetworks() {
try {
ParceledListSlice<WifiConfiguration> parceledList =
@@ -981,6 +988,7 @@ public class WifiManager {
/** @hide */
@SystemApi
+ @RequiresPermission(android.Manifest.permission.READ_WIFI_CREDENTIAL)
public WifiConnectionStatistics getConnectionStatistics() {
try {
return mService.getConnectionStatistics();
@@ -1522,6 +1530,7 @@ public class WifiManager {
/** @hide */
@SystemApi
+ @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS)
public boolean startScan(WorkSource workSource) {
try {
String packageName = mContext.getOpPackageName();
@@ -1542,6 +1551,7 @@ public class WifiManager {
*/
@Deprecated
@SystemApi
+ @SuppressLint("Doclava125")
public boolean startLocationRestrictedScan(WorkSource workSource) {
return false;
}
@@ -1556,6 +1566,7 @@ public class WifiManager {
*/
@Deprecated
@SystemApi
+ @SuppressLint("Doclava125")
public boolean isBatchedScanSupported() {
return false;
}
@@ -1569,6 +1580,7 @@ public class WifiManager {
*/
@Deprecated
@SystemApi
+ @SuppressLint("Doclava125")
public List<BatchedScanResult> getBatchedScanResults() {
return null;
}
@@ -1808,6 +1820,7 @@ public class WifiManager {
* @hide
*/
@SystemApi
+ @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED)
public boolean setWifiApEnabled(WifiConfiguration wifiConfig, boolean enabled) {
String packageName = mContext.getOpPackageName();
@@ -2053,6 +2066,7 @@ public class WifiManager {
* @hide
*/
@SystemApi
+ @RequiresPermission(android.Manifest.permission.ACCESS_WIFI_STATE)
public int getWifiApState() {
try {
return mService.getWifiApEnabledState();
@@ -2069,6 +2083,7 @@ public class WifiManager {
* @hide
*/
@SystemApi
+ @RequiresPermission(android.Manifest.permission.ACCESS_WIFI_STATE)
public boolean isWifiApEnabled() {
return getWifiApState() == WIFI_AP_STATE_ENABLED;
}
@@ -2080,6 +2095,7 @@ public class WifiManager {
* @hide
*/
@SystemApi
+ @RequiresPermission(android.Manifest.permission.ACCESS_WIFI_STATE)
public WifiConfiguration getWifiApConfiguration() {
try {
return mService.getWifiApConfiguration();
@@ -2095,6 +2111,7 @@ public class WifiManager {
* @hide
*/
@SystemApi
+ @RequiresPermission(android.Manifest.permission.CHANGE_WIFI_STATE)
public boolean setWifiApConfiguration(WifiConfiguration wifiConfig) {
try {
mService.setWifiApConfiguration(wifiConfig);
diff --git a/wifi/java/android/net/wifi/WifiScanner.java b/wifi/java/android/net/wifi/WifiScanner.java
index c02ceef95b73..f47d5caf182b 100644
--- a/wifi/java/android/net/wifi/WifiScanner.java
+++ b/wifi/java/android/net/wifi/WifiScanner.java
@@ -16,7 +16,10 @@
package android.net.wifi;
+import android.annotation.RequiresPermission;
+import android.annotation.SuppressLint;
import android.annotation.SystemApi;
+import android.annotation.SystemService;
import android.content.Context;
import android.os.Bundle;
import android.os.Handler;
@@ -40,12 +43,10 @@ import java.util.List;
/**
* This class provides a way to scan the Wifi universe around the device
- * Get an instance of this class by calling
- * {@link android.content.Context#getSystemService(String) Context.getSystemService(Context
- * .WIFI_SCANNING_SERVICE)}.
* @hide
*/
@SystemApi
+@SystemService(Context.WIFI_SCANNING_SERVICE)
public class WifiScanner {
/** no band specified; use channel list instead */
@@ -732,6 +733,7 @@ public class WifiScanner {
* key for this scan, and must also be specified to cancel the scan. Multiple
* scans should also not share this object.
*/
+ @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE)
public void startBackgroundScan(ScanSettings settings, ScanListener listener) {
startBackgroundScan(settings, listener, null);
}
@@ -744,6 +746,7 @@ public class WifiScanner {
* key for this scan, and must also be specified to cancel the scan. Multiple
* scans should also not share this object.
*/
+ @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE)
public void startBackgroundScan(ScanSettings settings, ScanListener listener,
WorkSource workSource) {
Preconditions.checkNotNull(listener, "listener cannot be null");
@@ -761,6 +764,7 @@ public class WifiScanner {
* @param listener specifies which scan to cancel; must be same object as passed in {@link
* #startBackgroundScan}
*/
+ @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE)
public void stopBackgroundScan(ScanListener listener) {
Preconditions.checkNotNull(listener, "listener cannot be null");
int key = removeListener(listener);
@@ -772,6 +776,7 @@ public class WifiScanner {
* reports currently available scan results on appropriate listeners
* @return true if all scan results were reported correctly
*/
+ @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE)
public boolean getScanResults() {
validateChannel();
Message reply = mAsyncChannel.sendMessageSynchronously(CMD_GET_SCAN_RESULTS, 0);
@@ -786,6 +791,7 @@ public class WifiScanner {
* key for this scan, and must also be specified to cancel the scan. Multiple
* scans should also not share this object.
*/
+ @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE)
public void startScan(ScanSettings settings, ScanListener listener) {
startScan(settings, listener, null);
}
@@ -799,6 +805,7 @@ public class WifiScanner {
* key for this scan, and must also be specified to cancel the scan. Multiple
* scans should also not share this object.
*/
+ @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE)
public void startScan(ScanSettings settings, ScanListener listener, WorkSource workSource) {
Preconditions.checkNotNull(listener, "listener cannot be null");
int key = addListener(listener);
@@ -815,6 +822,7 @@ public class WifiScanner {
* hasn't been called on the listener, ignored otherwise
* @param listener
*/
+ @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE)
public void stopScan(ScanListener listener) {
Preconditions.checkNotNull(listener, "listener cannot be null");
int key = removeListener(listener);
@@ -962,6 +970,7 @@ public class WifiScanner {
* @param bssidInfos access points to watch
*/
@Deprecated
+ @SuppressLint("Doclava125")
public void configureWifiChange(
int rssiSampleSize, /* sample size for RSSI averaging */
int lostApSampleSize, /* samples to confirm AP's loss */
@@ -995,6 +1004,7 @@ public class WifiScanner {
* provided on {@link #stopTrackingWifiChange}
*/
@Deprecated
+ @SuppressLint("Doclava125")
public void startTrackingWifiChange(WifiChangeListener listener) {
throw new UnsupportedOperationException();
}
@@ -1005,6 +1015,7 @@ public class WifiScanner {
* #stopTrackingWifiChange}
*/
@Deprecated
+ @SuppressLint("Doclava125")
public void stopTrackingWifiChange(WifiChangeListener listener) {
throw new UnsupportedOperationException();
}
@@ -1012,6 +1023,7 @@ public class WifiScanner {
/** @hide */
@SystemApi
@Deprecated
+ @SuppressLint("Doclava125")
public void configureWifiChange(WifiChangeSettings settings) {
throw new UnsupportedOperationException();
}
@@ -1067,6 +1079,7 @@ public class WifiScanner {
* also be provided on {@link #stopTrackingBssids}
*/
@Deprecated
+ @SuppressLint("Doclava125")
public void startTrackingBssids(BssidInfo[] bssidInfos,
int apLostThreshold, BssidListener listener) {
throw new UnsupportedOperationException();
@@ -1077,6 +1090,7 @@ public class WifiScanner {
* @param listener same object provided in {@link #startTrackingBssids}
*/
@Deprecated
+ @SuppressLint("Doclava125")
public void stopTrackingBssids(BssidListener listener) {
throw new UnsupportedOperationException();
}
diff --git a/wifi/java/android/net/wifi/aware/WifiAwareManager.java b/wifi/java/android/net/wifi/aware/WifiAwareManager.java
index 87f199292dd8..df0d9d23fe14 100644
--- a/wifi/java/android/net/wifi/aware/WifiAwareManager.java
+++ b/wifi/java/android/net/wifi/aware/WifiAwareManager.java
@@ -20,6 +20,7 @@ import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SdkConstant;
+import android.annotation.SystemService;
import android.annotation.SdkConstant.SdkConstantType;
import android.content.Context;
import android.net.ConnectivityManager;
@@ -49,9 +50,7 @@ import java.util.List;
/**
* This class provides the primary API for managing Wi-Fi Aware operations:
- * discovery and peer-to-peer data connections. Get an instance of this class by calling
- * {@link android.content.Context#getSystemService(String)
- * Context.getSystemService(Context.WIFI_AWARE_SERVICE)}.
+ * discovery and peer-to-peer data connections.
* <p>
* The class provides access to:
* <ul>
@@ -121,6 +120,7 @@ import java.util.List;
* {@link DiscoverySession#createNetworkSpecifierPassphrase(PeerHandle, String)}.
* </ul>
*/
+@SystemService(Context.WIFI_AWARE_SERVICE)
public class WifiAwareManager {
private static final String TAG = "WifiAwareManager";
private static final boolean DBG = false;
diff --git a/wifi/java/android/net/wifi/p2p/IWifiP2pManager.aidl b/wifi/java/android/net/wifi/p2p/IWifiP2pManager.aidl
index 8b1cfaee8119..bfdd45d9f9b0 100644
--- a/wifi/java/android/net/wifi/p2p/IWifiP2pManager.aidl
+++ b/wifi/java/android/net/wifi/p2p/IWifiP2pManager.aidl
@@ -25,8 +25,9 @@ import android.os.Messenger;
*/
interface IWifiP2pManager
{
- Messenger getMessenger();
+ Messenger getMessenger(in IBinder binder);
Messenger getP2pStateMachineMessenger();
+ oneway void close(in IBinder binder);
void setMiracastMode(int mode);
void checkConfigureWifiDisplayPermission();
}
diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pManager.java b/wifi/java/android/net/wifi/p2p/WifiP2pManager.java
index c93ac7b5f8f1..7f085f71e99c 100644
--- a/wifi/java/android/net/wifi/p2p/WifiP2pManager.java
+++ b/wifi/java/android/net/wifi/p2p/WifiP2pManager.java
@@ -17,6 +17,7 @@
package android.net.wifi.p2p;
import android.annotation.SdkConstant;
+import android.annotation.SystemService;
import android.annotation.SdkConstant.SdkConstantType;
import android.content.Context;
import android.net.wifi.WpsInfo;
@@ -27,6 +28,7 @@ import android.net.wifi.p2p.nsd.WifiP2pServiceRequest;
import android.net.wifi.p2p.nsd.WifiP2pServiceResponse;
import android.net.wifi.p2p.nsd.WifiP2pUpnpServiceInfo;
import android.net.wifi.p2p.nsd.WifiP2pUpnpServiceResponse;
+import android.os.Binder;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
@@ -119,9 +121,6 @@ import java.util.Map;
* {@link android.Manifest.permission#CHANGE_WIFI_STATE} to perform any further peer-to-peer
* operations.
*
- * Get an instance of this class by calling {@link android.content.Context#getSystemService(String)
- * Context.getSystemService(Context.WIFI_P2P_SERVICE)}.
- *
* {@see WifiP2pConfig}
* {@see WifiP2pInfo}
* {@see WifiP2pGroup}
@@ -129,6 +128,7 @@ import java.util.Map;
* {@see WifiP2pDeviceList}
* {@see android.net.wifi.WpsInfo}
*/
+@SystemService(Context.WIFI_P2P_SERVICE)
public class WifiP2pManager {
private static final String TAG = "WifiP2pManager";
/**
@@ -291,6 +291,7 @@ public class WifiP2pManager {
"android.net.wifi.p2p.CALLING_PACKAGE";
IWifiP2pManager mService;
+ private final Map<Channel, Binder> mBinders = new HashMap<>();
private static final int BASE = Protocol.BASE_WIFI_P2P_MANAGER;
@@ -890,7 +891,10 @@ public class WifiP2pManager {
* @return Channel instance that is necessary for performing any further p2p operations
*/
public Channel initialize(Context srcContext, Looper srcLooper, ChannelListener listener) {
- return initalizeChannel(srcContext, srcLooper, listener, getMessenger());
+ Binder binder = new Binder();
+ Channel channel = initalizeChannel(srcContext, srcLooper, listener, getMessenger(binder));
+ mBinders.put(channel, binder);
+ return channel;
}
/**
@@ -1386,12 +1390,14 @@ public class WifiP2pManager {
* Get a reference to WifiP2pService handler. This is used to establish
* an AsyncChannel communication with WifiService
*
+ * @param binder A binder for the service to associate with this client.
+ *
* @return Messenger pointing to the WifiP2pService handler
* @hide
*/
- public Messenger getMessenger() {
+ public Messenger getMessenger(Binder binder) {
try {
- return mService.getMessenger();
+ return mService.getMessenger(binder);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -1413,6 +1419,23 @@ public class WifiP2pManager {
}
/**
+ * Close the current P2P connection and clean-up any configuration requested by the
+ * current app. Takes same action as taken when the app dies.
+ *
+ * @param c is the channel created at {@link #initialize}
+ *
+ * @hide
+ */
+ public void close(Channel c) {
+ try {
+ mService.close(mBinders.get(c));
+ mBinders.remove(c);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* Get a handover request message for use in WFA NFC Handover transfer.
* @hide
*/