summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Android.mk4
-rw-r--r--api/current.txt3
-rw-r--r--api/system-current.txt3
-rw-r--r--api/test-current.txt3
-rw-r--r--core/java/android/accounts/Account.java47
-rw-r--r--core/java/android/accounts/AccountManager.java36
-rw-r--r--core/java/android/accounts/AccountManagerInternal.java48
-rw-r--r--core/java/android/accounts/GrantCredentialsPermissionActivity.java2
-rw-r--r--core/java/android/accounts/IAccountAccessTracker.aidl26
-rw-r--r--core/java/android/app/ActivityThread.java19
-rw-r--r--core/java/android/app/ApplicationThreadNative.java7
-rw-r--r--core/java/android/app/IApplicationThread.java4
-rw-r--r--core/java/android/bluetooth/BluetoothAvrcpController.java98
-rw-r--r--core/java/android/bluetooth/BluetoothDevice.java4
-rw-r--r--core/java/android/bluetooth/IBluetoothAvrcpController.aidl3
-rw-r--r--core/java/android/content/ContentResolver.java1
-rw-r--r--core/java/android/content/Context.java6
-rw-r--r--core/java/android/content/pm/PackageManagerInternal.java8
-rw-r--r--core/java/android/net/ConnectivityManager.java21
-rw-r--r--core/java/android/net/IConnectivityManager.aidl1
-rw-r--r--core/java/android/net/InterfaceConfiguration.java8
-rw-r--r--core/java/android/net/metrics/DnsEvent.java2
-rw-r--r--core/java/android/os/Build.java34
-rw-r--r--core/java/android/os/HwParcel.java16
-rw-r--r--core/java/android/os/IDeviceIdentifiersPolicyService.aidl24
-rw-r--r--core/java/android/os/PowerManager.java29
-rwxr-xr-xcore/java/android/provider/Settings.java22
-rw-r--r--core/java/android/service/dreams/DreamService.java160
-rw-r--r--core/java/android/transition/TransitionManager.java26
-rw-r--r--core/java/android/util/PackageUtils.java96
-rw-r--r--core/java/android/view/DragEvent.java2
-rw-r--r--core/java/android/view/IWindowManager.aidl10
-rw-r--r--core/java/android/view/View.java68
-rw-r--r--core/java/android/view/ViewGroup.java161
-rw-r--r--core/java/android/view/ViewRootImpl.java44
-rw-r--r--core/java/android/view/WindowManagerPolicy.java10
-rw-r--r--core/java/com/android/server/backup/AccountManagerBackupHelper.java85
-rw-r--r--core/java/com/android/server/backup/SystemBackupAgent.java3
-rw-r--r--core/jni/android/graphics/Shader.cpp16
-rw-r--r--core/jni/android_os_HwParcel.cpp209
-rw-r--r--core/jni/hwbinder/EphemeralStorage.cpp22
-rw-r--r--core/jni/hwbinder/EphemeralStorage.h3
-rw-r--r--docs/html/_redirects.yaml3
-rw-r--r--docs/html/develop/index.jd2
-rw-r--r--docs/html/index.jd2
-rw-r--r--docs/html/jd_extras_en.js6
-rw-r--r--docs/html/topic/arc/index.jd2
-rw-r--r--docs/html/training/testing/unit-testing/instrumented-unit-tests.jd5
-rw-r--r--libs/hwui/SkiaCanvas.cpp12
-rw-r--r--libs/hwui/tests/unit/RecordingCanvasTests.cpp26
-rw-r--r--libs/hwui/tests/unit/SkiaBehaviorTests.cpp10
-rw-r--r--packages/SystemUI/res/drawable/ic_qs_data_disabled.xml5
-rw-r--r--packages/SystemUI/res/drawable/stat_sys_data_disabled.xml4
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java37
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java25
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/tv/RecentsTvImpl.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java19
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java45
-rw-r--r--packages/SystemUI/src/com/android/systemui/tv/pip/PipManager.java7
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/TileLayoutTest.java162
-rw-r--r--packages/WallpaperBackup/src/com/android/wallpaperbackup/WallpaperBackupAgent.java5
-rw-r--r--services/accessibility/java/com/android/server/accessibility/AccessibilityGestureDetector.java2
-rw-r--r--services/core/Android.mk2
-rw-r--r--services/core/java/com/android/server/ConnectivityService.java100
-rw-r--r--services/core/java/com/android/server/ServiceWatcher.java17
-rw-r--r--services/core/java/com/android/server/TextServicesManagerService.java106
-rw-r--r--services/core/java/com/android/server/accounts/AccountManagerBackupHelper.java312
-rw-r--r--services/core/java/com/android/server/accounts/AccountManagerService.java194
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerService.java276
-rw-r--r--services/core/java/com/android/server/connectivity/MetricsLoggerService.java10
-rw-r--r--services/core/java/com/android/server/connectivity/NetdEventListenerService.java (renamed from services/core/java/com/android/server/connectivity/DnsEventListenerService.java)16
-rw-r--r--services/core/java/com/android/server/connectivity/NetworkAgentInfo.java16
-rw-r--r--services/core/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachine.java13
-rw-r--r--services/core/java/com/android/server/content/ContentService.java4
-rw-r--r--services/core/java/com/android/server/content/SyncManager.java59
-rw-r--r--services/core/java/com/android/server/content/SyncStorageEngine.java6
-rw-r--r--services/core/java/com/android/server/dreams/DreamController.java33
-rw-r--r--services/core/java/com/android/server/dreams/DreamManagerService.java10
-rw-r--r--services/core/java/com/android/server/lights/LightsService.java10
-rw-r--r--services/core/java/com/android/server/media/MediaSessionService.java7
-rw-r--r--services/core/java/com/android/server/net/NetworkPolicyManagerService.java58
-rw-r--r--services/core/java/com/android/server/notification/NotificationManagerService.java3
-rw-r--r--services/core/java/com/android/server/os/DeviceIdentifiersPolicyService.java63
-rw-r--r--services/core/java/com/android/server/pm/OtaDexoptService.java1
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerService.java7
-rw-r--r--services/core/java/com/android/server/pm/Settings.java8
-rw-r--r--services/core/java/com/android/server/policy/ImmersiveModeConfirmation.java13
-rw-r--r--services/core/java/com/android/server/policy/PhoneWindowManager.java28
-rw-r--r--services/core/java/com/android/server/power/PowerManagerService.java10
-rw-r--r--services/core/java/com/android/server/wallpaper/WallpaperManagerService.java29
-rw-r--r--services/core/java/com/android/server/wm/AppWindowToken.java8
-rw-r--r--services/core/java/com/android/server/wm/DisplayContent.java19
-rw-r--r--services/core/java/com/android/server/wm/Task.java24
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerService.java71
-rw-r--r--services/core/java/com/android/server/wm/WindowToken.java9
-rw-r--r--services/java/com/android/server/SystemServer.java18
-rw-r--r--services/net/java/android/net/ip/IpManager.java50
-rw-r--r--services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java97
-rw-r--r--services/tests/servicestests/src/com/android/server/connectivity/NetdEventListenerServiceTest.java (renamed from services/tests/servicestests/src/com/android/server/connectivity/DnsEventListenerServiceTest.java)18
-rw-r--r--services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java10
-rw-r--r--tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java10
-rw-r--r--wifi/java/android/net/wifi/WifiScanner.java21
-rw-r--r--wifi/java/android/net/wifi/nan/IWifiNanDiscoverySessionCallback.aidl (renamed from wifi/java/android/net/wifi/nan/IWifiNanSessionCallback.aidl)2
-rw-r--r--wifi/java/android/net/wifi/nan/IWifiNanManager.aidl7
-rw-r--r--wifi/java/android/net/wifi/nan/PublishConfig.java20
-rw-r--r--wifi/java/android/net/wifi/nan/SubscribeConfig.java22
-rw-r--r--wifi/java/android/net/wifi/nan/WifiNanDiscoveryBaseSession.java (renamed from wifi/java/android/net/wifi/nan/WifiNanSession.java)53
-rw-r--r--wifi/java/android/net/wifi/nan/WifiNanDiscoverySessionCallback.java (renamed from wifi/java/android/net/wifi/nan/WifiNanSessionCallback.java)67
-rw-r--r--wifi/java/android/net/wifi/nan/WifiNanEventCallback.java2
-rw-r--r--wifi/java/android/net/wifi/nan/WifiNanManager.java126
-rw-r--r--wifi/java/android/net/wifi/nan/WifiNanPublishDiscoverySession.java (renamed from wifi/java/android/net/wifi/nan/WifiNanPublishSession.java)27
-rw-r--r--wifi/java/android/net/wifi/nan/WifiNanSubscribeDiscoverySession.java (renamed from wifi/java/android/net/wifi/nan/WifiNanSubscribeSession.java)29
115 files changed, 2657 insertions, 1260 deletions
diff --git a/Android.mk b/Android.mk
index 534b5e5a5523..d646d9c81a5e 100644
--- a/Android.mk
+++ b/Android.mk
@@ -63,6 +63,7 @@ LOCAL_SRC_FILES += \
core/java/android/accessibilityservice/IAccessibilityServiceClient.aidl \
core/java/android/accounts/IAccountManager.aidl \
core/java/android/accounts/IAccountManagerResponse.aidl \
+ core/java/android/accounts/IAccountAccessTracker.aidl \
core/java/android/accounts/IAccountAuthenticator.aidl \
core/java/android/accounts/IAccountAuthenticatorResponse.aidl \
core/java/android/app/IActivityContainer.aidl \
@@ -221,6 +222,7 @@ LOCAL_SRC_FILES += \
core/java/android/os/IBatteryPropertiesListener.aidl \
core/java/android/os/IBatteryPropertiesRegistrar.aidl \
core/java/android/os/ICancellationSignal.aidl \
+ core/java/android/os/IDeviceIdentifiersPolicyService.aidl \
core/java/android/os/IDeviceIdleController.aidl \
core/java/android/os/IHardwarePropertiesManager.aidl \
core/java/android/os/IMaintenanceActivityListener.aidl \
@@ -456,7 +458,7 @@ LOCAL_SRC_FILES += \
wifi/java/android/net/wifi/IWifiManager.aidl \
wifi/java/android/net/wifi/nan/IWifiNanEventCallback.aidl \
wifi/java/android/net/wifi/nan/IWifiNanManager.aidl \
- wifi/java/android/net/wifi/nan/IWifiNanSessionCallback.aidl \
+ wifi/java/android/net/wifi/nan/IWifiNanDiscoverySessionCallback.aidl \
wifi/java/android/net/wifi/p2p/IWifiP2pManager.aidl \
wifi/java/android/net/wifi/IWifiScanner.aidl \
wifi/java/android/net/wifi/IRttManager.aidl \
diff --git a/api/current.txt b/api/current.txt
index dea5cec7f60e..25c6ab379bfd 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -28398,6 +28398,7 @@ package android.os {
public class Build {
ctor public Build();
method public static java.lang.String getRadioVersion();
+ method public static java.lang.String getSerial();
field public static final java.lang.String BOARD;
field public static final java.lang.String BOOTLOADER;
field public static final java.lang.String BRAND;
@@ -28413,7 +28414,7 @@ package android.os {
field public static final java.lang.String MODEL;
field public static final java.lang.String PRODUCT;
field public static final deprecated java.lang.String RADIO;
- field public static final java.lang.String SERIAL;
+ field public static final deprecated java.lang.String SERIAL;
field public static final java.lang.String[] SUPPORTED_32_BIT_ABIS;
field public static final java.lang.String[] SUPPORTED_64_BIT_ABIS;
field public static final java.lang.String[] SUPPORTED_ABIS;
diff --git a/api/system-current.txt b/api/system-current.txt
index 0911f0ac08d9..49a976edb36f 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -30888,6 +30888,7 @@ package android.os {
public class Build {
ctor public Build();
method public static java.lang.String getRadioVersion();
+ method public static java.lang.String getSerial();
field public static final java.lang.String BOARD;
field public static final java.lang.String BOOTLOADER;
field public static final java.lang.String BRAND;
@@ -30904,7 +30905,7 @@ package android.os {
field public static final boolean PERMISSIONS_REVIEW_REQUIRED;
field public static final java.lang.String PRODUCT;
field public static final deprecated java.lang.String RADIO;
- field public static final java.lang.String SERIAL;
+ field public static final deprecated java.lang.String SERIAL;
field public static final java.lang.String[] SUPPORTED_32_BIT_ABIS;
field public static final java.lang.String[] SUPPORTED_64_BIT_ABIS;
field public static final java.lang.String[] SUPPORTED_ABIS;
diff --git a/api/test-current.txt b/api/test-current.txt
index 5c065896cb97..8b0b0e80f0c0 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -28470,6 +28470,7 @@ package android.os {
public class Build {
ctor public Build();
method public static java.lang.String getRadioVersion();
+ method public static java.lang.String getSerial();
field public static final java.lang.String BOARD;
field public static final java.lang.String BOOTLOADER;
field public static final java.lang.String BRAND;
@@ -28485,7 +28486,7 @@ package android.os {
field public static final java.lang.String MODEL;
field public static final java.lang.String PRODUCT;
field public static final deprecated java.lang.String RADIO;
- field public static final java.lang.String SERIAL;
+ field public static final deprecated java.lang.String SERIAL;
field public static final java.lang.String[] SUPPORTED_32_BIT_ABIS;
field public static final java.lang.String[] SUPPORTED_64_BIT_ABIS;
field public static final java.lang.String[] SUPPORTED_ABIS;
diff --git a/core/java/android/accounts/Account.java b/core/java/android/accounts/Account.java
index 7b83a3076db3..6c16e322e978 100644
--- a/core/java/android/accounts/Account.java
+++ b/core/java/android/accounts/Account.java
@@ -16,9 +16,17 @@
package android.accounts;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.os.Parcelable;
import android.os.Parcel;
+import android.os.RemoteException;
import android.text.TextUtils;
+import android.util.ArraySet;
+import android.util.Log;
+import com.android.internal.annotations.GuardedBy;
+
+import java.util.Set;
/**
* Value type that represents an Account in the {@link AccountManager}. This object is
@@ -26,8 +34,14 @@ import android.text.TextUtils;
* suitable for use as the key of a {@link java.util.Map}
*/
public class Account implements Parcelable {
+ private static final String TAG = "Account";
+
+ @GuardedBy("sAccessedAccounts")
+ private static final Set<Account> sAccessedAccounts = new ArraySet<>();
+
public final String name;
public final String type;
+ private final @Nullable IAccountAccessTracker mAccessTracker;
public boolean equals(Object o) {
if (o == this) return true;
@@ -44,6 +58,20 @@ public class Account implements Parcelable {
}
public Account(String name, String type) {
+ this(name, type, null);
+ }
+
+ /**
+ * @hide
+ */
+ public Account(@NonNull Account other, @Nullable IAccountAccessTracker accessTracker) {
+ this(other.name, other.type, accessTracker);
+ }
+
+ /**
+ * @hide
+ */
+ public Account(String name, String type, IAccountAccessTracker accessTracker) {
if (TextUtils.isEmpty(name)) {
throw new IllegalArgumentException("the name must not be empty: " + name);
}
@@ -52,11 +80,29 @@ public class Account implements Parcelable {
}
this.name = name;
this.type = type;
+ this.mAccessTracker = accessTracker;
}
public Account(Parcel in) {
this.name = in.readString();
this.type = in.readString();
+ this.mAccessTracker = IAccountAccessTracker.Stub.asInterface(in.readStrongBinder());
+ if (mAccessTracker != null) {
+ synchronized (sAccessedAccounts) {
+ if (sAccessedAccounts.add(this)) {
+ try {
+ mAccessTracker.onAccountAccessed();
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error noting account access", e);
+ }
+ }
+ }
+ }
+ }
+
+ /** @hide */
+ public IAccountAccessTracker getAccessTracker() {
+ return mAccessTracker;
}
public int describeContents() {
@@ -66,6 +112,7 @@ public class Account implements Parcelable {
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(name);
dest.writeString(type);
+ dest.writeStrongInterface(mAccessTracker);
}
public static final Creator<Account> CREATOR = new Creator<Account>() {
diff --git a/core/java/android/accounts/AccountManager.java b/core/java/android/accounts/AccountManager.java
index 26e7dac587f4..1eb63e0d44ad 100644
--- a/core/java/android/accounts/AccountManager.java
+++ b/core/java/android/accounts/AccountManager.java
@@ -18,7 +18,6 @@ package android.accounts;
import static android.Manifest.permission.GET_ACCOUNTS;
-import android.annotation.IntRange;
import android.annotation.NonNull;
import android.annotation.RequiresPermission;
import android.annotation.Size;
@@ -180,6 +179,14 @@ public class AccountManager {
public static final String KEY_ACCOUNT_TYPE = "accountType";
/**
+ * Bundle key used for the {@link IAccountAccessTracker} account access tracker
+ * used for noting the account was accessed when unmarshalled from a parcel.
+ *
+ * @hide
+ */
+ public static final String KEY_ACCOUNT_ACCESS_TRACKER = "accountAccessTracker";
+
+ /**
* Bundle key used for the auth token value in results
* from {@link #getAuthToken} and friends.
*/
@@ -264,13 +271,13 @@ public class AccountManager {
public static final String AUTHENTICATOR_ATTRIBUTES_NAME = "account-authenticator";
/**
- * Token for the special case where a UID has access only to an account
- * but no authenticator specific auth tokens.
+ * Token type for the special case where a UID has access only to an account
+ * but no authenticator specific auth token types.
*
* @hide
*/
- public static final String ACCOUNT_ACCESS_TOKEN =
- "com.android.abbfd278-af8b-415d-af8b-7571d5dab133";
+ public static final String ACCOUNT_ACCESS_TOKEN_TYPE =
+ "com.android.AccountManager.ACCOUNT_ACCESS_TOKEN_TYPE";
private final Context mContext;
private final IAccountManager mService;
@@ -919,7 +926,9 @@ public class AccountManager {
public Account bundleToResult(Bundle bundle) throws AuthenticatorException {
String name = bundle.getString(KEY_ACCOUNT_NAME);
String type = bundle.getString(KEY_ACCOUNT_TYPE);
- return new Account(name, type);
+ IAccountAccessTracker tracker = IAccountAccessTracker.Stub.asInterface(
+ bundle.getBinder(KEY_ACCOUNT_ACCESS_TRACKER));
+ return new Account(name, type, tracker);
}
}.start();
}
@@ -2379,6 +2388,7 @@ public class AccountManager {
result.putString(KEY_ACCOUNT_NAME, null);
result.putString(KEY_ACCOUNT_TYPE, null);
result.putString(KEY_AUTHTOKEN, null);
+ result.putBinder(KEY_ACCOUNT_ACCESS_TRACKER, null);
try {
mResponse.onResult(result);
} catch (RemoteException e) {
@@ -2404,9 +2414,13 @@ public class AccountManager {
public void onResult(Bundle value) throws RemoteException {
Account account = new Account(
value.getString(KEY_ACCOUNT_NAME),
- value.getString(KEY_ACCOUNT_TYPE));
- mFuture = getAuthToken(account, mAuthTokenType, mLoginOptions,
- mActivity, mMyCallback, mHandler);
+ value.getString(KEY_ACCOUNT_TYPE),
+ IAccountAccessTracker.Stub.asInterface(
+ value.getBinder(
+ KEY_ACCOUNT_ACCESS_TRACKER)));
+ mFuture = getAuthToken(account, mAuthTokenType,
+ mLoginOptions, mActivity, mMyCallback,
+ mHandler);
}
@Override
@@ -2453,7 +2467,9 @@ public class AccountManager {
setException(new AuthenticatorException("account not in result"));
return;
}
- final Account account = new Account(accountName, accountType);
+ final IAccountAccessTracker tracker = IAccountAccessTracker.Stub.asInterface(
+ result.getBinder(KEY_ACCOUNT_ACCESS_TRACKER));
+ final Account account = new Account(accountName, accountType, tracker);
mNumAccounts = 1;
getAuthToken(account, mAuthTokenType, null /* options */, mActivity,
mMyCallback, mHandler);
diff --git a/core/java/android/accounts/AccountManagerInternal.java b/core/java/android/accounts/AccountManagerInternal.java
index d777643950e6..68c17c32fdc3 100644
--- a/core/java/android/accounts/AccountManagerInternal.java
+++ b/core/java/android/accounts/AccountManagerInternal.java
@@ -28,6 +28,21 @@ import android.os.RemoteCallback;
public abstract class AccountManagerInternal {
/**
+ * Listener for explicit UID account access grant changes.
+ */
+ public interface OnAppPermissionChangeListener {
+
+ /**
+ * Called when the explicit grant state for a given UID to
+ * access an account changes.
+ *
+ * @param account The account
+ * @param uid The UID for which the grant changed
+ */
+ public void onAppPermissionChanged(Account account, int uid);
+ }
+
+ /**
* Requests that a given package is given access to an account.
* The provided callback will be invoked with a {@link android.os.Bundle}
* containing the result which will be a boolean value mapped to the
@@ -38,7 +53,38 @@ public abstract class AccountManagerInternal {
* @param userId Concrete user id for which to request.
* @param callback A callback for receiving the result.
*/
- public abstract void requestAccountAccess(@NonNull Account account,
+ public abstract void requestAccountAccess(@NonNull Account account,
@NonNull String packageName, @IntRange(from = 0) int userId,
@NonNull RemoteCallback callback);
+
+ /**
+ * Check whether the given UID has access to the account.
+ *
+ * @param account The account
+ * @param uid The UID
+ * @return Whether the UID can access the account
+ */
+ public abstract boolean hasAccountAccess(@NonNull Account account, @IntRange(from = 0) int uid);
+
+ /**
+ * Adds a listener for explicit UID account access grant changes.
+ *
+ * @param listener The listener
+ */
+ public abstract void addOnAppPermissionChangeListener(
+ @NonNull OnAppPermissionChangeListener listener);
+
+ /**
+ * Backups the account access permissions.
+ * @param userId The user for which to backup.
+ * @return The backup data.
+ */
+ public abstract byte[] backupAccountAccessPermissions(int userId);
+
+ /**
+ * Restores the account access permissions.
+ * @param data The restore data.
+ * @param userId The user for which to restore.
+ */
+ public abstract void restoreAccountAccessPermissions(byte[] data, int userId);
}
diff --git a/core/java/android/accounts/GrantCredentialsPermissionActivity.java b/core/java/android/accounts/GrantCredentialsPermissionActivity.java
index 8d0ce58d3358..38eab2905022 100644
--- a/core/java/android/accounts/GrantCredentialsPermissionActivity.java
+++ b/core/java/android/accounts/GrantCredentialsPermissionActivity.java
@@ -108,7 +108,7 @@ public class GrantCredentialsPermissionActivity extends Activity implements View
}
};
- if (!AccountManager.ACCOUNT_ACCESS_TOKEN.equals(mAuthTokenType)) {
+ if (!AccountManager.ACCOUNT_ACCESS_TOKEN_TYPE.equals(mAuthTokenType)) {
AccountManager.get(this).getAuthTokenLabel(mAccount.type,
mAuthTokenType, callback, null);
}
diff --git a/core/java/android/accounts/IAccountAccessTracker.aidl b/core/java/android/accounts/IAccountAccessTracker.aidl
new file mode 100644
index 000000000000..e12b3d1e21c7
--- /dev/null
+++ b/core/java/android/accounts/IAccountAccessTracker.aidl
@@ -0,0 +1,26 @@
+/*
+ * 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.accounts;
+
+/**
+ * Interface to track which apps accessed an account
+ *
+ * @hide
+ */
+oneway interface IAccountAccessTracker {
+ void onAccountAccessed();
+}
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index cd4ba7ce2817..a0408c93c724 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -128,6 +128,8 @@ import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.lang.ref.WeakReference;
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
import java.net.InetAddress;
import java.text.DateFormat;
import java.util.ArrayList;
@@ -519,6 +521,7 @@ public final class ActivityThread {
boolean persistent;
Configuration config;
CompatibilityInfo compatInfo;
+ String buildSerial;
/** Initial values for {@link Profiler}. */
ProfilerInfo initProfilerInfo;
@@ -855,7 +858,8 @@ public final class ActivityThread {
IUiAutomationConnection instrumentationUiConnection, int debugMode,
boolean enableBinderTracking, boolean trackAllocation,
boolean isRestrictedBackupMode, boolean persistent, Configuration config,
- CompatibilityInfo compatInfo, Map<String, IBinder> services, Bundle coreSettings) {
+ CompatibilityInfo compatInfo, Map<String, IBinder> services, Bundle coreSettings,
+ String buildSerial) {
if (services != null) {
// Setup the service cache in the ServiceManager
@@ -880,6 +884,7 @@ public final class ActivityThread {
data.config = config;
data.compatInfo = compatInfo;
data.initProfilerInfo = profilerInfo;
+ data.buildSerial = buildSerial;
sendMessage(H.BIND_APPLICATION, data);
}
@@ -5196,6 +5201,18 @@ public final class ActivityThread {
StrictMode.enableDeathOnFileUriExposure();
}
+ // We deprecated Build.SERIAL and only apps that target pre NMR1
+ // SDK can see it. Since access to the serial is now behind a
+ // permission we push down the value and here we fix it up
+ // before any app code has been loaded.
+ try {
+ Field field = Build.class.getDeclaredField("SERIAL");
+ field.setAccessible(true);
+ field.set(Build.class, data.buildSerial);
+ } catch (NoSuchFieldException | IllegalAccessException e) {
+ /* ignore */
+ }
+
if (data.debugMode != IApplicationThread.DEBUG_OFF) {
// XXX should have option to change the port.
Debug.changeDebugPort(8100);
diff --git a/core/java/android/app/ApplicationThreadNative.java b/core/java/android/app/ApplicationThreadNative.java
index 28899e269fbe..12e527ea4841 100644
--- a/core/java/android/app/ApplicationThreadNative.java
+++ b/core/java/android/app/ApplicationThreadNative.java
@@ -302,10 +302,11 @@ public abstract class ApplicationThreadNative extends Binder
CompatibilityInfo compatInfo = CompatibilityInfo.CREATOR.createFromParcel(data);
HashMap<String, IBinder> services = data.readHashMap(null);
Bundle coreSettings = data.readBundle();
+ String buildSerial = data.readString();
bindApplication(packageName, info, providers, testName, profilerInfo, testArgs,
testWatcher, uiAutomationConnection, testMode, enableBinderTracking,
trackAllocation, restrictedBackupMode, persistent, config, compatInfo, services,
- coreSettings);
+ coreSettings, buildSerial);
return true;
}
@@ -1060,7 +1061,8 @@ class ApplicationThreadProxy implements IApplicationThread {
IUiAutomationConnection uiAutomationConnection, int debugMode,
boolean enableBinderTracking, boolean trackAllocation, boolean restrictedBackupMode,
boolean persistent, Configuration config, CompatibilityInfo compatInfo,
- Map<String, IBinder> services, Bundle coreSettings) throws RemoteException {
+ Map<String, IBinder> services, Bundle coreSettings, String buildSerial)
+ throws RemoteException {
Parcel data = Parcel.obtain();
data.writeInterfaceToken(IApplicationThread.descriptor);
data.writeString(packageName);
@@ -1090,6 +1092,7 @@ class ApplicationThreadProxy implements IApplicationThread {
compatInfo.writeToParcel(data, 0);
data.writeMap(services);
data.writeBundle(coreSettings);
+ data.writeString(buildSerial);
mRemote.transact(BIND_APPLICATION_TRANSACTION, data, null,
IBinder.FLAG_ONEWAY);
data.recycle();
diff --git a/core/java/android/app/IApplicationThread.java b/core/java/android/app/IApplicationThread.java
index 131c1f9be685..4189dd96d3f9 100644
--- a/core/java/android/app/IApplicationThread.java
+++ b/core/java/android/app/IApplicationThread.java
@@ -99,8 +99,8 @@ public interface IApplicationThread extends IInterface {
IInstrumentationWatcher testWatcher, IUiAutomationConnection uiAutomationConnection,
int debugMode, boolean enableBinderTracking, boolean trackAllocation,
boolean restrictedBackupMode, boolean persistent, Configuration config,
- CompatibilityInfo compatInfo, Map<String, IBinder> services, Bundle coreSettings)
- throws RemoteException;
+ CompatibilityInfo compatInfo, Map<String, IBinder> services, Bundle coreSettings,
+ String buildSerial) throws RemoteException;
void scheduleExit() throws RemoteException;
void scheduleSuicide() throws RemoteException;
void scheduleConfigurationChanged(Configuration config) throws RemoteException;
diff --git a/core/java/android/bluetooth/BluetoothAvrcpController.java b/core/java/android/bluetooth/BluetoothAvrcpController.java
index 444e4293fe2b..a395aa470f5b 100644
--- a/core/java/android/bluetooth/BluetoothAvrcpController.java
+++ b/core/java/android/bluetooth/BluetoothAvrcpController.java
@@ -66,21 +66,6 @@ public final class BluetoothAvrcpController implements BluetoothProfile {
"android.bluetooth.avrcp-controller.profile.action.CONNECTION_STATE_CHANGED";
/**
- * Intent used to broadcast the change in metadata state of playing track on the AVRCP
- * AG.
- *
- * <p>This intent will have the two extras:
- * <ul>
- * <li> {@link #EXTRA_METADATA} - {@link MediaMetadata} containing the current metadata.</li>
- * <li> {@link #EXTRA_PLAYBACK} - {@link PlaybackState} containing the current playback
- * state. </li>
- * </ul>
- */
- public static final String ACTION_TRACK_EVENT =
- "android.bluetooth.avrcp-controller.profile.action.TRACK_EVENT";
-
-
- /**
* Intent used to broadcast the change in player application setting state on AVRCP AG.
*
* <p>This intent will have the following extras:
@@ -92,35 +77,9 @@ public final class BluetoothAvrcpController implements BluetoothProfile {
public static final String ACTION_PLAYER_SETTING =
"android.bluetooth.avrcp-controller.profile.action.PLAYER_SETTING";
- public static final String EXTRA_METADATA =
- "android.bluetooth.avrcp-controller.profile.extra.METADATA";
-
- public static final String EXTRA_PLAYBACK =
- "android.bluetooth.avrcp-controller.profile.extra.PLAYBACK";
-
public static final String EXTRA_PLAYER_SETTING =
"android.bluetooth.avrcp-controller.profile.extra.PLAYER_SETTING";
- /*
- * KeyCoded for Pass Through Commands
- */
- public static final int PASS_THRU_CMD_ID_PLAY = 0x44;
- public static final int PASS_THRU_CMD_ID_PAUSE = 0x46;
- public static final int PASS_THRU_CMD_ID_VOL_UP = 0x41;
- public static final int PASS_THRU_CMD_ID_VOL_DOWN = 0x42;
- public static final int PASS_THRU_CMD_ID_STOP = 0x45;
- public static final int PASS_THRU_CMD_ID_FF = 0x49;
- public static final int PASS_THRU_CMD_ID_REWIND = 0x48;
- public static final int PASS_THRU_CMD_ID_FORWARD = 0x4B;
- public static final int PASS_THRU_CMD_ID_BACKWARD = 0x4C;
- /* Key State Variables */
- public static final int KEY_STATE_PRESSED = 0;
- public static final int KEY_STATE_RELEASED = 1;
- /* Group Navigation Key Codes */
- public static final int PASS_THRU_CMD_ID_NEXT_GRP = 0x00;
- public static final int PASS_THRU_CMD_ID_PREV_GRP = 0x01;
-
-
private Context mContext;
private ServiceListener mServiceListener;
private IBluetoothAvrcpController mService;
@@ -267,20 +226,6 @@ public final class BluetoothAvrcpController implements BluetoothProfile {
return BluetoothProfile.STATE_DISCONNECTED;
}
- public void sendPassThroughCmd(BluetoothDevice device, int keyCode, int keyState) {
- if (DBG) Log.d(TAG, "sendPassThroughCmd");
- if (mService != null && isEnabled()) {
- try {
- mService.sendPassThroughCmd(device, keyCode, keyState);
- return;
- } catch (RemoteException e) {
- Log.e(TAG, "Error talking to BT service in sendPassThroughCmd()", e);
- return;
- }
- }
- if (mService == null) Log.w(TAG, "Proxy not attached to service");
- }
-
/**
* Gets the player application settings.
*
@@ -301,49 +246,6 @@ public final class BluetoothAvrcpController implements BluetoothProfile {
}
/**
- * Gets the metadata for the current track.
- *
- * This should be usually called when application UI needs to be updated, eg. when the track
- * changes or immediately after connecting and getting the current state.
- * @return the {@link MediaMetadata} or {@link null} if there is an error.
- */
- public MediaMetadata getMetadata(BluetoothDevice device) {
- if (DBG) Log.d(TAG, "getMetadata");
- MediaMetadata metadata = null;
- if (mService != null && isEnabled()) {
- try {
- metadata = mService.getMetadata(device);
- } catch (RemoteException e) {
- Log.e(TAG, "Error talking to BT service in getMetadata() " + e);
- return null;
- }
- }
- return metadata;
- }
-
- /**
- * Gets the playback state for current track.
- *
- * When the application is first connecting it can use current track state to get playback info.
- * For all further updates it should listen to notifications.
- * @return the {@link PlaybackState} or {@link null} if there is an error.
- */
- public PlaybackState getPlaybackState(BluetoothDevice device) {
- if (DBG) Log.d(TAG, "getPlaybackState");
- PlaybackState playbackState = null;
- if (mService != null && isEnabled()) {
- try {
- playbackState = mService.getPlaybackState(device);
- } catch (RemoteException e) {
- Log.e(TAG,
- "Error talking to BT service in getPlaybackState() " + e);
- return null;
- }
- }
- return playbackState;
- }
-
- /**
* Sets the player app setting for current player.
* returns true in case setting is supported by remote, false otherwise
*/
diff --git a/core/java/android/bluetooth/BluetoothDevice.java b/core/java/android/bluetooth/BluetoothDevice.java
index 189147efa829..6d6dfebced2c 100644
--- a/core/java/android/bluetooth/BluetoothDevice.java
+++ b/core/java/android/bluetooth/BluetoothDevice.java
@@ -1167,12 +1167,12 @@ public final class BluetoothDevice implements Parcelable {
/**
* Confirm passkey for {@link #PAIRING_VARIANT_PASSKEY_CONFIRMATION} pairing.
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}.
+ * <p>Requires {@link android.Manifest.permission#BLUETOOTH_PRIVILEGED}.
*
* @return true confirmation has been sent out
* false for error
*/
- @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN)
+ @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
public boolean setPairingConfirmation(boolean confirm) {
if (sService == null) {
Log.e(TAG, "BT not enabled. Cannot set pairing confirmation");
diff --git a/core/java/android/bluetooth/IBluetoothAvrcpController.aidl b/core/java/android/bluetooth/IBluetoothAvrcpController.aidl
index f1288d022290..cfa11cac4a8a 100644
--- a/core/java/android/bluetooth/IBluetoothAvrcpController.aidl
+++ b/core/java/android/bluetooth/IBluetoothAvrcpController.aidl
@@ -30,10 +30,7 @@ interface IBluetoothAvrcpController {
List<BluetoothDevice> getConnectedDevices();
List<BluetoothDevice> getDevicesMatchingConnectionStates(in int[] states);
int getConnectionState(in BluetoothDevice device);
- void sendPassThroughCmd(in BluetoothDevice device, int keyCode, int keyState);
BluetoothAvrcpPlayerSettings getPlayerSettings(in BluetoothDevice device);
- MediaMetadata getMetadata(in BluetoothDevice device);
- PlaybackState getPlaybackState(in BluetoothDevice device);
boolean setPlayerApplicationSetting(in BluetoothAvrcpPlayerSettings plAppSetting);
void sendGroupNavigationCmd(in BluetoothDevice device, int keyCode, int keyState);
}
diff --git a/core/java/android/content/ContentResolver.java b/core/java/android/content/ContentResolver.java
index b3320d6f6976..daa1b93889cc 100644
--- a/core/java/android/content/ContentResolver.java
+++ b/core/java/android/content/ContentResolver.java
@@ -1877,6 +1877,7 @@ public abstract class ContentResolver {
if (extras != null) {
String accountName = extras.getString(SYNC_EXTRAS_ACCOUNT);
if (!TextUtils.isEmpty(accountName)) {
+ // TODO: No references to Google in AOSP
account = new Account(accountName, "com.google");
}
extras.remove(SYNC_EXTRAS_ACCOUNT);
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index b295919f6af9..457866b24aab 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -3675,6 +3675,12 @@ public abstract class Context {
public static final String GATEKEEPER_SERVICE = "android.service.gatekeeper.IGateKeeperService";
/**
+ * Service defining the policy for access to device identifiers.
+ * @hide
+ */
+ public static final String DEVICE_IDENTIFIERS_SERVICE = "device_identifiers";
+
+ /**
* Determine whether the given permission is allowed for a particular
* process and user ID running in the system.
*
diff --git a/core/java/android/content/pm/PackageManagerInternal.java b/core/java/android/content/pm/PackageManagerInternal.java
index d208fe7c10ca..f5bcf64417a6 100644
--- a/core/java/android/content/pm/PackageManagerInternal.java
+++ b/core/java/android/content/pm/PackageManagerInternal.java
@@ -160,4 +160,12 @@ public abstract class PackageManagerInternal {
* Returns {@code true} if a given package can't be wiped. Otherwise, returns {@code false}.
*/
public abstract boolean isPackageDataProtected(int userId, String packageName);
+
+ /**
+ * Gets whether the package was ever launched.
+ * @param packageName The package name.
+ * @param userId The user for which to check.
+ * @return Whether was launched.
+ */
+ public abstract boolean wasPackageEverLaunched(String packageName, int userId);
}
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index fd9e60d74215..c793a6eadf49 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -3241,6 +3241,27 @@ public class ConnectivityManager {
}
/**
+ * Informs the system to penalize {@code network}'s score when it becomes unvalidated. This is
+ * only meaningful if the system is configured not to penalize such networks, e.g., if the
+ * {@code config_networkAvoidBadWifi} configuration variable is set to 0 and the {@code
+ * NETWORK_AVOID_BAD_WIFI setting is unset}.
+ *
+ * <p>This method requires the caller to hold the permission
+ * {@link android.Manifest.permission#CONNECTIVITY_INTERNAL}
+ *
+ * @param network The network to accept.
+ *
+ * @hide
+ */
+ public void setAvoidUnvalidated(Network network) {
+ try {
+ mService.setAvoidUnvalidated(network);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* Resets all connectivity manager settings back to factory defaults.
* @hide
*/
diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl
index d48c155986f3..4aabda9eb09d 100644
--- a/core/java/android/net/IConnectivityManager.aidl
+++ b/core/java/android/net/IConnectivityManager.aidl
@@ -161,6 +161,7 @@ interface IConnectivityManager
void releaseNetworkRequest(in NetworkRequest networkRequest);
void setAcceptUnvalidated(in Network network, boolean accept, boolean always);
+ void setAvoidUnvalidated(in Network network);
int getRestoreDefaultNetworkDelay(int networkType);
diff --git a/core/java/android/net/InterfaceConfiguration.java b/core/java/android/net/InterfaceConfiguration.java
index 8cdd15305018..ea53a71245a5 100644
--- a/core/java/android/net/InterfaceConfiguration.java
+++ b/core/java/android/net/InterfaceConfiguration.java
@@ -80,6 +80,14 @@ public class InterfaceConfiguration implements Parcelable {
mFlags.add(FLAG_DOWN);
}
+ /**
+ * Set flags so that no changes will be made to the up/down status.
+ */
+ public void ignoreInterfaceUpDownStatus() {
+ mFlags.remove(FLAG_UP);
+ mFlags.remove(FLAG_DOWN);
+ }
+
public LinkAddress getLinkAddress() {
return mAddr;
}
diff --git a/core/java/android/net/metrics/DnsEvent.java b/core/java/android/net/metrics/DnsEvent.java
index 4fc6b7aaf842..6176b2c58deb 100644
--- a/core/java/android/net/metrics/DnsEvent.java
+++ b/core/java/android/net/metrics/DnsEvent.java
@@ -21,7 +21,7 @@ import android.os.Parcel;
import android.os.Parcelable;
/**
- * An event recorded by DnsEventListenerService.
+ * A DNS event recorded by NetdEventListenerService.
* {@hide}
*/
@SystemApi
diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java
index 5b51002120d6..01915895c229 100644
--- a/core/java/android/os/Build.java
+++ b/core/java/android/os/Build.java
@@ -16,7 +16,10 @@
package android.os;
+import android.Manifest;
+import android.annotation.RequiresPermission;
import android.annotation.SystemApi;
+import android.content.Context;
import android.text.TextUtils;
import android.util.Slog;
@@ -98,8 +101,35 @@ public class Build {
*/
public static final boolean IS_EMULATOR = getString("ro.kernel.qemu").equals("1");
- /** A hardware serial number, if available. Alphanumeric only, case-insensitive. */
- public static final String SERIAL = getString("ro.serialno");
+ /**
+ * A hardware serial number, if available. Alphanumeric only, case-insensitive.
+ * For apps targeting SDK higher than {@link Build.VERSION_CODES#N_MR1} this
+ * field is set to {@link Build#UNKNOWN}.
+ *
+ * @deprecated Use {@link #getSerial()} instead.
+ **/
+ @Deprecated
+ // IMPORTANT: This field should be initialized via a function call to
+ // prevent its value being inlined in the app during compilation because
+ // we will later set it to the value based on the app's target SDK.
+ public static final String SERIAL = getString("no.such.thing");
+
+ /**
+ * Gets the hardware serial, if available. Requires holding the {@link
+ * android.Manifest.permission#READ_PHONE_STATE} permission.
+ * @return The serial if specified.
+ */
+ @RequiresPermission(Manifest.permission.READ_PHONE_STATE)
+ public static String getSerial() {
+ IDeviceIdentifiersPolicyService service = IDeviceIdentifiersPolicyService.Stub
+ .asInterface(ServiceManager.getService(Context.DEVICE_IDENTIFIERS_SERVICE));
+ try {
+ return service.getSerial();
+ } catch (RemoteException e) {
+ e.rethrowFromSystemServer();
+ }
+ return UNKNOWN;
+ }
/**
* An ordered list of ABIs supported by this device. The most preferred ABI is the first
diff --git a/core/java/android/os/HwParcel.java b/core/java/android/os/HwParcel.java
index e4d57184ede9..180e8f46e93b 100644
--- a/core/java/android/os/HwParcel.java
+++ b/core/java/android/os/HwParcel.java
@@ -53,21 +53,13 @@ public class HwParcel {
public native final void writeDouble(double val);
public native final void writeString(String val);
- public native final void writeBoolArray(int size, boolean[] val);
public native final void writeBoolVector(boolean[] val);
- public native final void writeInt8Array(int size, byte[] val);
public native final void writeInt8Vector(byte[] val);
- public native final void writeInt16Array(int size, short[] val);
public native final void writeInt16Vector(short[] val);
- public native final void writeInt32Array(int size, int[] val);
public native final void writeInt32Vector(int[] val);
- public native final void writeInt64Array(int size, long[] val);
public native final void writeInt64Vector(long[] val);
- public native final void writeFloatArray(int size, float[] val);
public native final void writeFloatVector(float[] val);
- public native final void writeDoubleArray(int size, double[] val);
public native final void writeDoubleVector(double[] val);
- public native final void writeStringArray(int size, String[] val);
public native final void writeStringVector(String[] val);
public native final void writeStrongBinder(IHwBinder binder);
@@ -82,21 +74,13 @@ public class HwParcel {
public native final double readDouble();
public native final String readString();
- public native final boolean[] readBoolArray(int size);
public native final boolean[] readBoolVector();
- public native final byte[] readInt8Array(int size);
public native final byte[] readInt8Vector();
- public native final short[] readInt16Array(int size);
public native final short[] readInt16Vector();
- public native final int[] readInt32Array(int size);
public native final int[] readInt32Vector();
- public native final long[] readInt64Array(int size);
public native final long[] readInt64Vector();
- public native final float[] readFloatArray(int size);
public native final float[] readFloatVector();
- public native final double[] readDoubleArray(int size);
public native final double[] readDoubleVector();
- public native final String[] readStringArray(int size);
public native final String[] readStringVector();
public native final IHwBinder readStrongBinder();
diff --git a/core/java/android/os/IDeviceIdentifiersPolicyService.aidl b/core/java/android/os/IDeviceIdentifiersPolicyService.aidl
new file mode 100644
index 000000000000..ac19f2bd5bbc
--- /dev/null
+++ b/core/java/android/os/IDeviceIdentifiersPolicyService.aidl
@@ -0,0 +1,24 @@
+/*
+ * 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.os;
+
+/**
+ * @hide
+ */
+interface IDeviceIdentifiersPolicyService {
+ String getSerial();
+} \ No newline at end of file
diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java
index ce7a1243fe7a..1aed9b322816 100644
--- a/core/java/android/os/PowerManager.java
+++ b/core/java/android/os/PowerManager.java
@@ -1358,5 +1358,34 @@ public final class PowerManager {
+ " held=" + mHeld + ", refCount=" + mCount + "}";
}
}
+
+ /**
+ * Wraps a Runnable such that this method immediately acquires the wake lock and then
+ * once the Runnable is done the wake lock is released.
+ *
+ * <p>Example:
+ *
+ * <pre>
+ * mHandler.post(mWakeLock.wrap(() -> {
+ * // do things on handler, lock is held while we're waiting for this
+ * // to get scheduled and until the runnable is done executing.
+ * });
+ * </pre>
+ *
+ * <p>Note: you must make sure that the Runnable eventually gets executed, otherwise you'll
+ * leak the wakelock!
+ *
+ * @hide
+ */
+ public Runnable wrap(Runnable r) {
+ acquire();
+ return () -> {
+ try {
+ r.run();
+ } finally {
+ release();
+ }
+ };
+ }
}
}
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index f8cf9ab7b307..12a76c5d4875 100755
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -5989,6 +5989,18 @@ public final class Settings {
public static final String DOZE_ENABLED = "doze_enabled";
/**
+ * Whether the device should pulse on pick up gesture.
+ * @hide
+ */
+ public static final String DOZE_PULSE_ON_PICK_UP = "doze_pulse_on_pick_up";
+
+ /**
+ * Whether the device should pulse on double tap gesture.
+ * @hide
+ */
+ public static final String DOZE_PULSE_ON_DOUBLE_TAP = "doze_pulse_on_double_tap";
+
+ /**
* The current night mode that has been selected by the user. Owned
* and controlled by UiModeManagerService. Constants are as per
* UiModeManager.
@@ -6517,6 +6529,9 @@ public final class Settings {
CAMERA_DOUBLE_TAP_POWER_GESTURE_DISABLED,
SYSTEM_NAVIGATION_KEYS_ENABLED,
QS_TILES,
+ DOZE_ENABLED,
+ DOZE_PULSE_ON_PICK_UP,
+ DOZE_PULSE_ON_DOUBLE_TAP
};
/**
@@ -7559,6 +7574,13 @@ public final class Settings {
/**
* Whether to automatically switch away from wifi networks that lose Internet access.
+ * Only meaningful if config_networkAvoidBadWifi is set to 0, otherwise the system always
+ * avoids such networks. Valid values are:
+ *
+ * 0: Don't avoid bad wifi, don't prompt the user. Get stuck on bad wifi like it's 2013.
+ * null: Ask the user whether to switch away from bad wifi.
+ * 1: Avoid bad wifi.
+ *
* @hide
*/
public static final String NETWORK_AVOID_BAD_WIFI = "network_avoid_bad_wifi";
diff --git a/core/java/android/service/dreams/DreamService.java b/core/java/android/service/dreams/DreamService.java
index 0557d138eb74..e958fbef563d 100644
--- a/core/java/android/service/dreams/DreamService.java
+++ b/core/java/android/service/dreams/DreamService.java
@@ -192,6 +192,9 @@ public class DreamService extends Service implements Window.Callback {
private boolean mDebug = false;
+ private PowerManager.WakeLock mWakeLock;
+ private boolean mWakeLockAcquired;
+
public DreamService() {
mSandman = IDreamManager.Stub.asInterface(ServiceManager.getService(DREAM_SERVICE));
}
@@ -786,6 +789,8 @@ public class DreamService extends Service implements Window.Callback {
public void onCreate() {
if (mDebug) Slog.v(TAG, "onCreate()");
super.onCreate();
+ mWakeLock = getSystemService(PowerManager.class)
+ .newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "DreamService");
}
/**
@@ -825,9 +830,21 @@ public class DreamService extends Service implements Window.Callback {
@Override
public final IBinder onBind(Intent intent) {
if (mDebug) Slog.v(TAG, "onBind() intent = " + intent);
+
+ // Need to stay awake until we dispatch onDreamingStarted. This is released either in
+ // attach() or onDestroy().
+ mWakeLock.acquire(5000);
+ mWakeLockAcquired = true;
return new DreamServiceWrapper();
}
+ private void releaseWakeLockIfNeeded() {
+ if (mWakeLockAcquired) {
+ mWakeLock.release();
+ mWakeLockAcquired = false;
+ }
+ }
+
/**
* Stops the dream and detaches from the window.
* <p>
@@ -904,6 +921,8 @@ public class DreamService extends Service implements Window.Callback {
detach();
super.onDestroy();
+
+ releaseWakeLockIfNeeded(); // for acquire in onBind()
}
// end public api
@@ -944,83 +963,88 @@ public class DreamService extends Service implements Window.Callback {
* @param windowToken A window token that will allow a window to be created in the correct layer.
*/
private final void attach(IBinder windowToken, boolean canDoze) {
- if (mWindowToken != null) {
- Slog.e(TAG, "attach() called when already attached with token=" + mWindowToken);
- return;
- }
- if (mFinished || mWaking) {
- Slog.w(TAG, "attach() called after dream already finished");
- try {
- mSandman.finishSelf(windowToken, true /*immediate*/);
- } catch (RemoteException ex) {
- // system server died
+ try {
+ if (mWindowToken != null) {
+ Slog.e(TAG, "attach() called when already attached with token=" + mWindowToken);
+ return;
+ }
+ if (mFinished || mWaking) {
+ Slog.w(TAG, "attach() called after dream already finished");
+ try {
+ mSandman.finishSelf(windowToken, true /*immediate*/);
+ } catch (RemoteException ex) {
+ // system server died
+ }
+ return;
}
- return;
- }
-
- mWindowToken = windowToken;
- mCanDoze = canDoze;
- if (mWindowless && !mCanDoze) {
- throw new IllegalStateException("Only doze dreams can be windowless");
- }
- if (!mWindowless) {
- mWindow = new PhoneWindow(this);
- mWindow.setCallback(this);
- mWindow.requestFeature(Window.FEATURE_NO_TITLE);
- mWindow.setBackgroundDrawable(new ColorDrawable(0xFF000000));
- mWindow.setFormat(PixelFormat.OPAQUE);
-
- if (mDebug) Slog.v(TAG, String.format("Attaching window token: %s to window of type %s",
- windowToken, WindowManager.LayoutParams.TYPE_DREAM));
- WindowManager.LayoutParams lp = mWindow.getAttributes();
- lp.type = WindowManager.LayoutParams.TYPE_DREAM;
- lp.token = windowToken;
- lp.windowAnimations = com.android.internal.R.style.Animation_Dream;
- lp.flags |= ( WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
- | WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR
- | WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED
- | WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD
- | WindowManager.LayoutParams.FLAG_ALLOW_LOCK_WHILE_SCREEN_ON
- | (mFullscreen ? WindowManager.LayoutParams.FLAG_FULLSCREEN : 0)
- | (mScreenBright ? WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON : 0)
- );
- mWindow.setAttributes(lp);
- // Workaround: Currently low-profile and in-window system bar backgrounds don't go
- // along well. Dreams usually don't need such bars anyways, so disable them by default.
- mWindow.clearFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
- mWindow.setWindowManager(null, windowToken, "dream", true);
+ mWindowToken = windowToken;
+ mCanDoze = canDoze;
+ if (mWindowless && !mCanDoze) {
+ throw new IllegalStateException("Only doze dreams can be windowless");
+ }
+ if (!mWindowless) {
+ mWindow = new PhoneWindow(this);
+ mWindow.setCallback(this);
+ mWindow.requestFeature(Window.FEATURE_NO_TITLE);
+ mWindow.setBackgroundDrawable(new ColorDrawable(0xFF000000));
+ mWindow.setFormat(PixelFormat.OPAQUE);
+
+ if (mDebug) {
+ Slog.v(TAG, String.format("Attaching window token: %s to window of type %s",
+ windowToken, WindowManager.LayoutParams.TYPE_DREAM));
+ }
- applySystemUiVisibilityFlags(
- (mLowProfile ? View.SYSTEM_UI_FLAG_LOW_PROFILE : 0),
- View.SYSTEM_UI_FLAG_LOW_PROFILE);
+ WindowManager.LayoutParams lp = mWindow.getAttributes();
+ lp.type = WindowManager.LayoutParams.TYPE_DREAM;
+ lp.token = windowToken;
+ lp.windowAnimations = com.android.internal.R.style.Animation_Dream;
+ lp.flags |= (WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
+ | WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR
+ | WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED
+ | WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD
+ | WindowManager.LayoutParams.FLAG_ALLOW_LOCK_WHILE_SCREEN_ON
+ | (mFullscreen ? WindowManager.LayoutParams.FLAG_FULLSCREEN : 0)
+ | (mScreenBright ? WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON : 0)
+ );
+ mWindow.setAttributes(lp);
+ // Workaround: Currently low-profile and in-window system bar backgrounds don't go
+ // along well. Dreams usually don't need such bars anyways, so disable them by default.
+ mWindow.clearFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
+ mWindow.setWindowManager(null, windowToken, "dream", true);
+
+ applySystemUiVisibilityFlags(
+ (mLowProfile ? View.SYSTEM_UI_FLAG_LOW_PROFILE : 0),
+ View.SYSTEM_UI_FLAG_LOW_PROFILE);
- try {
- getWindowManager().addView(mWindow.getDecorView(), mWindow.getAttributes());
- } catch (WindowManager.BadTokenException ex) {
- // This can happen because the dream manager service will remove the token
- // immediately without necessarily waiting for the dream to start.
- // We should receive a finish message soon.
- Slog.i(TAG, "attach() called after window token already removed, dream will "
- + "finish soon");
- mWindow = null;
- return;
+ try {
+ getWindowManager().addView(mWindow.getDecorView(), mWindow.getAttributes());
+ } catch (WindowManager.BadTokenException ex) {
+ // This can happen because the dream manager service will remove the token
+ // immediately without necessarily waiting for the dream to start.
+ // We should receive a finish message soon.
+ Slog.i(TAG, "attach() called after window token already removed, dream will "
+ + "finish soon");
+ mWindow = null;
+ return;
+ }
}
- }
- // We need to defer calling onDreamingStarted until after onWindowAttached,
- // which is posted to the handler by addView, so we post onDreamingStarted
- // to the handler also. Need to watch out here in case detach occurs before
- // this callback is invoked.
- mHandler.post(new Runnable() {
- @Override
- public void run() {
+ // We need to defer calling onDreamingStarted until after onWindowAttached,
+ // which is posted to the handler by addView, so we post onDreamingStarted
+ // to the handler also. Need to watch out here in case detach occurs before
+ // this callback is invoked.
+ mHandler.post(mWakeLock.wrap(() -> {
if (mWindow != null || mWindowless) {
- if (mDebug) Slog.v(TAG, "Calling onDreamingStarted()");
+ if (mDebug) {
+ Slog.v(TAG, "Calling onDreamingStarted()");
+ }
mStarted = true;
onDreamingStarted();
}
- }
- });
+ }));
+ } finally {
+ releaseWakeLockIfNeeded(); // for acquire in onBind
+ }
}
private boolean getWindowFlagValue(int flag, boolean defaultValue) {
diff --git a/core/java/android/transition/TransitionManager.java b/core/java/android/transition/TransitionManager.java
index 16f3bc050a89..479f49368191 100644
--- a/core/java/android/transition/TransitionManager.java
+++ b/core/java/android/transition/TransitionManager.java
@@ -185,25 +185,25 @@ public class TransitionManager {
final ViewGroup sceneRoot = scene.getSceneRoot();
if (!sPendingTransitions.contains(sceneRoot)) {
- sPendingTransitions.add(sceneRoot);
+ if (transition == null) {
+ scene.enter();
+ } else {
+ sPendingTransitions.add(sceneRoot);
- Transition transitionClone = null;
- if (transition != null) {
- transitionClone = transition.clone();
+ Transition transitionClone = transition.clone();
transitionClone.setSceneRoot(sceneRoot);
- }
- Scene oldScene = Scene.getCurrentScene(sceneRoot);
- if (oldScene != null && transitionClone != null &&
- oldScene.isCreatedFromLayoutResource()) {
- transitionClone.setCanRemoveViews(true);
- }
+ Scene oldScene = Scene.getCurrentScene(sceneRoot);
+ if (oldScene != null && oldScene.isCreatedFromLayoutResource()) {
+ transitionClone.setCanRemoveViews(true);
+ }
- sceneChangeSetup(sceneRoot, transitionClone);
+ sceneChangeSetup(sceneRoot, transitionClone);
- scene.enter();
+ scene.enter();
- sceneChangeRunTransition(sceneRoot, transitionClone);
+ sceneChangeRunTransition(sceneRoot, transitionClone);
+ }
}
}
diff --git a/core/java/android/util/PackageUtils.java b/core/java/android/util/PackageUtils.java
new file mode 100644
index 000000000000..6531aef9a50c
--- /dev/null
+++ b/core/java/android/util/PackageUtils.java
@@ -0,0 +1,96 @@
+/*
+ * 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.util;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.Signature;
+
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+
+/**
+ * Helper functions applicable to packages.
+ * @hide
+ */
+public final class PackageUtils {
+ private final static char[] HEX_ARRAY = "0123456789ABCDEF".toCharArray();
+
+ private PackageUtils() {
+ /* hide constructor */
+ }
+
+ /**
+ * Computes the SHA256 digest of the signing cert for a package.
+ * @param packageManager The package manager.
+ * @param packageName The package for which to generate the digest.
+ * @param userId The user for which to generate the digest.
+ * @return The digest or null if the package does not exist for this user.
+ */
+ public static @Nullable String computePackageCertSha256Digest(
+ @NonNull PackageManager packageManager,
+ @NonNull String packageName, int userId) {
+ final PackageInfo packageInfo;
+ try {
+ packageInfo = packageManager.getPackageInfoAsUser(packageName,
+ PackageManager.GET_SIGNATURES, userId);
+ } catch (PackageManager.NameNotFoundException e) {
+ return null;
+ }
+ return computeCertSha256Digest(packageInfo.signatures[0]);
+ }
+
+ /**
+ * Computes the SHA256 digest of a cert.
+ * @param signature The signature.
+ * @return The digest or null if an error occurs.
+ */
+ public static @Nullable String computeCertSha256Digest(@NonNull Signature signature) {
+ return computeSha256Digest(signature.toByteArray());
+ }
+
+ /**
+ * Computes the SHA256 digest of some data.
+ * @param data The data.
+ * @return The digest or null if an error occurs.
+ */
+ public static @Nullable String computeSha256Digest(@NonNull byte[] data) {
+ MessageDigest messageDigest;
+ try {
+ messageDigest = MessageDigest.getInstance("SHA256");
+ } catch (NoSuchAlgorithmException e) {
+ /* can't happen */
+ return null;
+ }
+
+ messageDigest.update(data);
+
+ final byte[] digest = messageDigest.digest();
+ final int digestLength = digest.length;
+ final int charCount = 2 * digestLength;
+
+ final char[] chars = new char[charCount];
+ for (int i = 0; i < digestLength; i++) {
+ final int byteHex = digest[i] & 0xFF;
+ chars[i * 2] = HEX_ARRAY[byteHex >>> 4];
+ chars[i * 2 + 1] = HEX_ARRAY[byteHex & 0x0F];
+ }
+ return new String(chars);
+ }
+}
diff --git a/core/java/android/view/DragEvent.java b/core/java/android/view/DragEvent.java
index a394f351b7f3..691a385be9da 100644
--- a/core/java/android/view/DragEvent.java
+++ b/core/java/android/view/DragEvent.java
@@ -134,6 +134,7 @@ public class DragEvent implements Parcelable {
Object mLocalState;
boolean mDragResult;
+ boolean mEventHandlerWasCalled;
private DragEvent mNext;
private RuntimeException mRecycledLocation;
@@ -439,6 +440,7 @@ public class DragEvent implements Parcelable {
mClipData = null;
mClipDescription = null;
mLocalState = null;
+ mEventHandlerWasCalled = false;
synchronized (gRecyclerLock) {
if (gRecyclerUsed < MAX_RECYCLED) {
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index c16339380294..897e29b3f1e5 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -356,6 +356,16 @@ interface IWindowManager
oneway void statusBarVisibilityChanged(int visibility);
/**
+ * Called by System UI to notify of changes to the visibility of Recents.
+ */
+ oneway void setRecentsVisibility(boolean visible);
+
+ /**
+ * Called by System UI to notify of changes to the visibility of PIP.
+ */
+ oneway void setTvPipVisibility(boolean visible);
+
+ /**
* Device has a software navigation bar (separate from the status bar).
*/
boolean hasNavigationBar();
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index a7337d2581ca..d0708237e304 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -40,7 +40,6 @@ import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.Canvas;
-import android.graphics.Color;
import android.graphics.Insets;
import android.graphics.Interpolator;
import android.graphics.LinearGradient;
@@ -831,6 +830,17 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
protected static boolean sPreserveMarginParamsInLayoutParamConversion;
/**
+ * Prior to N, when drag enters into child of a view that has already received an
+ * ACTION_DRAG_ENTERED event, the parent doesn't get a ACTION_DRAG_EXITED event.
+ * ACTION_DRAG_LOCATION and ACTION_DROP were delivered to the parent of a view that returned
+ * false from its event handler for these events.
+ * Starting from N, the parent will get ACTION_DRAG_EXITED event before the child gets its
+ * ACTION_DRAG_ENTERED. ACTION_DRAG_LOCATION and ACTION_DROP are never propagated to the parent.
+ * sCascadedDragDrop is true for pre-N apps for backwards compatibility implementation.
+ */
+ static boolean sCascadedDragDrop;
+
+ /**
* This view does not want keystrokes. Use with TAKES_FOCUS_MASK when
* calling setFlags.
*/
@@ -3088,20 +3098,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
/**
* @hide
*
- * Whether Recents is visible or not.
- */
- public static final int RECENT_APPS_VISIBLE = 0x00004000;
-
- /**
- * @hide
- *
- * Whether the TV's picture-in-picture is visible or not.
- */
- public static final int TV_PICTURE_IN_PICTURE_VISIBLE = 0x00010000;
-
- /**
- * @hide
- *
* Makes navigation bar transparent (but not the status bar).
*/
public static final int NAVIGATION_BAR_TRANSPARENT = 0x00008000;
@@ -4068,6 +4064,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
// in apps so we target check it to avoid breaking existing apps.
sPreserveMarginParamsInLayoutParamConversion = targetSdkVersion >= N;
+ sCascadedDragDrop = targetSdkVersion < N;
+
sCompatibilityDone = true;
}
}
@@ -20864,6 +20862,11 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
return false;
}
+ // Dispatches ACTION_DRAG_ENTERED and ACTION_DRAG_EXITED events for pre-Nougat apps.
+ boolean dispatchDragEnterExitInPreN(DragEvent event) {
+ return callDragEventHandler(event);
+ }
+
/**
* Detects if this View is enabled and has a drag event listener.
* If both are true, then it calls the drag event listener with the
@@ -20881,13 +20884,44 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* </p>
*/
public boolean dispatchDragEvent(DragEvent event) {
+ event.mEventHandlerWasCalled = true;
+ if (event.mAction == DragEvent.ACTION_DRAG_LOCATION ||
+ event.mAction == DragEvent.ACTION_DROP) {
+ // About to deliver an event with coordinates to this view. Notify that now this view
+ // has drag focus. This will send exit/enter events as needed.
+ getViewRootImpl().setDragFocus(this, event);
+ }
+ return callDragEventHandler(event);
+ }
+
+ final boolean callDragEventHandler(DragEvent event) {
+ final boolean result;
+
ListenerInfo li = mListenerInfo;
//noinspection SimplifiableIfStatement
if (li != null && li.mOnDragListener != null && (mViewFlags & ENABLED_MASK) == ENABLED
&& li.mOnDragListener.onDrag(this, event)) {
- return true;
+ result = true;
+ } else {
+ result = onDragEvent(event);
}
- return onDragEvent(event);
+
+ switch (event.mAction) {
+ case DragEvent.ACTION_DRAG_ENTERED: {
+ mPrivateFlags2 |= View.PFLAG2_DRAG_HOVERED;
+ refreshDrawableState();
+ } break;
+ case DragEvent.ACTION_DRAG_EXITED: {
+ mPrivateFlags2 &= ~View.PFLAG2_DRAG_HOVERED;
+ refreshDrawableState();
+ } break;
+ case DragEvent.ACTION_DRAG_ENDED: {
+ mPrivateFlags2 &= ~View.DRAG_MASK;
+ refreshDrawableState();
+ } break;
+ }
+
+ return result;
}
boolean canAcceptDrag() {
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index 030fff10d7e1..1b3f6ffe2b64 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -154,8 +154,9 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
*/
Transformation mInvalidationTransformation;
- // View currently under an ongoing drag. Can be null, a child or this window.
- private View mCurrentDragView;
+ // Current frontmost child that can accept drag and lies under the drag location.
+ // Used only to generate ENTER/EXIT events for pre-Nougat aps.
+ private View mCurrentDragChild;
// Metadata about the ongoing drag
private DragEvent mCurrentDragStartEvent;
@@ -1359,6 +1360,20 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
return mLocalPoint;
}
+ @Override
+ boolean dispatchDragEnterExitInPreN(DragEvent event) {
+ if (event.mAction == DragEvent.ACTION_DRAG_EXITED && mCurrentDragChild != null) {
+ // The drag exited a sub-tree of views; notify of the exit all descendants that are in
+ // entered state.
+ // We don't need this recursive delivery for ENTERED events because they get generated
+ // from the recursive delivery of LOCATION/DROP events, and hence, don't need their own
+ // recursion.
+ mCurrentDragChild.dispatchDragEnterExitInPreN(event);
+ mCurrentDragChild = null;
+ }
+ return mIsInterestedInDrag && super.dispatchDragEnterExitInPreN(event);
+ }
+
// TODO: Write real docs
@Override
public boolean dispatchDragEvent(DragEvent event) {
@@ -1366,15 +1381,13 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
final float tx = event.mX;
final float ty = event.mY;
- ViewRootImpl root = getViewRootImpl();
-
// Dispatch down the view hierarchy
final PointF localPoint = getLocalPoint();
switch (event.mAction) {
case DragEvent.ACTION_DRAG_STARTED: {
- // clear state to recalculate which views we drag over
- mCurrentDragView = null;
+ // Clear the state to recalculate which views we drag over.
+ mCurrentDragChild = null;
// Set up our tracking of drag-started notifications
mCurrentDragStartEvent = DragEvent.obtain(event);
@@ -1420,8 +1433,6 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
if (child.dispatchDragEvent(event)) {
retval = true;
}
- child.mPrivateFlags2 &= ~View.DRAG_MASK;
- child.refreshDrawableState();
}
childrenInterestedInDrag.clear();
}
@@ -1438,60 +1449,45 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
}
} break;
- case DragEvent.ACTION_DRAG_LOCATION: {
+ case DragEvent.ACTION_DRAG_LOCATION:
+ case DragEvent.ACTION_DROP: {
// Find the [possibly new] drag target
View target = findFrontmostDroppableChildAt(event.mX, event.mY, localPoint);
- if (target == null && mIsInterestedInDrag) {
- target = this;
- }
- // If we've changed apparent drag target, tell the view root which view
- // we're over now [for purposes of the eventual drag-recipient-changed
- // notifications to the framework] and tell the new target that the drag
- // has entered its bounds. The root will see setDragFocus() calls all
- // the way down to the final leaf view that is handling the LOCATION event
- // before reporting the new potential recipient to the framework.
- if (mCurrentDragView != target) {
- root.setDragFocus(target);
-
- final int action = event.mAction;
- // Position should not be available for ACTION_DRAG_ENTERED and ACTION_DRAG_EXITED.
- event.mX = 0;
- event.mY = 0;
-
- // If we've dragged off of a child view or this window, send it the EXITED message
- if (mCurrentDragView != null) {
- final View view = mCurrentDragView;
- event.mAction = DragEvent.ACTION_DRAG_EXITED;
- if (view != this) {
- view.dispatchDragEvent(event);
- view.mPrivateFlags2 &= ~View.PFLAG2_DRAG_HOVERED;
- view.refreshDrawableState();
- } else {
- super.dispatchDragEvent(event);
+ if (target != mCurrentDragChild) {
+ if (sCascadedDragDrop) {
+ // For pre-Nougat apps, make sure that the whole hierarchy of views that contain
+ // the drag location is kept in the state between ENTERED and EXITED events.
+ // (Starting with N, only the innermost view will be in that state).
+
+ final int action = event.mAction;
+ // Position should not be available for ACTION_DRAG_ENTERED and
+ // ACTION_DRAG_EXITED.
+ event.mX = 0;
+ event.mY = 0;
+
+ if (mCurrentDragChild != null) {
+ event.mAction = DragEvent.ACTION_DRAG_EXITED;
+ mCurrentDragChild.dispatchDragEnterExitInPreN(event);
}
- }
-
- mCurrentDragView = target;
- // If we've dragged over a new child view, send it the ENTERED message, otherwise
- // send it to this window.
- if (target != null) {
- event.mAction = DragEvent.ACTION_DRAG_ENTERED;
- if (target != this) {
- target.dispatchDragEvent(event);
- target.mPrivateFlags2 |= View.PFLAG2_DRAG_HOVERED;
- target.refreshDrawableState();
- } else {
- super.dispatchDragEvent(event);
+ if (target != null) {
+ event.mAction = DragEvent.ACTION_DRAG_ENTERED;
+ target.dispatchDragEnterExitInPreN(event);
}
+
+ event.mAction = action;
+ event.mX = tx;
+ event.mY = ty;
}
- event.mAction = action; // restore the event's original state
- event.mX = tx;
- event.mY = ty;
+ mCurrentDragChild = target;
}
- // Dispatch the actual drag location notice, localized into its coordinates
+ if (target == null && mIsInterestedInDrag) {
+ target = this;
+ }
+
+ // Dispatch the actual drag notice, localized into the target coordinates.
if (target != null) {
if (target != this) {
event.mX = localPoint.x;
@@ -1501,55 +1497,21 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
event.mX = tx;
event.mY = ty;
- } else {
- retval = super.dispatchDragEvent(event);
- }
- }
- } break;
- /* Entered / exited dispatch
- *
- * DRAG_ENTERED is not dispatched downwards from ViewGroup. The reason for this is
- * that we're about to get the corresponding LOCATION event, which we will use to
- * determine which of our children is the new target; at that point we will
- * push a DRAG_ENTERED down to the new target child [which may itself be a ViewGroup].
- * If no suitable child is detected, dispatch to this window.
- *
- * DRAG_EXITED *is* dispatched all the way down immediately: once we know the
- * drag has left this ViewGroup, we know by definition that every contained subview
- * is also no longer under the drag point.
- */
+ if (mIsInterestedInDrag) {
+ final boolean eventWasConsumed;
+ if (sCascadedDragDrop) {
+ eventWasConsumed = retval;
+ } else {
+ eventWasConsumed = event.mEventHandlerWasCalled;
+ }
- case DragEvent.ACTION_DRAG_EXITED: {
- if (mCurrentDragView != null) {
- final View view = mCurrentDragView;
- if (view != this) {
- view.dispatchDragEvent(event);
- view.mPrivateFlags2 &= ~View.PFLAG2_DRAG_HOVERED;
- view.refreshDrawableState();
+ if (!eventWasConsumed) {
+ retval = super.dispatchDragEvent(event);
+ }
+ }
} else {
- super.dispatchDragEvent(event);
- }
-
- mCurrentDragView = null;
- }
- } break;
-
- case DragEvent.ACTION_DROP: {
- if (ViewDebug.DEBUG_DRAG) Log.d(View.VIEW_LOG_TAG, "Drop event: " + event);
- View target = findFrontmostDroppableChildAt(event.mX, event.mY, localPoint);
- if (target != null) {
- if (ViewDebug.DEBUG_DRAG) Log.d(View.VIEW_LOG_TAG, " dispatch drop to " + target);
- event.mX = localPoint.x;
- event.mY = localPoint.y;
- retval = target.dispatchDragEvent(event);
- event.mX = tx;
- event.mY = ty;
- } else if (mIsInterestedInDrag) {
- retval = super.dispatchDragEvent(event);
- } else {
- if (ViewDebug.DEBUG_DRAG) {
- Log.d(View.VIEW_LOG_TAG, " not dropped on an accepting view");
+ retval = super.dispatchDragEvent(event);
}
}
} break;
@@ -1596,6 +1558,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
final boolean canAccept = child.dispatchDragEvent(mCurrentDragStartEvent);
mCurrentDragStartEvent.mX = tx;
mCurrentDragStartEvent.mY = ty;
+ mCurrentDragStartEvent.mEventHandlerWasCalled = false;
if (canAccept) {
mChildrenInterestedInDrag.add(child);
if (!child.canAcceptDrag()) {
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 3bbf75e8e856..ec29abfe4253 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -5527,9 +5527,11 @@ public final class ViewRootImpl implements ViewParent,
if (what == DragEvent.ACTION_DRAG_EXITED) {
// A direct EXITED event means that the window manager knows we've just crossed
// a window boundary, so the current drag target within this one must have
- // just been exited. Send it the usual notifications and then we're done
- // for now.
- mView.dispatchDragEvent(event);
+ // just been exited. Send the EXITED notification to the current drag view, if any.
+ if (View.sCascadedDragDrop) {
+ mView.dispatchDragEnterExitInPreN(event);
+ }
+ setDragFocus(null, event);
} else {
// For events with a [screen] location, translate into window coordinates
if ((what == DragEvent.ACTION_DRAG_LOCATION) || (what == DragEvent.ACTION_DROP)) {
@@ -5556,6 +5558,12 @@ public final class ViewRootImpl implements ViewParent,
// Now dispatch the drag/drop event
boolean result = mView.dispatchDragEvent(event);
+ if (what == DragEvent.ACTION_DRAG_LOCATION && !event.mEventHandlerWasCalled) {
+ // If the LOCATION event wasn't delivered to any handler, no view now has a drag
+ // focus.
+ setDragFocus(null, event);
+ }
+
// If we changed apparent drag target, tell the OS about it
if (prevDragView != mCurrentDragView) {
try {
@@ -5582,6 +5590,7 @@ public final class ViewRootImpl implements ViewParent,
// When the drag operation ends, reset drag-related state
if (what == DragEvent.ACTION_DRAG_ENDED) {
+ mCurrentDragView = null;
setLocalDragState(null);
mAttachInfo.mDragToken = null;
if (mAttachInfo.mDragSurface != null) {
@@ -5641,10 +5650,33 @@ public final class ViewRootImpl implements ViewParent,
return mLastTouchSource;
}
- public void setDragFocus(View newDragTarget) {
- if (mCurrentDragView != newDragTarget) {
- mCurrentDragView = newDragTarget;
+ public void setDragFocus(View newDragTarget, DragEvent event) {
+ if (mCurrentDragView != newDragTarget && !View.sCascadedDragDrop) {
+ // Send EXITED and ENTERED notifications to the old and new drag focus views.
+
+ final float tx = event.mX;
+ final float ty = event.mY;
+ final int action = event.mAction;
+ // Position should not be available for ACTION_DRAG_ENTERED and ACTION_DRAG_EXITED.
+ event.mX = 0;
+ event.mY = 0;
+
+ if (mCurrentDragView != null) {
+ event.mAction = DragEvent.ACTION_DRAG_EXITED;
+ mCurrentDragView.callDragEventHandler(event);
+ }
+
+ if (newDragTarget != null) {
+ event.mAction = DragEvent.ACTION_DRAG_ENTERED;
+ newDragTarget.callDragEventHandler(event);
+ }
+
+ event.mAction = action;
+ event.mX = tx;
+ event.mY = ty;
}
+
+ mCurrentDragView = newDragTarget;
}
private AudioManager getAudioManager() {
diff --git a/core/java/android/view/WindowManagerPolicy.java b/core/java/android/view/WindowManagerPolicy.java
index 2a524ec489e0..da361c1c04d2 100644
--- a/core/java/android/view/WindowManagerPolicy.java
+++ b/core/java/android/view/WindowManagerPolicy.java
@@ -1311,6 +1311,16 @@ public interface WindowManagerPolicy {
public int adjustSystemUiVisibilityLw(int visibility);
/**
+ * Called by System UI to notify of changes to the visibility of Recents.
+ */
+ public void setRecentsVisibilityLw(boolean visible);
+
+ /**
+ * Called by System UI to notify of changes to the visibility of PIP.
+ */
+ public void setTvPipVisibilityLw(boolean visible);
+
+ /**
* Specifies whether there is an on-screen navigation bar separate from the status bar.
*/
public boolean hasNavigationBar();
diff --git a/core/java/com/android/server/backup/AccountManagerBackupHelper.java b/core/java/com/android/server/backup/AccountManagerBackupHelper.java
new file mode 100644
index 000000000000..39b18c0f2c16
--- /dev/null
+++ b/core/java/com/android/server/backup/AccountManagerBackupHelper.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.backup;
+
+import android.accounts.AccountManagerInternal;
+import android.app.backup.BlobBackupHelper;
+import android.os.UserHandle;
+import android.util.Slog;
+import com.android.server.LocalServices;
+
+/**
+ * Helper for handling backup of account manager specific state.
+ */
+public class AccountManagerBackupHelper extends BlobBackupHelper {
+ private static final String TAG = "AccountsBackup";
+ private static final boolean DEBUG = false;
+
+ // current schema of the backup state blob
+ private static final int STATE_VERSION = 1;
+
+ // key under which the account access grant state blob is committed to backup
+ private static final String KEY_ACCOUNT_ACCESS_GRANTS = "account_access_grants";
+
+ public AccountManagerBackupHelper() {
+ super(STATE_VERSION, KEY_ACCOUNT_ACCESS_GRANTS);
+ }
+
+ @Override
+ protected byte[] getBackupPayload(String key) {
+ AccountManagerInternal am = LocalServices.getService(AccountManagerInternal.class);
+ if (DEBUG) {
+ Slog.d(TAG, "Handling backup of " + key);
+ }
+ try {
+ switch (key) {
+ case KEY_ACCOUNT_ACCESS_GRANTS: {
+ return am.backupAccountAccessPermissions(UserHandle.USER_SYSTEM);
+ }
+
+ default: {
+ Slog.w(TAG, "Unexpected backup key " + key);
+ }
+ }
+ } catch (Exception e) {
+ Slog.e(TAG, "Unable to store payload " + key);
+ }
+
+ return new byte[0];
+ }
+
+ @Override
+ protected void applyRestoredPayload(String key, byte[] payload) {
+ AccountManagerInternal am = LocalServices.getService(AccountManagerInternal.class);
+ if (DEBUG) {
+ Slog.d(TAG, "Handling restore of " + key);
+ }
+ try {
+ switch (key) {
+ case KEY_ACCOUNT_ACCESS_GRANTS: {
+ am.restoreAccountAccessPermissions(payload, UserHandle.USER_SYSTEM);
+ } break;
+
+ default: {
+ Slog.w(TAG, "Unexpected restore key " + key);
+ }
+ }
+ } catch (Exception e) {
+ Slog.w(TAG, "Unable to restore key " + key);
+ }
+ }
+}
diff --git a/core/java/com/android/server/backup/SystemBackupAgent.java b/core/java/com/android/server/backup/SystemBackupAgent.java
index 9d296fa19400..537565185d9b 100644
--- a/core/java/com/android/server/backup/SystemBackupAgent.java
+++ b/core/java/com/android/server/backup/SystemBackupAgent.java
@@ -49,6 +49,7 @@ public class SystemBackupAgent extends BackupAgentHelper {
private static final String PERMISSION_HELPER = "permissions";
private static final String USAGE_STATS_HELPER = "usage_stats";
private static final String SHORTCUT_MANAGER_HELPER = "shortcut_manager";
+ private static final String ACCOUNT_MANAGER_HELPER = "account_manager";
// These paths must match what the WallpaperManagerService uses. The leaf *_FILENAME
// are also used in the full-backup file format, so must not change unless steps are
@@ -82,6 +83,7 @@ public class SystemBackupAgent extends BackupAgentHelper {
addHelper(PERMISSION_HELPER, new PermissionBackupHelper());
addHelper(USAGE_STATS_HELPER, new UsageStatsBackupHelper(this));
addHelper(SHORTCUT_MANAGER_HELPER, new ShortcutBackupHelper());
+ addHelper(ACCOUNT_MANAGER_HELPER, new AccountManagerBackupHelper());
super.onBackup(oldState, data, newState);
}
@@ -111,6 +113,7 @@ public class SystemBackupAgent extends BackupAgentHelper {
addHelper(PERMISSION_HELPER, new PermissionBackupHelper());
addHelper(USAGE_STATS_HELPER, new UsageStatsBackupHelper(this));
addHelper(SHORTCUT_MANAGER_HELPER, new ShortcutBackupHelper());
+ addHelper(ACCOUNT_MANAGER_HELPER, new AccountManagerBackupHelper());
try {
super.onRestore(data, appVersionCode, newState);
diff --git a/core/jni/android/graphics/Shader.cpp b/core/jni/android/graphics/Shader.cpp
index 9781ae11daec..03462a6d402e 100644
--- a/core/jni/android/graphics/Shader.cpp
+++ b/core/jni/android/graphics/Shader.cpp
@@ -1,5 +1,6 @@
#include "GraphicsJNI.h"
#include "SkGradientShader.h"
+#include "SkImagePriv.h"
#include "SkShader.h"
#include "SkXfermode.h"
#include "core_jni_helpers.h"
@@ -94,12 +95,15 @@ static jlong BitmapShader_constructor(JNIEnv* env, jobject o, jobject jbitmap,
// we'll pass an empty SkBitmap to avoid crashing/excepting for compatibility.
GraphicsJNI::getSkBitmap(env, jbitmap, &bitmap);
}
- SkShader* s = SkShader::CreateBitmapShader(bitmap,
- (SkShader::TileMode)tileModeX,
- (SkShader::TileMode)tileModeY);
-
- ThrowIAE_IfNull(env, s);
- return reinterpret_cast<jlong>(s);
+ sk_sp<SkShader> s = SkMakeBitmapShader(bitmap,
+ (SkShader::TileMode)tileModeX,
+ (SkShader::TileMode)tileModeY,
+ nullptr,
+ kNever_SkCopyPixelsMode,
+ nullptr);
+
+ ThrowIAE_IfNull(env, s.get());
+ return reinterpret_cast<jlong>(s.release());
}
///////////////////////////////////////////////////////////////////////////////////////////////
diff --git a/core/jni/android_os_HwParcel.cpp b/core/jni/android_os_HwParcel.cpp
index d453b29c0663..5c879b8894a1 100644
--- a/core/jni/android_os_HwParcel.cpp
+++ b/core/jni/android_os_HwParcel.cpp
@@ -431,35 +431,6 @@ static void JHwParcel_native_writeString(
signalExceptionForError(env, err);
}
-#define DEFINE_PARCEL_ARRAY_WRITER(Suffix,Type) \
-static void JHwParcel_native_write ## Suffix ## Array( \
- JNIEnv *env, jobject thiz, jint size, Type ## Array valObj) { \
- if (valObj == NULL) { \
- jniThrowException(env, "java/lang/NullPointerException", NULL); \
- return; \
- } \
- \
- jsize len = env->GetArrayLength(valObj); \
- \
- if (len != size) { \
- jniThrowException(env, "java/lang/IllegalArgumentException", NULL); \
- return; \
- } \
- \
- sp<JHwParcel> impl = JHwParcel::GetNativeContext(env, thiz); \
- \
- const Type *val = \
- impl->getStorage()->allocTemporary ## Suffix ## Array(env, valObj); \
- \
- hardware::Parcel *parcel = impl->getParcel(); \
- \
- size_t parentHandle; \
- status_t err = parcel->writeBuffer( \
- val, size * sizeof(*val), &parentHandle); \
- \
- signalExceptionForError(env, err); \
-}
-
#define DEFINE_PARCEL_VECTOR_WRITER(Suffix,Type) \
static void JHwParcel_native_write ## Suffix ## Vector( \
JNIEnv *env, jobject thiz, Type ## Array valObj) { \
@@ -491,13 +462,6 @@ static void JHwParcel_native_write ## Suffix ## Vector( \
signalExceptionForError(env, err); \
}
-DEFINE_PARCEL_ARRAY_WRITER(Int8,jbyte)
-DEFINE_PARCEL_ARRAY_WRITER(Int16,jshort)
-DEFINE_PARCEL_ARRAY_WRITER(Int32,jint)
-DEFINE_PARCEL_ARRAY_WRITER(Int64,jlong)
-DEFINE_PARCEL_ARRAY_WRITER(Float,jfloat)
-DEFINE_PARCEL_ARRAY_WRITER(Double,jdouble)
-
DEFINE_PARCEL_VECTOR_WRITER(Int8,jbyte)
DEFINE_PARCEL_VECTOR_WRITER(Int16,jshort)
DEFINE_PARCEL_VECTOR_WRITER(Int32,jint)
@@ -505,43 +469,6 @@ DEFINE_PARCEL_VECTOR_WRITER(Int64,jlong)
DEFINE_PARCEL_VECTOR_WRITER(Float,jfloat)
DEFINE_PARCEL_VECTOR_WRITER(Double,jdouble)
-static void JHwParcel_native_writeBoolArray(
- JNIEnv *env, jobject thiz, jint size, jbooleanArray valObj) {
- if (valObj == NULL) {
- jniThrowException(env, "java/lang/NullPointerException", NULL);
- return;
- }
-
- jsize len = env->GetArrayLength(valObj);
-
- if (len != size) {
- jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
- return;
- }
-
- sp<JHwParcel> impl = JHwParcel::GetNativeContext(env, thiz);
-
- jboolean *src = env->GetBooleanArrayElements(valObj, nullptr);
-
- bool *dst =
- (bool *)impl->getStorage()->allocTemporaryStorage(size * sizeof(bool));
-
- for (jint i = 0; i < size; ++i) {
- dst[i] = src[i];
- }
-
- env->ReleaseBooleanArrayElements(valObj, src, 0 /* mode */);
- src = nullptr;
-
- hardware::Parcel *parcel = impl->getParcel();
-
- size_t parentHandle;
- status_t err = parcel->writeBuffer(
- dst, size * sizeof(*dst), &parentHandle);
-
- signalExceptionForError(env, err);
-}
-
static void JHwParcel_native_writeBoolVector(
JNIEnv *env, jobject thiz, jbooleanArray valObj) {
if (valObj == NULL) {
@@ -651,22 +578,6 @@ static jstring JHwParcel_native_readString(JNIEnv *env, jobject thiz) {
return MakeStringObjFromHidlString(env, *s);
}
-#define DEFINE_PARCEL_ARRAY_READER(Suffix,Type,NewType) \
-static Type ## Array JHwParcel_native_read ## Suffix ## Array( \
- JNIEnv *env, jobject thiz, jint size) { \
- hardware::Parcel *parcel = \
- JHwParcel::GetNativeContext(env, thiz)->getParcel(); \
- \
- size_t parentHandle; \
- const Type *val = static_cast<const Type *>( \
- parcel->readBuffer(&parentHandle)); \
- \
- Type ## Array valObj = env->New ## NewType ## Array(size); \
- env->Set ## NewType ## ArrayRegion(valObj, 0, size, val); \
- \
- return valObj; \
-}
-
#define DEFINE_PARCEL_VECTOR_READER(Suffix,Type,NewType) \
static Type ## Array JHwParcel_native_read ## Suffix ## Vector( \
JNIEnv *env, jobject thiz) { \
@@ -703,13 +614,6 @@ static Type ## Array JHwParcel_native_read ## Suffix ## Vector( \
return valObj; \
}
-DEFINE_PARCEL_ARRAY_READER(Int8,jbyte,Byte)
-DEFINE_PARCEL_ARRAY_READER(Int16,jshort,Short)
-DEFINE_PARCEL_ARRAY_READER(Int32,jint,Int)
-DEFINE_PARCEL_ARRAY_READER(Int64,jlong,Long)
-DEFINE_PARCEL_ARRAY_READER(Float,jfloat,Float)
-DEFINE_PARCEL_ARRAY_READER(Double,jdouble,Double)
-
DEFINE_PARCEL_VECTOR_READER(Int8,jbyte,Byte)
DEFINE_PARCEL_VECTOR_READER(Int16,jshort,Short)
DEFINE_PARCEL_VECTOR_READER(Int32,jint,Int)
@@ -717,25 +621,6 @@ DEFINE_PARCEL_VECTOR_READER(Int64,jlong,Long)
DEFINE_PARCEL_VECTOR_READER(Float,jfloat,Float)
DEFINE_PARCEL_VECTOR_READER(Double,jdouble,Double)
-static jbooleanArray JHwParcel_native_readBoolArray(
- JNIEnv *env, jobject thiz, jint size) {
- hardware::Parcel *parcel =
- JHwParcel::GetNativeContext(env, thiz)->getParcel();
-
- size_t parentHandle;
- const bool *val = static_cast<const bool *>(
- parcel->readBuffer(&parentHandle));
-
- jbooleanArray valObj = env->NewBooleanArray(size);
-
- for (jint i = 0; i < size; ++i) {
- jboolean x = val[i];
- env->SetBooleanArrayRegion(valObj, i, 1, &x);
- }
-
- return valObj;
-}
-
static jbooleanArray JHwParcel_native_readBoolVector(
JNIEnv *env, jobject thiz) {
hardware::Parcel *parcel =
@@ -797,80 +682,6 @@ static jobjectArray MakeStringArray(
return arrayObj;
}
-static jobjectArray JHwParcel_native_readStringArray(
- JNIEnv *env, jobject thiz, jint size) {
- hardware::Parcel *parcel =
- JHwParcel::GetNativeContext(env, thiz)->getParcel();
-
- size_t parentHandle;
- const hidl_string *val = static_cast<const hidl_string *>(
- parcel->readBuffer(&parentHandle));
-
- if (val == NULL) {
- signalExceptionForError(env, UNKNOWN_ERROR);
- return NULL;
- }
-
- status_t err = OK;
- for (jint i = 0; (err == OK) && (i < size); ++i) {
- err = const_cast<hidl_string *>(&val[i])
- ->readEmbeddedFromParcel(
- *parcel,
- parentHandle,
- i * sizeof(hidl_string));
- }
-
- if (err != OK) {
- signalExceptionForError(env, err);
- return NULL;
- }
-
- return MakeStringArray(env, val, size);
-}
-
-static void JHwParcel_native_writeStringArray(
- JNIEnv *env, jobject thiz, jint size, jobjectArray arrayObj) {
- if (arrayObj == NULL) {
- jniThrowException(env, "java/lang/NullPointerException", NULL);
- return;
- }
-
- jsize len = env->GetArrayLength(arrayObj);
-
- if (len != size) {
- jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
- return;
- }
-
- sp<JHwParcel> impl = JHwParcel::GetNativeContext(env, thiz);
-
- hidl_string *strings = impl->getStorage()->allocStringArray(len);
-
- for (jsize i = 0; i < len; ++i) {
- ScopedLocalRef<jstring> stringObj(
- env,
- (jstring)env->GetObjectArrayElement(arrayObj, i));
-
- const hidl_string *s =
- impl->getStorage()->allocTemporaryString(env, stringObj.get());
-
- strings[i].setToExternal(s->c_str(), s->size());
- }
-
- hardware::Parcel *parcel = impl->getParcel();
-
- size_t parentHandle;
- status_t err = parcel->writeBuffer(
- strings, sizeof(hidl_string) * len, &parentHandle);
-
- for (jsize i = 0; (err == OK) && (i < len); ++i) {
- err = strings[i].writeEmbeddedToParcel(
- parcel, parentHandle, i * sizeof(hidl_string));
- }
-
- signalExceptionForError(env, err);
-}
-
static jobjectArray JHwParcel_native_readStringVector(
JNIEnv *env, jobject thiz) {
typedef hidl_vec<hidl_string> string_vec;
@@ -1047,26 +858,16 @@ static JNINativeMethod gMethods[] = {
{ "writeString", "(Ljava/lang/String;)V",
(void *)JHwParcel_native_writeString },
- { "writeBoolArray", "(I[Z)V", (void *)JHwParcel_native_writeBoolArray },
{ "writeBoolVector", "([Z)V", (void *)JHwParcel_native_writeBoolVector },
- { "writeInt8Array", "(I[B)V", (void *)JHwParcel_native_writeInt8Array },
{ "writeInt8Vector", "([B)V", (void *)JHwParcel_native_writeInt8Vector },
- { "writeInt16Array", "(I[S)V", (void *)JHwParcel_native_writeInt16Array },
{ "writeInt16Vector", "([S)V", (void *)JHwParcel_native_writeInt16Vector },
- { "writeInt32Array", "(I[I)V", (void *)JHwParcel_native_writeInt32Array },
{ "writeInt32Vector", "([I)V", (void *)JHwParcel_native_writeInt32Vector },
- { "writeInt64Array", "(I[J)V", (void *)JHwParcel_native_writeInt64Array },
{ "writeInt64Vector", "([J)V", (void *)JHwParcel_native_writeInt64Vector },
- { "writeFloatArray", "(I[F)V", (void *)JHwParcel_native_writeFloatArray },
{ "writeFloatVector", "([F)V", (void *)JHwParcel_native_writeFloatVector },
- { "writeDoubleArray", "(I[D)V", (void *)JHwParcel_native_writeDoubleArray },
{ "writeDoubleVector", "([D)V",
(void *)JHwParcel_native_writeDoubleVector },
- { "writeStringArray", "(I[Ljava/lang/String;)V",
- (void *)JHwParcel_native_writeStringArray },
-
{ "writeStringVector", "([Ljava/lang/String;)V",
(void *)JHwParcel_native_writeStringVector },
@@ -1087,24 +888,14 @@ static JNINativeMethod gMethods[] = {
{ "readString", "()Ljava/lang/String;",
(void *)JHwParcel_native_readString },
- { "readBoolArray", "(I)[Z", (void *)JHwParcel_native_readBoolArray },
{ "readBoolVector", "()[Z", (void *)JHwParcel_native_readBoolVector },
- { "readInt8Array", "(I)[B", (void *)JHwParcel_native_readInt8Array },
{ "readInt8Vector", "()[B", (void *)JHwParcel_native_readInt8Vector },
- { "readInt16Array", "(I)[S", (void *)JHwParcel_native_readInt16Array },
{ "readInt16Vector", "()[S", (void *)JHwParcel_native_readInt16Vector },
- { "readInt32Array", "(I)[I", (void *)JHwParcel_native_readInt32Array },
{ "readInt32Vector", "()[I", (void *)JHwParcel_native_readInt32Vector },
- { "readInt64Array", "(I)[J", (void *)JHwParcel_native_readInt64Array },
{ "readInt64Vector", "()[J", (void *)JHwParcel_native_readInt64Vector },
- { "readFloatArray", "(I)[F", (void *)JHwParcel_native_readFloatArray },
{ "readFloatVector", "()[F", (void *)JHwParcel_native_readFloatVector },
- { "readDoubleArray", "(I)[D", (void *)JHwParcel_native_readDoubleArray },
{ "readDoubleVector", "()[D", (void *)JHwParcel_native_readDoubleVector },
- { "readStringArray", "(I)[Ljava/lang/String;",
- (void *)JHwParcel_native_readStringArray },
-
{ "readStringVector", "()[Ljava/lang/String;",
(void *)JHwParcel_native_readStringVector },
diff --git a/core/jni/hwbinder/EphemeralStorage.cpp b/core/jni/hwbinder/EphemeralStorage.cpp
index 187beeea4de1..4996bc86cade 100644
--- a/core/jni/hwbinder/EphemeralStorage.cpp
+++ b/core/jni/hwbinder/EphemeralStorage.cpp
@@ -71,21 +71,6 @@ const hidl_string *EphemeralStorage::allocTemporaryString(
return s;
}
-#define DEFINE_ALLOC_ARRAY_METHODS(Suffix,Type,NewType) \
-const Type *EphemeralStorage::allocTemporary ## Suffix ## Array( \
- JNIEnv *env, Type ## Array arrayObj) { \
- Type ## Array obj = (Type ## Array)env->NewGlobalRef(arrayObj); \
- const Type *val = env->Get ## NewType ## ArrayElements(obj, NULL); \
- \
- Item item; \
- item.mType = TYPE_ ## Suffix ## _ARRAY; \
- item.mObj = obj; \
- item.mPtr = (void *)val; \
- mItems.push_back(item); \
- \
- return val; \
-}
-
#define DEFINE_ALLOC_VECTOR_METHODS(Suffix,Type,NewType) \
const hidl_vec<Type> *EphemeralStorage::allocTemporary ## Suffix ## Vector( \
JNIEnv *env, Type ## Array arrayObj) { \
@@ -107,13 +92,6 @@ const hidl_vec<Type> *EphemeralStorage::allocTemporary ## Suffix ## Vector( \
return vec; \
}
-DEFINE_ALLOC_ARRAY_METHODS(Int8,jbyte,Byte)
-DEFINE_ALLOC_ARRAY_METHODS(Int16,jshort,Short)
-DEFINE_ALLOC_ARRAY_METHODS(Int32,jint,Int)
-DEFINE_ALLOC_ARRAY_METHODS(Int64,jlong,Long)
-DEFINE_ALLOC_ARRAY_METHODS(Float,jfloat,Float)
-DEFINE_ALLOC_ARRAY_METHODS(Double,jdouble,Double)
-
DEFINE_ALLOC_VECTOR_METHODS(Int8,jbyte,Byte)
DEFINE_ALLOC_VECTOR_METHODS(Int16,jshort,Short)
DEFINE_ALLOC_VECTOR_METHODS(Int32,jint,Int)
diff --git a/core/jni/hwbinder/EphemeralStorage.h b/core/jni/hwbinder/EphemeralStorage.h
index b02ed9f5ea69..f07c782bfdf7 100644
--- a/core/jni/hwbinder/EphemeralStorage.h
+++ b/core/jni/hwbinder/EphemeralStorage.h
@@ -26,9 +26,6 @@
namespace android {
#define DECLARE_ALLOC_METHODS(Suffix,Type) \
- const Type *allocTemporary ## Suffix ## Array( \
- JNIEnv *env, Type ## Array arrayObj); \
- \
const ::android::hardware::hidl_vec<Type> * \
allocTemporary ## Suffix ## Vector( \
JNIEnv *env, Type ## Array arrayObj);
diff --git a/docs/html/_redirects.yaml b/docs/html/_redirects.yaml
index 7e7c2de04b68..3458bdc73149 100644
--- a/docs/html/_redirects.yaml
+++ b/docs/html/_redirects.yaml
@@ -1282,3 +1282,6 @@ redirects:
- from: /preview/features/data-saver.html
to: /training/basics/network-ops/data-saver.html
+# Temporary redirect
+- from: /ndk/guides/cmake.html
+ to: https://sites.google.com/a/android.com/tools/tech-docs/external-c-builds#TOC-CMake-Variables-List \ No newline at end of file
diff --git a/docs/html/develop/index.jd b/docs/html/develop/index.jd
index cee8327a3008..b1d738832b3a 100644
--- a/docs/html/develop/index.jd
+++ b/docs/html/develop/index.jd
@@ -27,7 +27,7 @@ rewritten <b>layout editor</b> with the new constraint layout,
helping you build rich UI with less work.</p>
-<p class="dac-hero-description">With over a dozen new features, Android Studio
+<p class="dac-hero-description">With over 20 new features, Android Studio
2.2 helps you code faster and smarter.</p>
<p style="margin-top:24px">
diff --git a/docs/html/index.jd b/docs/html/index.jd
index 32360fd0e932..39e3d73439ee 100644
--- a/docs/html/index.jd
+++ b/docs/html/index.jd
@@ -75,7 +75,7 @@ nonavpage=true
<div class="col-7of16 col-pull-6of16">
<h1 class="dac-hero-title" style="color:#004d40">Android Studio 2.2!</h1>
<p class="dac-hero-description" style="color:#004d40">The latest update is
-packed with over a dozen new features, like a rewritten layout editor with the
+packed with over 20 new features, like a rewritten layout editor with the
new constraint layout, support for Android 7.0 Nougat, Espresso test recording,
enhanced Jack compiler / Java 8 support, expanded C++ support with CMake and
NDK-Build, and much more!</p>
diff --git a/docs/html/jd_extras_en.js b/docs/html/jd_extras_en.js
index f3469b4f4ec1..e4bd36856c9f 100644
--- a/docs/html/jd_extras_en.js
+++ b/docs/html/jd_extras_en.js
@@ -4127,8 +4127,8 @@ METADATA['en'].collections = {
"develop/landing/tools": {
"title": "",
"resources": [
- "https://www.youtube.com/watch?v=ZOz_yr8Yxq8&list=PLWz5rJ2EKKc_w6fodMGrA1_tsI3pqPbqa",
- "https://www.youtube.com/watch?v=eOV2owswDkE&list=PLWz5rJ2EKKc_w6fodMGrA1_tsI3pqPbqa",
+ "https://www.youtube.com/watch?v=NbHsi3-uR8E&list=PLWz5rJ2EKKc_w6fodMGrA1_tsI3pqPbqa",
+ "https://www.youtube.com/watch?v=-SY5nkNVUn0&list=PLWz5rJ2EKKc_w6fodMGrA1_tsI3pqPbqa",
"https://www.youtube.com/watch?v=StqAZ1OQbqA&list=PLWz5rJ2EKKc_w6fodMGrA1_tsI3pqPbqa",
"https://www.youtube.com/watch?v=-SY5nkNVUn0&list=PLWz5rJ2EKKc_w6fodMGrA1_tsI3pqPbqa",
"https://www.youtube.com/watch?v=4rI4tTd7-J8&list=PLWz5rJ2EKKc_w6fodMGrA1_tsI3pqPbqa",
@@ -5568,7 +5568,7 @@ METADATA['en'].collections = {
"title": "",
"resources": [
"https://medium.com/google-developers/how-often-should-you-update-android-studio-db25785c488e#.8blbql35x",
- "http://android-developers.blogspot.com/2016/04/android-studio-2-0.html",
+ "https://android-developers.blogspot.com/2016/09/android-studio-2-2.html",
"https://medium.com/google-developers/writing-more-code-by-writing-less-code-with-android-studio-live-templates-244f648d17c7#.hczcm02du",
]
},
diff --git a/docs/html/topic/arc/index.jd b/docs/html/topic/arc/index.jd
index d46fbc89ac59..a025459226aa 100644
--- a/docs/html/topic/arc/index.jd
+++ b/docs/html/topic/arc/index.jd
@@ -51,7 +51,7 @@ review your mouse and keyboard interactions.
&lt;!-- Some Chromebooks don't support touch. Although not essential,
it's a good idea to explicitly include this declaration. --&gt;
&lt;uses-feature android:name="android.hardware.touchscreen"
- required="false" /&gt;
+ android:required="false" /&gt;
&lt;/manifest&gt;
</pre>
diff --git a/docs/html/training/testing/unit-testing/instrumented-unit-tests.jd b/docs/html/training/testing/unit-testing/instrumented-unit-tests.jd
index df8b1bc5c9a6..dc94bdf05502 100644
--- a/docs/html/training/testing/unit-testing/instrumented-unit-tests.jd
+++ b/docs/html/training/testing/unit-testing/instrumented-unit-tests.jd
@@ -53,8 +53,9 @@ you choose, to simulate any dependency relationships.</p>
<p>In your Android Studio project, you must store the source files for
instrumented tests at
-<code><var>module-name</var>/src/androidTests/java/</code>. This directory
-already exists when you create a new project.</p>
+<code><var>module-name</var>/src/androidTest/java/</code>. This directory
+already exists when you create a new project and contains an example
+instrumented test.</p>
<p>Before you begin, you should
<a href="{@docRoot}tools/testing-support-library/index.html#setup">download
diff --git a/libs/hwui/SkiaCanvas.cpp b/libs/hwui/SkiaCanvas.cpp
index a3c9a3944159..9553ab459b5c 100644
--- a/libs/hwui/SkiaCanvas.cpp
+++ b/libs/hwui/SkiaCanvas.cpp
@@ -26,6 +26,7 @@
#include <SkDrawFilter.h>
#include <SkGraphics.h>
#include <SkImage.h>
+#include <SkImagePriv.h>
#include <SkRSXform.h>
#include <SkShader.h>
#include <SkTemplates.h>
@@ -594,10 +595,13 @@ void SkiaCanvas::drawBitmapMesh(const SkBitmap& bitmap, int meshWidth, int meshH
if (paint) {
tmpPaint = *paint;
}
- SkShader* shader = SkShader::CreateBitmapShader(bitmap,
- SkShader::kClamp_TileMode,
- SkShader::kClamp_TileMode);
- SkSafeUnref(tmpPaint.setShader(shader));
+ sk_sp<SkShader> shader = SkMakeBitmapShader(bitmap,
+ SkShader::kClamp_TileMode,
+ SkShader::kClamp_TileMode,
+ nullptr,
+ kNever_SkCopyPixelsMode,
+ nullptr);
+ tmpPaint.setShader(std::move(shader));
mCanvas->drawVertices(SkCanvas::kTriangles_VertexMode, ptCount, (SkPoint*)vertices,
texs, (const SkColor*)colors, NULL, indices,
diff --git a/libs/hwui/tests/unit/RecordingCanvasTests.cpp b/libs/hwui/tests/unit/RecordingCanvasTests.cpp
index fdf0b547fb54..edc7191459b7 100644
--- a/libs/hwui/tests/unit/RecordingCanvasTests.cpp
+++ b/libs/hwui/tests/unit/RecordingCanvasTests.cpp
@@ -740,10 +740,13 @@ TEST(RecordingCanvas, refBitmapInShader_bitmapShader) {
SkBitmap bitmap = TestUtils::createSkBitmap(100, 100);
auto dl = TestUtils::createDisplayList<RecordingCanvas>(100, 100, [&bitmap](RecordingCanvas& canvas) {
SkPaint paint;
- SkAutoTUnref<SkShader> shader(SkShader::CreateBitmapShader(bitmap,
+ sk_sp<SkShader> shader = SkMakeBitmapShader(bitmap,
SkShader::TileMode::kClamp_TileMode,
- SkShader::TileMode::kClamp_TileMode));
- paint.setShader(shader);
+ SkShader::TileMode::kClamp_TileMode,
+ nullptr,
+ kNever_SkCopyPixelsMode,
+ nullptr);
+ paint.setShader(std::move(shader));
canvas.drawRoundRect(0, 0, 100, 100, 20.0f, 20.0f, paint);
});
auto& bitmaps = dl->getBitmapResources();
@@ -754,21 +757,24 @@ TEST(RecordingCanvas, refBitmapInShader_composeShader) {
SkBitmap bitmap = TestUtils::createSkBitmap(100, 100);
auto dl = TestUtils::createDisplayList<RecordingCanvas>(100, 100, [&bitmap](RecordingCanvas& canvas) {
SkPaint paint;
- SkAutoTUnref<SkShader> shader1(SkShader::CreateBitmapShader(bitmap,
+ sk_sp<SkShader> shader1 = SkMakeBitmapShader(bitmap,
+ SkShader::TileMode::kClamp_TileMode,
SkShader::TileMode::kClamp_TileMode,
- SkShader::TileMode::kClamp_TileMode));
+ nullptr,
+ kNever_SkCopyPixelsMode,
+ nullptr);
SkPoint center;
center.set(50, 50);
SkColor colors[2];
colors[0] = Color::Black;
colors[1] = Color::White;
- SkAutoTUnref<SkShader> shader2(SkGradientShader::CreateRadial(center, 50, colors, nullptr, 2,
- SkShader::TileMode::kRepeat_TileMode));
+ sk_sp<SkShader> shader2 = SkGradientShader::MakeRadial(center, 50, colors, nullptr, 2,
+ SkShader::TileMode::kRepeat_TileMode);
- SkAutoTUnref<SkShader> composeShader(SkShader::CreateComposeShader(shader1, shader2,
- SkXfermode::Mode::kMultiply_Mode));
- paint.setShader(composeShader);
+ sk_sp<SkShader> composeShader = SkShader::MakeComposeShader(std::move(shader1), std::move(shader2),
+ SkXfermode::Mode::kMultiply_Mode);
+ paint.setShader(std::move(composeShader));
canvas.drawRoundRect(0, 0, 100, 100, 20.0f, 20.0f, paint);
});
auto& bitmaps = dl->getBitmapResources();
diff --git a/libs/hwui/tests/unit/SkiaBehaviorTests.cpp b/libs/hwui/tests/unit/SkiaBehaviorTests.cpp
index 158938a85907..a30ada0df453 100644
--- a/libs/hwui/tests/unit/SkiaBehaviorTests.cpp
+++ b/libs/hwui/tests/unit/SkiaBehaviorTests.cpp
@@ -17,8 +17,9 @@
#include "tests/common/TestUtils.h"
#include <gtest/gtest.h>
-#include <SkShader.h>
#include <SkColorMatrixFilter.h>
+#include <SkImagePriv.h>
+#include <SkShader.h>
using namespace android;
using namespace android::uirenderer;
@@ -29,10 +30,13 @@ using namespace android::uirenderer;
*/
TEST(SkiaBehavior, CreateBitmapShader1x1) {
SkBitmap origBitmap = TestUtils::createSkBitmap(1, 1);
- SkAutoTUnref<SkShader> s(SkShader::CreateBitmapShader(
+ sk_sp<SkShader> s = SkMakeBitmapShader(
origBitmap,
SkShader::kClamp_TileMode,
- SkShader::kRepeat_TileMode));
+ SkShader::kRepeat_TileMode,
+ nullptr,
+ kNever_SkCopyPixelsMode,
+ nullptr);
SkBitmap bitmap;
SkShader::TileMode xy[2];
diff --git a/packages/SystemUI/res/drawable/ic_qs_data_disabled.xml b/packages/SystemUI/res/drawable/ic_qs_data_disabled.xml
index b4144a3474fd..d11b6f461870 100644
--- a/packages/SystemUI/res/drawable/ic_qs_data_disabled.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_data_disabled.xml
@@ -14,8 +14,9 @@
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="24.0dp"
- android:height="24.0dp"
+ android:autoMirrored="true"
+ android:width="32.0dp"
+ android:height="32.0dp"
android:viewportWidth="40.0"
android:viewportHeight="40.0">
<path
diff --git a/packages/SystemUI/res/drawable/stat_sys_data_disabled.xml b/packages/SystemUI/res/drawable/stat_sys_data_disabled.xml
index 4e2a0245ab2a..694019e98867 100644
--- a/packages/SystemUI/res/drawable/stat_sys_data_disabled.xml
+++ b/packages/SystemUI/res/drawable/stat_sys_data_disabled.xml
@@ -14,9 +14,9 @@
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="17.0dp"
+ android:width="8.5dp"
android:height="17.0dp"
- android:viewportWidth="40.0"
+ android:viewportWidth="20.0"
android:viewportHeight="40.0">
<path
android:fillColor="#FFFFFFFF"
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java b/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
index 610418171266..d483e4240315 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
@@ -160,6 +160,10 @@ public class QSAnimator implements Callback, PageListener, Listener, OnLayoutCha
for (QSTile<?> tile : tiles) {
QSTileBaseView tileView = mQsPanel.getTileView(tile);
+ if (tileView == null) {
+ Log.e(TAG, "tileView is null " + tile.getTileSpec());
+ continue;
+ }
final TextView label = ((QSTileView) tileView).getLabel();
final View tileIcon = tileView.getIcon().getIconView();
if (count < mNumQuickTiles && mAllowFancy) {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
index 784d2ba34c48..e5493b645078 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
@@ -17,6 +17,7 @@
package com.android.systemui.recents;
import android.app.Activity;
+import android.app.ActivityManager;
import android.app.ActivityOptions;
import android.app.TaskStackBuilder;
import android.content.BroadcastReceiver;
@@ -89,6 +90,7 @@ import com.android.systemui.statusbar.BaseStatusBar;
import java.io.FileDescriptor;
import java.io.PrintWriter;
+import java.util.List;
/**
* The main Recents activity that is started from RecentsComponent.
@@ -167,18 +169,39 @@ public class RecentsActivity extends Activity implements ViewTreeObserver.OnPreD
*/
final BroadcastReceiver mSystemBroadcastReceiver = new BroadcastReceiver() {
@Override
- public void onReceive(Context context, Intent intent) {
+ public void onReceive(Context ctx, Intent intent) {
String action = intent.getAction();
if (action.equals(Intent.ACTION_SCREEN_OFF)) {
// When the screen turns off, dismiss Recents to Home
dismissRecentsToHomeIfVisible(false);
} else if (action.equals(Intent.ACTION_TIME_CHANGED)) {
- // For the time being, if the time changes, then invalidate the
- // last-stack-active-time, this ensures that we will just show the last N tasks
- // the next time that Recents loads, but prevents really old tasks from showing
- // up if the task time is set forward.
- Prefs.putLong(RecentsActivity.this, Prefs.Key.OVERVIEW_LAST_STACK_TASK_ACTIVE_TIME,
- 0);
+ // If the time shifts but the currentTime >= lastStackActiveTime, then that boundary
+ // is still valid. Otherwise, we need to reset the lastStackactiveTime to the
+ // currentTime and remove the old tasks in between which would not be previously
+ // visible, but currently would be in the new currentTime
+ long oldLastStackActiveTime = Prefs.getLong(RecentsActivity.this,
+ Prefs.Key.OVERVIEW_LAST_STACK_TASK_ACTIVE_TIME, -1);
+ if (oldLastStackActiveTime != -1) {
+ long currentTime = System.currentTimeMillis();
+ if (currentTime < oldLastStackActiveTime) {
+ // We are only removing tasks that are between the new current time
+ // and the old last stack active time, they were not visible and in the
+ // TaskStack so we don't need to remove any associated TaskViews but we do
+ // need to load the task id's from the system
+ RecentsTaskLoadPlan loadPlan = Recents.getTaskLoader().createLoadPlan(ctx);
+ loadPlan.preloadRawTasks(false /* includeFrontMostExcludedTask */);
+ List<ActivityManager.RecentTaskInfo> tasks = loadPlan.getRawTasks();
+ for (int i = tasks.size() - 1; i >= 0; i--) {
+ ActivityManager.RecentTaskInfo task = tasks.get(i);
+ if (currentTime <= task.lastActiveTime && task.lastActiveTime <
+ oldLastStackActiveTime) {
+ Recents.getSystemServices().removeTask(task.persistentId);
+ }
+ }
+ Prefs.putLong(RecentsActivity.this,
+ Prefs.Key.OVERVIEW_LAST_STACK_TASK_ACTIVE_TIME, currentTime);
+ }
+ }
}
}
};
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
index 83f98e5d874c..44a5bd3407b2 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
@@ -217,11 +217,7 @@ public class RecentsImpl implements ActivityOptions.OnAnimationFinishedListener
* {@link Recents#onBusEvent(RecentsVisibilityChangedEvent)}.
*/
public void onVisibilityChanged(Context context, boolean visible) {
- SystemUIApplication app = (SystemUIApplication) context;
- PhoneStatusBar statusBar = app.getComponent(PhoneStatusBar.class);
- if (statusBar != null) {
- statusBar.updateRecentsVisibility(visible);
- }
+ Recents.getSystemServices().setRecentsVisibility(visible);
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
index 9d9e2738973e..e0cdb1ac7c62 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
@@ -70,6 +70,7 @@ import android.util.MutableBoolean;
import android.view.Display;
import android.view.IAppTransitionAnimationSpecsFuture;
import android.view.IDockedStackListener;
+import android.view.IWindowManager;
import android.view.WindowManager;
import android.view.WindowManager.KeyboardShortcutsReceiver;
import android.view.WindowManagerGlobal;
@@ -121,6 +122,7 @@ public class SystemServicesProxy {
IPackageManager mIpm;
AssistUtils mAssistUtils;
WindowManager mWm;
+ IWindowManager mIwm;
UserManager mUm;
Display mDisplay;
String mRecentsPackage;
@@ -208,6 +210,7 @@ public class SystemServicesProxy {
mIpm = AppGlobals.getPackageManager();
mAssistUtils = new AssistUtils(context);
mWm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
+ mIwm = WindowManagerGlobal.getWindowManagerService();
mUm = UserManager.get(context);
mDisplay = mWm.getDefaultDisplay();
mRecentsPackage = context.getPackageName();
@@ -1097,6 +1100,28 @@ public class SystemServicesProxy {
}
}
+ /**
+ * Updates the visibility of recents.
+ */
+ public void setRecentsVisibility(boolean visible) {
+ try {
+ mIwm.setRecentsVisibility(visible);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Unable to reach window manager", e);
+ }
+ }
+
+ /**
+ * Updates the visibility of the picture-in-picture.
+ */
+ public void setTvPipVisibility(boolean visible) {
+ try {
+ mIwm.setTvPipVisibility(visible);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Unable to reach window manager", e);
+ }
+ }
+
private final class H extends Handler {
private static final int ON_TASK_STACK_CHANGED = 1;
private static final int ON_ACTIVITY_PINNED = 2;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java
index 1278b735a7cd..9b48e4d02623 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java
@@ -248,6 +248,13 @@ public class RecentsTaskLoadPlan {
return mStack;
}
+ /**
+ * Returns the raw list of recent tasks.
+ */
+ public List<ActivityManager.RecentTaskInfo> getRawTasks() {
+ return mRawTasks;
+ }
+
/** Returns whether there are any tasks in any stacks. */
public boolean hasTasks() {
if (mStack != null) {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/tv/RecentsTvImpl.java b/packages/SystemUI/src/com/android/systemui/recents/tv/RecentsTvImpl.java
index fca8d2d1fae1..ef9de53682e4 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/tv/RecentsTvImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/tv/RecentsTvImpl.java
@@ -140,10 +140,6 @@ public class RecentsTvImpl extends RecentsImpl{
@Override
public void onVisibilityChanged(Context context, boolean visible) {
- SystemUIApplication app = (SystemUIApplication) context;
- TvStatusBar statusBar = app.getComponent(TvStatusBar.class);
- if (statusBar != null) {
- statusBar.updateRecentsVisibility(visible);
- }
+ Recents.getSystemServices().setRecentsVisibility(visible);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
index 4c40da0ef2fc..089f7a9f0503 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -3003,10 +3003,6 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
Integer.toHexString(diff)));
boolean sbModeChanged = false;
if (diff != 0) {
- // we never set the recents bit via this method, so save the prior state to prevent
- // clobbering the bit below
- final boolean wasRecentsVisible = (mSystemUiVisibility & View.RECENT_APPS_VISIBLE) > 0;
-
mSystemUiVisibility = newVal;
// update low profile
@@ -3055,11 +3051,6 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
mSystemUiVisibility &= ~View.NAVIGATION_BAR_UNHIDE;
}
- // restore the recents bit
- if (wasRecentsVisible) {
- mSystemUiVisibility |= View.RECENT_APPS_VISIBLE;
- }
-
// send updated sysui visibility to window manager
notifyUiVisibilityChanged(mSystemUiVisibility);
}
@@ -4848,16 +4839,6 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
return false;
}
- public void updateRecentsVisibility(boolean visible) {
- // Update the recents visibility flag
- if (visible) {
- mSystemUiVisibility |= View.RECENT_APPS_VISIBLE;
- } else {
- mSystemUiVisibility &= ~View.RECENT_APPS_VISIBLE;
- }
- notifyUiVisibilityChanged(mSystemUiVisibility);
- }
-
@Override
public void showScreenPinningRequest(int taskId) {
if (mKeyguardMonitor.isShowing()) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java
index 2d4900b36890..3c83921a1e14 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java
@@ -19,7 +19,6 @@ package com.android.systemui.statusbar.tv;
import android.content.ComponentName;
import android.graphics.Rect;
import android.os.IBinder;
-import android.os.RemoteException;
import android.service.notification.NotificationListenerService.RankingMap;
import android.service.notification.StatusBarNotification;
import android.view.View;
@@ -36,16 +35,6 @@ import com.android.systemui.tv.pip.PipManager;
public class TvStatusBar extends BaseStatusBar {
- /**
- * Tracking calls to View.setSystemUiVisibility().
- */
- int mSystemUiVisibility = View.SYSTEM_UI_FLAG_VISIBLE;
-
- /**
- * Last value sent to window manager.
- */
- private int mLastDispatchedSystemUiVisibility = ~View.SYSTEM_UI_FLAG_VISIBLE;
-
@Override
public void setIcon(String slot, StatusBarIcon icon) {
}
@@ -224,40 +213,6 @@ public class TvStatusBar extends BaseStatusBar {
putComponent(TvStatusBar.class, this);
}
- /**
- * Updates the visibility of the picture-in-picture.
- */
- public void updatePipVisibility(boolean visible) {
- if (visible) {
- mSystemUiVisibility |= View.TV_PICTURE_IN_PICTURE_VISIBLE;
- } else {
- mSystemUiVisibility &= ~View.TV_PICTURE_IN_PICTURE_VISIBLE;
- }
- notifyUiVisibilityChanged(mSystemUiVisibility);
- }
-
- /**
- * Updates the visibility of the Recents
- */
- public void updateRecentsVisibility(boolean visible) {
- if (visible) {
- mSystemUiVisibility |= View.RECENT_APPS_VISIBLE;
- } else {
- mSystemUiVisibility &= ~View.RECENT_APPS_VISIBLE;
- }
- notifyUiVisibilityChanged(mSystemUiVisibility);
- }
-
- private void notifyUiVisibilityChanged(int vis) {
- try {
- if (mLastDispatchedSystemUiVisibility != vis) {
- mWindowManagerService.statusBarVisibilityChanged(vis);
- mLastDispatchedSystemUiVisibility = vis;
- }
- } catch (RemoteException ex) {
- }
- }
-
@Override
public void handleSystemNavigationKey(int arg1) {
// Not implemented
diff --git a/packages/SystemUI/src/com/android/systemui/tv/pip/PipManager.java b/packages/SystemUI/src/com/android/systemui/tv/pip/PipManager.java
index 3f8650a5e116..085e003f8869 100644
--- a/packages/SystemUI/src/com/android/systemui/tv/pip/PipManager.java
+++ b/packages/SystemUI/src/com/android/systemui/tv/pip/PipManager.java
@@ -723,10 +723,7 @@ public class PipManager {
return mPipRecentsOverlayManager;
}
- private void updatePipVisibility(boolean visible) {
- TvStatusBar statusBar = ((SystemUIApplication) mContext).getComponent(TvStatusBar.class);
- if (statusBar != null) {
- statusBar.updatePipVisibility(visible);
- }
+ private void updatePipVisibility(final boolean visible) {
+ SystemServicesProxy.getInstance(mContext).setTvPipVisibility(visible);
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/TileLayoutTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/TileLayoutTest.java
new file mode 100644
index 000000000000..8eecfcf00d46
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/TileLayoutTest.java
@@ -0,0 +1,162 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.qs;
+
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertTrue;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.anyBoolean;
+import static org.mockito.Mockito.anyInt;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+import android.content.Context;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.runner.AndroidJUnit4;
+import android.test.suitebuilder.annotation.SmallTest;
+import com.android.systemui.R;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class TileLayoutTest {
+ private Context mContext = InstrumentationRegistry.getTargetContext();
+ private final TileLayout mTileLayout = new TileLayout(mContext);
+ private int mLayoutSizeForOneTile;
+
+ @Before
+ public void setUp() throws Exception {
+ // Layout needs to leave space for the tile margins. Three times the margin size is
+ // sufficient for any number of columns.
+ mLayoutSizeForOneTile =
+ mContext.getResources().getDimensionPixelSize(R.dimen.qs_tile_margin) * 3;
+ }
+
+ private QSPanel.TileRecord createTileRecord() {
+ QSPanel.TileRecord tileRecord = new QSPanel.TileRecord();
+ tileRecord.tile = mock(QSTile.class);
+ tileRecord.tileView = spy(new QSTileBaseView(mContext, new QSIconView(mContext)));
+ return tileRecord;
+ }
+
+ @Test
+ public void testAddTile_CallsSetListeningOnTile() {
+ QSPanel.TileRecord tileRecord = createTileRecord();
+ mTileLayout.addTile(tileRecord);
+ verify(tileRecord.tile, times(1)).setListening(mTileLayout, false);
+ }
+
+ @Test
+ public void testSetListening_CallsSetListeningOnTile() {
+ QSPanel.TileRecord tileRecord = createTileRecord();
+ mTileLayout.addTile(tileRecord);
+ mTileLayout.setListening(true);
+ verify(tileRecord.tile, times(1)).setListening(mTileLayout, true);
+ }
+
+ @Test
+ public void testSetListening_SameValueIsNoOp() {
+ QSPanel.TileRecord tileRecord = createTileRecord();
+ mTileLayout.addTile(tileRecord);
+ mTileLayout.setListening(false);
+ verify(tileRecord.tile, times(1)).setListening(any(), anyBoolean());
+ }
+
+ @Test
+ public void testSetListening_ChangesValueForAddingFutureTiles() {
+ QSPanel.TileRecord tileRecord = createTileRecord();
+ mTileLayout.setListening(true);
+ mTileLayout.addTile(tileRecord);
+ verify(tileRecord.tile, times(1)).setListening(mTileLayout, true);
+ }
+
+ @Test
+ public void testRemoveTile_CallsSetListeningFalseOnTile() {
+ QSPanel.TileRecord tileRecord = createTileRecord();
+ mTileLayout.setListening(true);
+ mTileLayout.addTile(tileRecord);
+ mTileLayout.removeTile(tileRecord);
+ verify(tileRecord.tile, times(1)).setListening(mTileLayout, false);
+ }
+
+ @Test
+ public void testRemoveAllViews_CallsSetListeningFalseOnAllTiles() {
+ QSPanel.TileRecord tileRecord1 = createTileRecord();
+ QSPanel.TileRecord tileRecord2 = createTileRecord();
+ mTileLayout.setListening(true);
+ mTileLayout.addTile(tileRecord1);
+ mTileLayout.addTile(tileRecord2);
+ mTileLayout.removeAllViews();
+ verify(tileRecord1.tile, times(1)).setListening(mTileLayout, false);
+ verify(tileRecord2.tile, times(1)).setListening(mTileLayout, false);
+ }
+
+ @Test
+ public void testMeasureLayout_CallsLayoutOnTile() {
+ QSPanel.TileRecord tileRecord = createTileRecord();
+ mTileLayout.addTile(tileRecord);
+ mTileLayout.measure(mLayoutSizeForOneTile, mLayoutSizeForOneTile);
+ mTileLayout.layout(0, 0, mLayoutSizeForOneTile, mLayoutSizeForOneTile);
+ verify(tileRecord.tileView, times(1)).layout(anyInt(), anyInt(), anyInt(), anyInt());
+ }
+
+ @Test
+ public void testMeasureLayout_CallsLayoutOnTilesWithNeighboredBounds() {
+ QSPanel.TileRecord tileRecord1 = createTileRecord();
+ QSPanel.TileRecord tileRecord2 = createTileRecord();
+ mTileLayout.addTile(tileRecord1);
+ mTileLayout.addTile(tileRecord2);
+ mTileLayout.measure(mLayoutSizeForOneTile * 2, mLayoutSizeForOneTile * 2);
+ mTileLayout.layout(0, 0, mLayoutSizeForOneTile * 2, mLayoutSizeForOneTile * 2);
+
+ // Capture the layout calls for both tiles.
+ ArgumentCaptor<Integer> left1 = ArgumentCaptor.forClass(Integer.class);
+ ArgumentCaptor<Integer> top1 = ArgumentCaptor.forClass(Integer.class);
+ ArgumentCaptor<Integer> right1 = ArgumentCaptor.forClass(Integer.class);
+ ArgumentCaptor<Integer> bottom1 = ArgumentCaptor.forClass(Integer.class);
+ verify(tileRecord1.tileView, times(1))
+ .layout(left1.capture(), top1.capture(), right1.capture(), bottom1.capture());
+ ArgumentCaptor<Integer> left2 = ArgumentCaptor.forClass(Integer.class);
+ ArgumentCaptor<Integer> top2 = ArgumentCaptor.forClass(Integer.class);
+ ArgumentCaptor<Integer> right2 = ArgumentCaptor.forClass(Integer.class);
+ ArgumentCaptor<Integer> bottom2 = ArgumentCaptor.forClass(Integer.class);
+ verify(tileRecord2.tileView, times(1))
+ .layout(left2.capture(), top2.capture(), right2.capture(), bottom2.capture());
+
+ // We assume two tiles will always fit side-by-side.
+ assertTrue(mContext.getResources().getInteger(R.integer.quick_settings_num_columns) > 1);
+
+ // left <= right, top <= bottom
+ assertTrue(left1.getValue() <= right1.getValue());
+ assertTrue(top1.getValue() <= bottom1.getValue());
+ assertTrue(left2.getValue() <= right2.getValue());
+ assertTrue(top2.getValue() <= bottom2.getValue());
+
+ // The tiles' left and right should describe discrete ranges.
+ // Agnostic of Layout direction.
+ assertTrue(left1.getValue() > right2.getValue() || right1.getValue() < left2.getValue());
+
+ // The tiles' Top and Bottom should be the same.
+ assertEquals(top1.getValue().intValue(), top2.getValue().intValue());
+ assertEquals(bottom1.getValue().intValue(), bottom2.getValue().intValue());
+ }
+}
diff --git a/packages/WallpaperBackup/src/com/android/wallpaperbackup/WallpaperBackupAgent.java b/packages/WallpaperBackup/src/com/android/wallpaperbackup/WallpaperBackupAgent.java
index 3a82f8828b6d..ff934ef18677 100644
--- a/packages/WallpaperBackup/src/com/android/wallpaperbackup/WallpaperBackupAgent.java
+++ b/packages/WallpaperBackup/src/com/android/wallpaperbackup/WallpaperBackupAgent.java
@@ -147,11 +147,12 @@ public class WallpaperBackupAgent extends BackupAgent {
}
// only back up the wallpapers if we've been told they're eligible
- if ((sysEligible || lockEligible) && mWallpaperInfo.exists()) {
+ if (mWallpaperInfo.exists()) {
if (sysChanged || lockChanged || !infoStage.exists()) {
if (DEBUG) Slog.v(TAG, "New wallpaper configuration; copying");
FileUtils.copyFileOrThrow(mWallpaperInfo, infoStage);
}
+ if (DEBUG) Slog.v(TAG, "Storing wallpaper metadata");
fullBackupFile(infoStage, data);
}
if (sysEligible && mWallpaperFile.exists()) {
@@ -159,6 +160,7 @@ public class WallpaperBackupAgent extends BackupAgent {
if (DEBUG) Slog.v(TAG, "New system wallpaper; copying");
FileUtils.copyFileOrThrow(mWallpaperFile, imageStage);
}
+ if (DEBUG) Slog.v(TAG, "Storing system wallpaper image");
fullBackupFile(imageStage, data);
prefs.edit().putInt(SYSTEM_GENERATION, sysGeneration).apply();
}
@@ -169,6 +171,7 @@ public class WallpaperBackupAgent extends BackupAgent {
if (DEBUG) Slog.v(TAG, "New lock wallpaper; copying");
FileUtils.copyFileOrThrow(mLockWallpaperFile, lockImageStage);
}
+ if (DEBUG) Slog.v(TAG, "Storing lock wallpaper image");
fullBackupFile(lockImageStage, data);
prefs.edit().putInt(LOCK_GENERATION, lockGeneration).apply();
}
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityGestureDetector.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityGestureDetector.java
index 562d95065cd8..582b19b62c22 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityGestureDetector.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityGestureDetector.java
@@ -341,6 +341,8 @@ class AccessibilityGestureDetector extends GestureDetector.SimpleOnGestureListen
mDoubleTapDetected = false;
mSecondFingerDoubleTap = false;
mGestureStarted = false;
+ mGestureDetector.onTouchEvent(MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_CANCEL,
+ 0.0f, 0.0f, 0));
cancelGesture();
}
diff --git a/services/core/Android.mk b/services/core/Android.mk
index b965ce39e7d5..a5b1069974f2 100644
--- a/services/core/Android.mk
+++ b/services/core/Android.mk
@@ -11,7 +11,7 @@ LOCAL_SRC_FILES += \
java/com/android/server/EventLogTags.logtags \
java/com/android/server/am/EventLogTags.logtags \
../../../../system/netd/server/binder/android/net/INetd.aidl \
- ../../../../system/netd/server/binder/android/net/metrics/IDnsEventListener.aidl \
+ ../../../../system/netd/server/binder/android/net/metrics/INetdEventListener.aidl \
LOCAL_AIDL_INCLUDES += \
system/netd/server/binder
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 667a4a9e1b47..4111d21e6112 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -372,6 +372,11 @@ public class ConnectivityService extends IConnectivityManager.Stub
private static final int EVENT_SET_ACCEPT_UNVALIDATED = 28;
/**
+ * used to specify whether a network should not be penalized when it becomes unvalidated.
+ */
+ private static final int EVENT_SET_AVOID_UNVALIDATED = 35;
+
+ /**
* used to ask the user to confirm a connection to an unvalidated network.
* obj = network
*/
@@ -2064,7 +2069,9 @@ public class ConnectivityService extends IConnectivityManager.Stub
mKeepaliveTracker.dump(pw);
pw.println();
+ dumpAvoidBadWifiSettings(pw);
+ pw.println();
if (mInetLog != null && mInetLog.size() > 0) {
pw.println();
pw.println("Inet condition reports:");
@@ -2720,6 +2727,12 @@ public class ConnectivityService extends IConnectivityManager.Stub
accept ? 1 : 0, always ? 1: 0, network));
}
+ @Override
+ public void setAvoidUnvalidated(Network network) {
+ enforceConnectivityInternalPermission();
+ mHandler.sendMessage(mHandler.obtainMessage(EVENT_SET_AVOID_UNVALIDATED, network));
+ }
+
private void handleSetAcceptUnvalidated(Network network, boolean accept, boolean always) {
if (DBG) log("handleSetAcceptUnvalidated network=" + network +
" accept=" + accept + " always=" + always);
@@ -2760,6 +2773,20 @@ public class ConnectivityService extends IConnectivityManager.Stub
}
+ private void handleSetAvoidUnvalidated(Network network) {
+ NetworkAgentInfo nai = getNetworkAgentInfoForNetwork(network);
+ if (nai == null || nai.lastValidated) {
+ // Nothing to do. The network either disconnected or revalidated.
+ return;
+ }
+ if (!nai.avoidUnvalidated) {
+ int oldScore = nai.getCurrentScore();
+ nai.avoidUnvalidated = true;
+ rematchAllNetworksAndRequests(nai, oldScore);
+ sendUpdatedScoreToFactories(nai);
+ }
+ }
+
private void scheduleUnvalidatedPrompt(NetworkAgentInfo nai) {
if (VDBG) log("scheduleUnvalidatedPrompt " + nai.network);
mHandler.sendMessageDelayed(
@@ -2767,31 +2794,70 @@ public class ConnectivityService extends IConnectivityManager.Stub
PROMPT_UNVALIDATED_DELAY_MS);
}
- private boolean mAvoidBadWifi;
+ private boolean mAvoidBadWifi = true;
public boolean avoidBadWifi() {
return mAvoidBadWifi;
}
@VisibleForTesting
- public boolean updateAvoidBadWifi() {
- // There are two modes: either we always automatically avoid unvalidated wifi, or we show a
- // dialog and don't switch to it. The behaviour is controlled by the NETWORK_AVOID_BAD_WIFI
- // setting. If the setting has no value, then the value is taken from the config value,
- // which can be changed via OEM/carrier overlays.
- //
- // The only valid values for NETWORK_AVOID_BAD_WIFI are null and unset. Currently, the unit
- // test uses 0 in order to avoid having to mock out fetching the carrier setting.
- int defaultAvoidBadWifi =
- mContext.getResources().getInteger(R.integer.config_networkAvoidBadWifi);
- int avoid = Settings.Global.getInt(mContext.getContentResolver(),
- Settings.Global.NETWORK_AVOID_BAD_WIFI, defaultAvoidBadWifi);
+ /** Whether the device or carrier configuration disables avoiding bad wifi by default. */
+ public boolean configRestrictsAvoidBadWifi() {
+ return mContext.getResources().getInteger(R.integer.config_networkAvoidBadWifi) == 0;
+ }
+
+ /** Whether we should display a notification when wifi becomes unvalidated. */
+ public boolean shouldNotifyWifiUnvalidated() {
+ return configRestrictsAvoidBadWifi() &&
+ Settings.Global.getString(mContext.getContentResolver(),
+ Settings.Global.NETWORK_AVOID_BAD_WIFI) == null;
+ }
+
+ private boolean updateAvoidBadWifi() {
+ boolean settingAvoidBadWifi = "1".equals(Settings.Global.getString(
+ mContext.getContentResolver(), Settings.Global.NETWORK_AVOID_BAD_WIFI));
boolean prev = mAvoidBadWifi;
- mAvoidBadWifi = (avoid == 1);
+ mAvoidBadWifi = settingAvoidBadWifi || !configRestrictsAvoidBadWifi();
return mAvoidBadWifi != prev;
}
+ private void dumpAvoidBadWifiSettings(IndentingPrintWriter pw) {
+ boolean configRestrict = configRestrictsAvoidBadWifi();
+ if (!configRestrict) {
+ pw.println("Bad Wi-Fi avoidance: unrestricted");
+ return;
+ }
+
+ pw.println("Bad Wi-Fi avoidance: " + avoidBadWifi());
+ pw.increaseIndent();
+ pw.println("Config restrict: " + configRestrict);
+
+ String value = Settings.Global.getString(
+ mContext.getContentResolver(), Settings.Global.NETWORK_AVOID_BAD_WIFI);
+ String description;
+ // Can't use a switch statement because strings are legal case labels, but null is not.
+ if ("0".equals(value)) {
+ description = "get stuck";
+ } else if (value == null) {
+ description = "prompt";
+ } else if ("1".equals(value)) {
+ description = "avoid";
+ } else {
+ description = value + " (?)";
+ }
+ pw.println("User setting: " + description);
+ pw.println("Network overrides:");
+ pw.increaseIndent();
+ for (NetworkAgentInfo nai : mNetworkAgentInfos.values()) {
+ if (nai.avoidUnvalidated) {
+ pw.println(nai.name());
+ }
+ }
+ pw.decreaseIndent();
+ pw.decreaseIndent();
+ }
+
private void showValidationNotification(NetworkAgentInfo nai, NotificationType type) {
final String action;
switch (type) {
@@ -2841,7 +2907,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
NetworkCapabilities nc = nai.networkCapabilities;
if (DBG) log("handleNetworkUnvalidated " + nai.name() + " cap=" + nc);
- if (nc.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) && !avoidBadWifi()) {
+ if (nc.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) && shouldNotifyWifiUnvalidated()) {
showValidationNotification(nai, NotificationType.LOST_INTERNET);
}
}
@@ -2924,6 +2990,10 @@ public class ConnectivityService extends IConnectivityManager.Stub
handleSetAcceptUnvalidated((Network) msg.obj, msg.arg1 != 0, msg.arg2 != 0);
break;
}
+ case EVENT_SET_AVOID_UNVALIDATED: {
+ handleSetAvoidUnvalidated((Network) msg.obj);
+ break;
+ }
case EVENT_PROMPT_UNVALIDATED: {
handlePromptUnvalidated((Network) msg.obj);
break;
diff --git a/services/core/java/com/android/server/ServiceWatcher.java b/services/core/java/com/android/server/ServiceWatcher.java
index 383e25a6d293..2ff036be4b4b 100644
--- a/services/core/java/com/android/server/ServiceWatcher.java
+++ b/services/core/java/com/android/server/ServiceWatcher.java
@@ -141,8 +141,12 @@ public class ServiceWatcher implements ServiceConnection {
* <p>
* Note that if there are no matching encryption-aware services, we may not
* bind to a real service until after the current user is unlocked.
+ *
+ * @returns {@code true} if a potential service implementation was found.
*/
public boolean start() {
+ if (isServiceMissing()) return false;
+
synchronized (mLock) {
bindBestPackageLocked(mServicePackageName, false);
}
@@ -174,6 +178,17 @@ public class ServiceWatcher implements ServiceConnection {
}
/**
+ * Check if any instance of this service is present on the device,
+ * regardless of it being encryption-aware or not.
+ */
+ private boolean isServiceMissing() {
+ final Intent intent = new Intent(mAction);
+ final int flags = PackageManager.MATCH_DIRECT_BOOT_AWARE
+ | PackageManager.MATCH_DIRECT_BOOT_UNAWARE;
+ return mPm.queryIntentServicesAsUser(intent, flags, mCurrentUserId).isEmpty();
+ }
+
+ /**
* Searches and binds to the best package, or do nothing if the best package
* is already bound, unless force rebinding is requested.
*
@@ -181,7 +196,7 @@ public class ServiceWatcher implements ServiceConnection {
* packages if it is {@code null}.
* @param forceRebind Force a rebinding to the best package if it's already
* bound.
- * @return {@code true} if a valid package was found to bind to.
+ * @returns {@code true} if a valid package was found to bind to.
*/
private boolean bindBestPackageLocked(String justCheckThisPackage, boolean forceRebind) {
Intent intent = new Intent(mAction);
diff --git a/services/core/java/com/android/server/TextServicesManagerService.java b/services/core/java/com/android/server/TextServicesManagerService.java
index 4b0d4be11b14..4f02a23d1e76 100644
--- a/services/core/java/com/android/server/TextServicesManagerService.java
+++ b/services/core/java/com/android/server/TextServicesManagerService.java
@@ -459,71 +459,75 @@ public class TextServicesManagerService extends ITextServicesManager.Stub {
if (!calledFromValidUser()) {
return null;
}
+ final int subtypeHashCode;
+ final SpellCheckerInfo sci;
+ final Locale systemLocale;
synchronized (mSpellCheckerMap) {
- final int subtypeHashCode =
+ subtypeHashCode =
mSettings.getSelectedSpellCheckerSubtype(SpellCheckerSubtype.SUBTYPE_ID_NONE);
if (DBG) {
Slog.w(TAG, "getCurrentSpellCheckerSubtype: " + subtypeHashCode);
}
- final SpellCheckerInfo sci = getCurrentSpellChecker(null);
- if (sci == null || sci.getSubtypeCount() == 0) {
- if (DBG) {
- Slog.w(TAG, "Subtype not found.");
+ sci = getCurrentSpellChecker(null);
+ systemLocale = mContext.getResources().getConfiguration().locale;
+ }
+ if (sci == null || sci.getSubtypeCount() == 0) {
+ if (DBG) {
+ Slog.w(TAG, "Subtype not found.");
+ }
+ return null;
+ }
+ if (subtypeHashCode == SpellCheckerSubtype.SUBTYPE_ID_NONE
+ && !allowImplicitlySelectedSubtype) {
+ return null;
+ }
+ String candidateLocale = null;
+ if (subtypeHashCode == 0) {
+ // Spell checker language settings == "auto"
+ final InputMethodManager imm = mContext.getSystemService(InputMethodManager.class);
+ if (imm != null) {
+ final InputMethodSubtype currentInputMethodSubtype =
+ imm.getCurrentInputMethodSubtype();
+ if (currentInputMethodSubtype != null) {
+ final String localeString = currentInputMethodSubtype.getLocale();
+ if (!TextUtils.isEmpty(localeString)) {
+ // 1. Use keyboard locale if available in the spell checker
+ candidateLocale = localeString;
+ }
}
- return null;
}
- if (subtypeHashCode == SpellCheckerSubtype.SUBTYPE_ID_NONE
- && !allowImplicitlySelectedSubtype) {
- return null;
+ if (candidateLocale == null) {
+ // 2. Use System locale if available in the spell checker
+ candidateLocale = systemLocale.toString();
}
- String candidateLocale = null;
+ }
+ SpellCheckerSubtype candidate = null;
+ for (int i = 0; i < sci.getSubtypeCount(); ++i) {
+ final SpellCheckerSubtype scs = sci.getSubtypeAt(i);
if (subtypeHashCode == 0) {
- // Spell checker language settings == "auto"
- final InputMethodManager imm = mContext.getSystemService(InputMethodManager.class);
- if (imm != null) {
- final InputMethodSubtype currentInputMethodSubtype =
- imm.getCurrentInputMethodSubtype();
- if (currentInputMethodSubtype != null) {
- final String localeString = currentInputMethodSubtype.getLocale();
- if (!TextUtils.isEmpty(localeString)) {
- // 1. Use keyboard locale if available in the spell checker
- candidateLocale = localeString;
- }
+ final String scsLocale = scs.getLocale();
+ if (candidateLocale.equals(scsLocale)) {
+ return scs;
+ } else if (candidate == null) {
+ if (candidateLocale.length() >= 2 && scsLocale.length() >= 2
+ && candidateLocale.startsWith(scsLocale)) {
+ // Fall back to the applicable language
+ candidate = scs;
}
}
- if (candidateLocale == null) {
- // 2. Use System locale if available in the spell checker
- candidateLocale = mContext.getResources().getConfiguration().locale.toString();
- }
- }
- SpellCheckerSubtype candidate = null;
- for (int i = 0; i < sci.getSubtypeCount(); ++i) {
- final SpellCheckerSubtype scs = sci.getSubtypeAt(i);
- if (subtypeHashCode == 0) {
- final String scsLocale = scs.getLocale();
- if (candidateLocale.equals(scsLocale)) {
- return scs;
- } else if (candidate == null) {
- if (candidateLocale.length() >= 2 && scsLocale.length() >= 2
- && candidateLocale.startsWith(scsLocale)) {
- // Fall back to the applicable language
- candidate = scs;
- }
- }
- } else if (scs.hashCode() == subtypeHashCode) {
- if (DBG) {
- Slog.w(TAG, "Return subtype " + scs.hashCode() + ", input= " + locale
- + ", " + scs.getLocale());
- }
- // 3. Use the user specified spell check language
- return scs;
+ } else if (scs.hashCode() == subtypeHashCode) {
+ if (DBG) {
+ Slog.w(TAG, "Return subtype " + scs.hashCode() + ", input= " + locale
+ + ", " + scs.getLocale());
}
+ // 3. Use the user specified spell check language
+ return scs;
}
- // 4. Fall back to the applicable language and return it if not null
- // 5. Simply just return it even if it's null which means we could find no suitable
- // spell check languages
- return candidate;
}
+ // 4. Fall back to the applicable language and return it if not null
+ // 5. Simply just return it even if it's null which means we could find no suitable
+ // spell check languages
+ return candidate;
}
@Override
diff --git a/services/core/java/com/android/server/accounts/AccountManagerBackupHelper.java b/services/core/java/com/android/server/accounts/AccountManagerBackupHelper.java
new file mode 100644
index 000000000000..f4511d28ba46
--- /dev/null
+++ b/services/core/java/com/android/server/accounts/AccountManagerBackupHelper.java
@@ -0,0 +1,312 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.accounts;
+
+import android.accounts.Account;
+import android.accounts.AccountManager;
+import android.accounts.AccountManagerInternal;
+import android.annotation.IntRange;
+import android.annotation.NonNull;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.database.Cursor;
+import android.database.sqlite.SQLiteDatabase;
+import android.os.UserHandle;
+import android.text.TextUtils;
+import android.util.Log;
+import android.util.PackageUtils;
+import android.util.Xml;
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.content.PackageMonitor;
+import com.android.internal.util.FastXmlSerializer;
+import com.android.internal.util.XmlUtils;
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlSerializer;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Helper class for backup and restore of account access grants.
+ */
+public final class AccountManagerBackupHelper {
+ private static final String TAG = "AccountManagerBackupHelper";
+
+ private static final long PENDING_RESTORE_TIMEOUT_MILLIS = 60 * 60 * 1000; // 1 hour
+
+ private static final String TAG_PERMISSIONS = "permissions";
+ private static final String TAG_PERMISSION = "permission";
+ private static final String ATTR_ACCOUNT_SHA_256 = "account-sha-256";
+ private static final String ATTR_PACKAGE = "package";
+ private static final String ATTR_DIGEST = "digest";
+
+ private static final String ACCOUNT_ACCESS_GRANTS = ""
+ + "SELECT " + AccountManagerService.ACCOUNTS_NAME + ", "
+ + AccountManagerService.GRANTS_GRANTEE_UID
+ + " FROM " + AccountManagerService.TABLE_ACCOUNTS
+ + ", " + AccountManagerService.TABLE_GRANTS
+ + " WHERE " + AccountManagerService.GRANTS_ACCOUNTS_ID
+ + "=" + AccountManagerService.ACCOUNTS_ID;
+
+ private final Object mLock = new Object();
+
+ private final AccountManagerService mAccountManagerService;
+ private final AccountManagerInternal mAccountManagerInternal;
+
+ @GuardedBy("mLock")
+ private List<PendingAppPermission> mRestorePendingAppPermissions;
+
+ @GuardedBy("mLock")
+ private RestorePackageMonitor mRestorePackageMonitor;
+
+ @GuardedBy("mLock")
+ private Runnable mRestoreCancelCommand;
+
+ public AccountManagerBackupHelper(AccountManagerService accountManagerService,
+ AccountManagerInternal accountManagerInternal) {
+ mAccountManagerService = accountManagerService;
+ mAccountManagerInternal = accountManagerInternal;
+ }
+
+ private final class PendingAppPermission {
+ private final @NonNull String accountDigest;
+ private final @NonNull String packageName;
+ private final @NonNull String certDigest;
+ private final @IntRange(from = 0) int userId;
+
+ public PendingAppPermission(String accountDigest, String packageName,
+ String certDigest, int userId) {
+ this.accountDigest = accountDigest;
+ this.packageName = packageName;
+ this.certDigest = certDigest;
+ this.userId = userId;
+ }
+
+ public boolean apply(PackageManager packageManager) {
+ Account account = null;
+ AccountManagerService.UserAccounts accounts = mAccountManagerService
+ .getUserAccounts(userId);
+ synchronized (accounts.cacheLock) {
+ for (Account[] accountsPerType : accounts.accountCache.values()) {
+ for (Account accountPerType : accountsPerType) {
+ if (accountDigest.equals(PackageUtils.computeSha256Digest(
+ accountPerType.name.getBytes()))) {
+ account = accountPerType;
+ break;
+ }
+ }
+ if (account != null) {
+ break;
+ }
+ }
+ }
+ if (account == null) {
+ return false;
+ }
+ final PackageInfo packageInfo;
+ try {
+ packageInfo = packageManager.getPackageInfoAsUser(packageName,
+ PackageManager.GET_SIGNATURES, userId);
+ } catch (PackageManager.NameNotFoundException e) {
+ return false;
+ }
+ String currentCertDigest = PackageUtils.computeCertSha256Digest(
+ packageInfo.signatures[0]);
+ if (!certDigest.equals(currentCertDigest)) {
+ return false;
+ }
+ final int uid = packageInfo.applicationInfo.uid;
+ if (!mAccountManagerInternal.hasAccountAccess(account, uid)) {
+ mAccountManagerService.grantAppPermission(account,
+ AccountManager.ACCOUNT_ACCESS_TOKEN_TYPE, uid);
+ }
+ return true;
+ }
+ }
+
+ public byte[] backupAccountAccessPermissions(int userId) {
+ final AccountManagerService.UserAccounts accounts = mAccountManagerService
+ .getUserAccounts(userId);
+ synchronized (accounts.cacheLock) {
+ SQLiteDatabase db = accounts.openHelper.getReadableDatabase();
+ try (
+ Cursor cursor = db.rawQuery(ACCOUNT_ACCESS_GRANTS, null);
+ ) {
+ if (cursor == null || !cursor.moveToFirst()) {
+ return null;
+ }
+
+ final int nameColumnIdx = cursor.getColumnIndex(
+ AccountManagerService.ACCOUNTS_NAME);
+ final int uidColumnIdx = cursor.getColumnIndex(
+ AccountManagerService.GRANTS_GRANTEE_UID);
+
+ ByteArrayOutputStream dataStream = new ByteArrayOutputStream();
+ try {
+ final XmlSerializer serializer = new FastXmlSerializer();
+ serializer.setOutput(dataStream, StandardCharsets.UTF_8.name());
+ serializer.startDocument(null, true);
+ serializer.startTag(null, TAG_PERMISSIONS);
+
+ PackageManager packageManager = mAccountManagerService.mContext
+ .getPackageManager();
+
+ do {
+ final String accountName = cursor.getString(nameColumnIdx);
+ final int uid = cursor.getInt(uidColumnIdx);
+
+ final String[] packageNames = packageManager.getPackagesForUid(uid);
+ if (packageNames == null) {
+ continue;
+ }
+
+ for (String packageName : packageNames) {
+ String digest = PackageUtils.computePackageCertSha256Digest(
+ packageManager, packageName, userId);
+ if (digest != null) {
+ serializer.startTag(null, TAG_PERMISSION);
+ serializer.attribute(null, ATTR_ACCOUNT_SHA_256,
+ PackageUtils.computeSha256Digest(accountName.getBytes()));
+ serializer.attribute(null, ATTR_PACKAGE, packageName);
+ serializer.attribute(null, ATTR_DIGEST, digest);
+ serializer.endTag(null, TAG_PERMISSION);
+ }
+ }
+ } while (cursor.moveToNext());
+
+ serializer.endTag(null, TAG_PERMISSIONS);
+ serializer.endDocument();
+ serializer.flush();
+ } catch (IOException e) {
+ Log.e(TAG, "Error backing up account access grants", e);
+ return null;
+ }
+
+ return dataStream.toByteArray();
+ }
+ }
+ }
+
+ public void restoreAccountAccessPermissions(byte[] data, int userId) {
+ try {
+ ByteArrayInputStream dataStream = new ByteArrayInputStream(data);
+ XmlPullParser parser = Xml.newPullParser();
+ parser.setInput(dataStream, StandardCharsets.UTF_8.name());
+ PackageManager packageManager = mAccountManagerService.mContext.getPackageManager();
+
+ final int permissionsOuterDepth = parser.getDepth();
+ while (XmlUtils.nextElementWithin(parser, permissionsOuterDepth)) {
+ if (!TAG_PERMISSIONS.equals(parser.getName())) {
+ continue;
+ }
+ final int permissionOuterDepth = parser.getDepth();
+ while (XmlUtils.nextElementWithin(parser, permissionOuterDepth)) {
+ if (!TAG_PERMISSION.equals(parser.getName())) {
+ continue;
+ }
+ String accountDigest = parser.getAttributeValue(null, ATTR_ACCOUNT_SHA_256);
+ if (TextUtils.isEmpty(accountDigest)) {
+ XmlUtils.skipCurrentTag(parser);
+ }
+ String packageName = parser.getAttributeValue(null, ATTR_PACKAGE);
+ if (TextUtils.isEmpty(packageName)) {
+ XmlUtils.skipCurrentTag(parser);
+ }
+ String digest = parser.getAttributeValue(null, ATTR_DIGEST);
+ if (TextUtils.isEmpty(digest)) {
+ XmlUtils.skipCurrentTag(parser);
+ }
+
+ PendingAppPermission pendingAppPermission = new PendingAppPermission(
+ accountDigest, packageName, digest, userId);
+
+ if (!pendingAppPermission.apply(packageManager)) {
+ synchronized (mLock) {
+ // Start watching before add pending to avoid a missed signal
+ if (mRestorePackageMonitor == null) {
+ mRestorePackageMonitor = new RestorePackageMonitor();
+ mRestorePackageMonitor.register(mAccountManagerService.mContext,
+ mAccountManagerService.mHandler.getLooper(), true);
+ }
+ if (mRestorePendingAppPermissions == null) {
+ mRestorePendingAppPermissions = new ArrayList<>();
+ }
+ mRestorePendingAppPermissions.add(pendingAppPermission);
+ }
+ }
+ }
+ }
+
+ // Make sure we eventually prune the in-memory pending restores
+ mRestoreCancelCommand = new CancelRestoreCommand();
+ mAccountManagerService.mHandler.postDelayed(mRestoreCancelCommand,
+ PENDING_RESTORE_TIMEOUT_MILLIS);
+ } catch (XmlPullParserException | IOException e) {
+ Log.e(TAG, "Error restoring app permissions", e);
+ }
+ }
+
+ private final class RestorePackageMonitor extends PackageMonitor {
+ @Override
+ public void onPackageAdded(String packageName, int uid) {
+ synchronized (mLock) {
+ if (mRestorePendingAppPermissions == null) {
+ return;
+ }
+ if (UserHandle.getUserId(uid) != UserHandle.USER_SYSTEM) {
+ return;
+ }
+ final int count = mRestorePendingAppPermissions.size();
+ for (int i = count - 1; i >= 0; i--) {
+ PendingAppPermission pendingAppPermission =
+ mRestorePendingAppPermissions.get(i);
+ if (!pendingAppPermission.packageName.equals(packageName)) {
+ continue;
+ }
+ if (pendingAppPermission.apply(
+ mAccountManagerService.mContext.getPackageManager())) {
+ mRestorePendingAppPermissions.remove(i);
+ }
+ }
+ if (mRestorePendingAppPermissions.isEmpty()
+ && mRestoreCancelCommand != null) {
+ mAccountManagerService.mHandler.removeCallbacks(mRestoreCancelCommand);
+ mRestoreCancelCommand.run();
+ mRestoreCancelCommand = null;
+ }
+ }
+ }
+ }
+
+ private final class CancelRestoreCommand implements Runnable {
+ @Override
+ public void run() {
+ synchronized (mLock) {
+ mRestorePendingAppPermissions = null;
+ if (mRestorePackageMonitor != null) {
+ mRestorePackageMonitor.unregister();
+ mRestorePackageMonitor = null;
+ }
+ }
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java
index b152372d092d..04c15c8983cc 100644
--- a/services/core/java/com/android/server/accounts/AccountManagerService.java
+++ b/services/core/java/com/android/server/accounts/AccountManagerService.java
@@ -26,12 +26,14 @@ import android.accounts.AccountManagerInternal;
import android.accounts.AuthenticatorDescription;
import android.accounts.CantAddAccountActivity;
import android.accounts.GrantCredentialsPermissionActivity;
+import android.accounts.IAccountAccessTracker;
import android.accounts.IAccountAuthenticator;
import android.accounts.IAccountAuthenticatorResponse;
import android.accounts.IAccountManager;
import android.accounts.IAccountManagerResponse;
import android.annotation.IntRange;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.app.ActivityManager;
import android.app.ActivityManagerNative;
import android.app.ActivityThread;
@@ -87,12 +89,14 @@ import android.os.UserManager;
import android.os.storage.StorageManager;
import android.text.TextUtils;
import android.util.Log;
+import android.util.PackageUtils;
import android.util.Pair;
import android.util.Slog;
import android.util.SparseArray;
import android.util.SparseBooleanArray;
import com.android.internal.R;
+import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.content.PackageMonitor;
import com.android.internal.util.ArrayUtils;
@@ -120,11 +124,11 @@ import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
-import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
+import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
@@ -155,13 +159,6 @@ public class AccountManagerService
}
@Override
- public void onBootPhase(int phase) {
- if (phase == SystemService.PHASE_ACTIVITY_MANAGER_READY) {
- mService.systemReady();
- }
- }
-
- @Override
public void onUnlockUser(int userHandle) {
mService.onUnlockUser(userHandle);
}
@@ -174,13 +171,13 @@ public class AccountManagerService
private static final int MAX_DEBUG_DB_SIZE = 64;
- private final Context mContext;
+ final Context mContext;
private final PackageManager mPackageManager;
private final AppOpsManager mAppOpsManager;
private UserManager mUserManager;
- private final MessageHandler mHandler;
+ final MessageHandler mHandler;
// Messages that can be sent on mHandler
private static final int MESSAGE_TIMED_OUT = 3;
@@ -188,9 +185,9 @@ public class AccountManagerService
private final IAccountAuthenticatorCache mAuthenticatorCache;
- private static final String TABLE_ACCOUNTS = "accounts";
- private static final String ACCOUNTS_ID = "_id";
- private static final String ACCOUNTS_NAME = "name";
+ static final String TABLE_ACCOUNTS = "accounts";
+ static final String ACCOUNTS_ID = "_id";
+ static final String ACCOUNTS_NAME = "name";
private static final String ACCOUNTS_TYPE = "type";
private static final String ACCOUNTS_TYPE_COUNT = "count(type)";
private static final String ACCOUNTS_PASSWORD = "password";
@@ -204,10 +201,10 @@ public class AccountManagerService
private static final String AUTHTOKENS_TYPE = "type";
private static final String AUTHTOKENS_AUTHTOKEN = "authtoken";
- private static final String TABLE_GRANTS = "grants";
- private static final String GRANTS_ACCOUNTS_ID = "accounts_id";
+ static final String TABLE_GRANTS = "grants";
+ static final String GRANTS_ACCOUNTS_ID = "accounts_id";
private static final String GRANTS_AUTH_TOKEN_TYPE = "auth_token_type";
- private static final String GRANTS_GRANTEE_UID = "uid";
+ static final String GRANTS_GRANTEE_UID = "uid";
private static final String TABLE_EXTRAS = "extras";
private static final String EXTRAS_ID = "_id";
@@ -276,16 +273,16 @@ public class AccountManagerService
static class UserAccounts {
private final int userId;
- private final DeDatabaseHelper openHelper;
+ final DeDatabaseHelper openHelper;
private final HashMap<Pair<Pair<Account, String>, Integer>, Integer>
credentialsPermissionNotificationIds =
new HashMap<Pair<Pair<Account, String>, Integer>, Integer>();
private final HashMap<Account, Integer> signinRequiredNotificationIds =
new HashMap<Account, Integer>();
- private final Object cacheLock = new Object();
+ final Object cacheLock = new Object();
/** protected by the {@link #cacheLock} */
- private final HashMap<String, Account[]> accountCache =
- new LinkedHashMap<String, Account[]>();
+ final HashMap<String, Account[]> accountCache =
+ new LinkedHashMap<>();
/** protected by the {@link #cacheLock} */
private final Map<Account, Map<String, String>> userDataCache = new HashMap<>();
/** protected by the {@link #cacheLock} */
@@ -337,6 +334,8 @@ public class AccountManagerService
private final SparseArray<UserAccounts> mUsers = new SparseArray<>();
private final SparseBooleanArray mLocalUnlockedUsers = new SparseBooleanArray();
+ private CopyOnWriteArrayList<AccountManagerInternal.OnAppPermissionChangeListener>
+ mAppPermissionChangeListeners = new CopyOnWriteArrayList<>();
private static AtomicReference<AccountManagerService> sThis = new AtomicReference<>();
private static final Account[] EMPTY_ACCOUNT_ARRAY = new Account[]{};
@@ -560,7 +559,7 @@ public class AccountManagerService
if (!checkAccess || hasAccountAccess(account, packageName,
UserHandle.getUserHandleForUid(uid))) {
cancelNotification(getCredentialPermissionNotificationId(account,
- AccountManager.ACCOUNT_ACCESS_TOKEN, uid), packageName,
+ AccountManager.ACCOUNT_ACCESS_TOKEN_TYPE, uid), packageName,
UserHandle.getUserHandleForUid(uid));
}
}
@@ -1056,9 +1055,6 @@ public class AccountManagerService
}
}
- public void systemReady() {
- }
-
private UserManager getUserManager() {
if (mUserManager == null) {
mUserManager = UserManager.get(mContext);
@@ -1196,7 +1192,8 @@ public class AccountManagerService
final ArrayList<String> accountNames = cur.getValue();
final Account[] accountsForType = new Account[accountNames.size()];
for (int i = 0; i < accountsForType.length; i++) {
- accountsForType[i] = new Account(accountNames.get(i), accountType);
+ accountsForType[i] = new Account(accountNames.get(i), accountType,
+ new AccountAccessTracker());
}
accounts.accountCache.put(accountType, accountsForType);
}
@@ -1977,6 +1974,8 @@ public class AccountManagerService
Bundle result = new Bundle();
result.putString(AccountManager.KEY_ACCOUNT_NAME, resultingAccount.name);
result.putString(AccountManager.KEY_ACCOUNT_TYPE, resultingAccount.type);
+ result.putBinder(AccountManager.KEY_ACCOUNT_ACCESS_TRACKER,
+ resultingAccount.getAccessTracker().asBinder());
try {
response.onResult(result);
} catch (RemoteException e) {
@@ -2035,8 +2034,10 @@ public class AccountManagerService
/*
* Database transaction was successful. Clean up cached
* data associated with the account in the user profile.
+ * The account is now being tracked for remote access.
*/
- insertAccountIntoCacheLocked(accounts, renamedAccount);
+ renamedAccount = insertAccountIntoCacheLocked(accounts, renamedAccount);
+
/*
* Extract the data and token caches before removing the
* old account to preserve the user data associated with
@@ -2324,7 +2325,7 @@ public class AccountManagerService
for (Pair<Pair<Account, String>, Integer> key
: accounts.credentialsPermissionNotificationIds.keySet()) {
if (account.equals(key.first.first)
- && AccountManager.ACCOUNT_ACCESS_TOKEN.equals(key.first.second)) {
+ && AccountManager.ACCOUNT_ACCESS_TOKEN_TYPE.equals(key.first.second)) {
final int uid = (Integer) key.second;
mHandler.post(() -> cancelAccountAccessRequestNotificationIfNeeded(
account, uid, false));
@@ -3887,22 +3888,36 @@ public class AccountManagerService
Preconditions.checkArgumentInRange(userId, 0, Integer.MAX_VALUE, "user must be concrete");
try {
-
final int uid = mPackageManager.getPackageUidAsUser(packageName, userId);
- // Use null token which means any token. Having a token means the package
- // is trusted by the authenticator, hence it is fine to access the account.
- if (permissionIsGranted(account, null, uid, userId)) {
- return true;
- }
- // In addition to the permissions required to get an auth token we also allow
- // the account to be accessed by holders of the get accounts permissions.
- return checkUidPermission(Manifest.permission.GET_ACCOUNTS_PRIVILEGED, uid, packageName)
- || checkUidPermission(Manifest.permission.GET_ACCOUNTS, uid, packageName);
+ return hasAccountAccess(account, packageName, uid);
} catch (NameNotFoundException e) {
return false;
}
}
+ private boolean hasAccountAccess(@NonNull Account account, @Nullable String packageName,
+ int uid) {
+ if (packageName == null) {
+ String[] packageNames = mPackageManager.getPackagesForUid(uid);
+ if (ArrayUtils.isEmpty(packageNames)) {
+ return false;
+ }
+ // For app op checks related to permissions all packages in the UID
+ // have the same app op state, so doesn't matter which one we pick.
+ packageName = packageNames[0];
+ }
+
+ // Use null token which means any token. Having a token means the package
+ // is trusted by the authenticator, hence it is fine to access the account.
+ if (permissionIsGranted(account, null, uid, UserHandle.getUserId(uid))) {
+ return true;
+ }
+ // In addition to the permissions required to get an auth token we also allow
+ // the account to be accessed by holders of the get accounts permissions.
+ return checkUidPermission(Manifest.permission.GET_ACCOUNTS_PRIVILEGED, uid, packageName)
+ || checkUidPermission(Manifest.permission.GET_ACCOUNTS, uid, packageName);
+ }
+
private boolean checkUidPermission(String permission, int uid, String opPackageName) {
final long identity = Binder.clearCallingIdentity();
try {
@@ -3978,7 +3993,7 @@ public class AccountManagerService
private void handleAuthenticatorResponse(boolean accessGranted) throws RemoteException {
cancelNotification(getCredentialPermissionNotificationId(account,
- AccountManager.ACCOUNT_ACCESS_TOKEN, uid), packageName,
+ AccountManager.ACCOUNT_ACCESS_TOKEN_TYPE, uid), packageName,
UserHandle.getUserHandleForUid(uid));
if (callback != null) {
Bundle result = new Bundle();
@@ -3986,7 +4001,7 @@ public class AccountManagerService
callback.sendResult(result);
}
}
- }), AccountManager.ACCOUNT_ACCESS_TOKEN, false);
+ }), AccountManager.ACCOUNT_ACCESS_TOKEN_TYPE, false);
}
@Override
@@ -4809,7 +4824,7 @@ public class AccountManagerService
}
}
- private class MessageHandler extends Handler {
+ class MessageHandler extends Handler {
MessageHandler(Looper looper) {
super(looper);
}
@@ -5922,7 +5937,7 @@ public class AccountManagerService
* which is in the system. This means we don't need to protect it with permissions.
* @hide
*/
- private void grantAppPermission(Account account, String authTokenType, int uid) {
+ void grantAppPermission(Account account, String authTokenType, int uid) {
if (account == null || authTokenType == null) {
Log.e(TAG, "grantAppPermission: called with invalid arguments", new Exception());
return;
@@ -5939,6 +5954,12 @@ public class AccountManagerService
cancelAccountAccessRequestNotificationIfNeeded(account, uid, true);
}
+
+ // Listeners are a final CopyOnWriteArrayList, hence no lock needed.
+ for (AccountManagerInternal.OnAppPermissionChangeListener listener
+ : mAppPermissionChangeListeners) {
+ mHandler.post(() -> listener.onAppPermissionChanged(account, uid));
+ }
}
/**
@@ -5968,9 +5989,16 @@ public class AccountManagerService
} finally {
db.endTransaction();
}
+
cancelNotification(getCredentialPermissionNotificationId(account, authTokenType, uid),
new UserHandle(accounts.userId));
}
+
+ // Listeners are a final CopyOnWriteArrayList, hence no lock needed.
+ for (AccountManagerInternal.OnAppPermissionChangeListener listener
+ : mAppPermissionChangeListeners) {
+ mHandler.post(() -> listener.onAppPermissionChanged(account, uid));
+ }
}
static final private String stringArrayToString(String[] value) {
@@ -6001,16 +6029,22 @@ public class AccountManagerService
/**
* This assumes that the caller has already checked that the account is not already present.
+ * IMPORTANT: The account being inserted will begin to be tracked for access in remote
+ * processes and if you will return this account to apps you should return the result.
+ * @return The inserted account which is a new instance that is being tracked.
*/
- private void insertAccountIntoCacheLocked(UserAccounts accounts, Account account) {
+ private Account insertAccountIntoCacheLocked(UserAccounts accounts, Account account) {
Account[] accountsForType = accounts.accountCache.get(account.type);
int oldLength = (accountsForType != null) ? accountsForType.length : 0;
Account[] newAccountsForType = new Account[oldLength + 1];
if (accountsForType != null) {
System.arraycopy(accountsForType, 0, newAccountsForType, 0, oldLength);
}
- newAccountsForType[oldLength] = account;
+ IAccountAccessTracker accessTracker = account.getAccessTracker() != null
+ ? account.getAccessTracker() : new AccountAccessTracker();
+ newAccountsForType[oldLength] = new Account(account, accessTracker);
accounts.accountCache.put(account.type, newAccountsForType);
+ return newAccountsForType[oldLength];
}
private Account[] filterSharedAccounts(UserAccounts userAccounts, Account[] unfiltered,
@@ -6626,7 +6660,39 @@ public class AccountManagerService
}
}
+ private final class AccountAccessTracker extends IAccountAccessTracker.Stub {
+ @Override
+ public void onAccountAccessed() throws RemoteException {
+ final int uid = Binder.getCallingUid();
+ if (UserHandle.getAppId(uid) == Process.SYSTEM_UID) {
+ return;
+ }
+ final int userId = UserHandle.getCallingUserId();
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ for (Account account : getAccounts(userId, mContext.getOpPackageName())) {
+ IAccountAccessTracker accountTracker = account.getAccessTracker();
+ if (accountTracker != null && asBinder() == accountTracker.asBinder()) {
+ // An app just accessed the account. At this point it knows about
+ // it and there is not need to hide this account from the app.
+ if (!hasAccountAccess(account, null, uid)) {
+ updateAppPermission(account, AccountManager.ACCOUNT_ACCESS_TOKEN_TYPE,
+ uid, true);
+ }
+ }
+ }
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+ }
+
private final class AccountManagerInternalImpl extends AccountManagerInternal {
+ private final Object mLock = new Object();
+
+ @GuardedBy("mLock")
+ private AccountManagerBackupHelper mBackupHelper;
+
@Override
public void requestAccountAccess(@NonNull Account account, @NonNull String packageName,
@IntRange(from = 0) int userId, @NonNull RemoteCallback callback) {
@@ -6647,7 +6713,8 @@ public class AccountManagerService
return;
}
- if (hasAccountAccess(account, packageName, new UserHandle(userId))) {
+ if (AccountManagerService.this.hasAccountAccess(account, packageName,
+ new UserHandle(userId))) {
Bundle result = new Bundle();
result.putBoolean(AccountManager.KEY_BOOLEAN_RESULT, true);
callback.sendResult(result);
@@ -6663,7 +6730,44 @@ public class AccountManagerService
}
Intent intent = newRequestAccountAccessIntent(account, packageName, uid, callback);
- doNotification(mUsers.get(userId), account, null, intent, packageName, userId);
+ final UserAccounts userAccounts;
+ synchronized (mUsers) {
+ userAccounts = mUsers.get(userId);
+ }
+ doNotification(userAccounts, account, null, intent, packageName, userId);
+ }
+
+ @Override
+ public void addOnAppPermissionChangeListener(OnAppPermissionChangeListener listener) {
+ // Listeners are a final CopyOnWriteArrayList, hence no lock needed.
+ mAppPermissionChangeListeners.add(listener);
+ }
+
+ @Override
+ public boolean hasAccountAccess(@NonNull Account account, @IntRange(from = 0) int uid) {
+ return AccountManagerService.this.hasAccountAccess(account, null, uid);
+ }
+
+ @Override
+ public byte[] backupAccountAccessPermissions(int userId) {
+ synchronized (mLock) {
+ if (mBackupHelper == null) {
+ mBackupHelper = new AccountManagerBackupHelper(
+ AccountManagerService.this, this);
+ }
+ return mBackupHelper.backupAccountAccessPermissions(userId);
+ }
+ }
+
+ @Override
+ public void restoreAccountAccessPermissions(byte[] data, int userId) {
+ synchronized (mLock) {
+ if (mBackupHelper == null) {
+ mBackupHelper = new AccountManagerBackupHelper(
+ AccountManagerService.this, this);
+ }
+ mBackupHelper.restoreAccountAccessPermissions(data, userId);
+ }
}
}
}
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index aa536768b6ea..0c8532924af3 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -16,6 +16,7 @@
package com.android.server.am;
+import android.os.IDeviceIdentifiersPolicyService;
import com.android.internal.telephony.TelephonyIntents;
import com.google.android.collect.Lists;
import com.google.android.collect.Maps;
@@ -1125,11 +1126,14 @@ public final class ActivityManagerService extends ActivityManagerNative
*/
Configuration mGlobalConfiguration = new Configuration();
+ /** Current sequencing integer of the configuration, for skipping old configurations. */
+ private int mConfigurationSeq;
+
/**
- * Current sequencing integer of the configuration, for skipping old
- * configurations.
+ * Temp object used when global configuration is updated. It is also sent to outer world
+ * instead of {@link #mGlobalConfiguration} because we don't trust anyone...
*/
- private int mConfigurationSeq;
+ private Configuration mTempGlobalConfig = new Configuration();
boolean mSuppressResizeConfigChanges;
@@ -2291,6 +2295,9 @@ public final class ActivityManagerService extends ActivityManagerNative
} break;
case VR_MODE_CHANGE_MSG: {
VrManagerInternal vrService = LocalServices.getService(VrManagerInternal.class);
+ if (vrService == null) {
+ break;
+ }
final ActivityRecord r = (ActivityRecord) msg.obj;
boolean vrMode;
ComponentName requestedPackage;
@@ -6519,6 +6526,17 @@ public final class ActivityManagerService extends ActivityManagerNative
}
ProfilerInfo profilerInfo = profileFile == null ? null
: new ProfilerInfo(profileFile, profileFd, samplingInterval, profileAutoStop);
+
+ // We deprecated Build.SERIAL and only apps that target pre NMR1
+ // SDK can see it. Since access to the serial is now behind a
+ // permission we push down the value.
+ String buildSerial = Build.UNKNOWN;
+ if (appInfo.targetSdkVersion <= Build.VERSION_CODES.N_MR1) {
+ buildSerial = IDeviceIdentifiersPolicyService.Stub.asInterface(
+ ServiceManager.getService(Context.DEVICE_IDENTIFIERS_SERVICE))
+ .getSerial();
+ }
+
thread.bindApplication(processName, appInfo, providers, app.instrumentationClass,
profilerInfo, app.instrumentationArguments, app.instrumentationWatcher,
app.instrumentationUiAutomationConnection, testMode,
@@ -6526,7 +6544,9 @@ public final class ActivityManagerService extends ActivityManagerNative
isRestrictedBackupMode || !normalMode, app.persistent,
new Configuration(mGlobalConfiguration), app.compat,
getCommonServicesLocked(app.isolated),
- mCoreSettingsObserver.getCoreSettingsLocked());
+ mCoreSettingsObserver.getCoreSettingsLocked(),
+ buildSerial);
+
updateLruProcessLocked(app, false, null);
app.lastRequestedGc = app.lastLowMemory = SystemClock.uptimeMillis();
} catch (Exception e) {
@@ -18833,6 +18853,7 @@ public final class ActivityManagerService extends ActivityManagerNative
throw new SecurityException(msg);
}
+ @Override
public void updateConfiguration(Configuration values) {
enforceCallingPermission(android.Manifest.permission.CHANGE_CONFIGURATION,
"updateConfiguration()");
@@ -18857,10 +18878,12 @@ public final class ActivityManagerService extends ActivityManagerNative
}
void updateUserConfigurationLocked() {
- Configuration configuration = new Configuration(mGlobalConfiguration);
+ final Configuration configuration = new Configuration(mGlobalConfiguration);
+ final int currentUserId = mUserController.getCurrentUserIdLocked();
Settings.System.adjustConfigurationForUser(mContext.getContentResolver(), configuration,
- mUserController.getCurrentUserIdLocked(), Settings.System.canWrite(mContext));
- updateConfigurationLocked(configuration, null, false);
+ currentUserId, Settings.System.canWrite(mContext));
+ updateConfigurationLocked(configuration, null /* starting */, false /* initLocale */,
+ false /* persistent */, currentUserId, false /* deferResume */);
}
boolean updateConfigurationLocked(Configuration values, ActivityRecord starting,
@@ -18891,130 +18914,147 @@ public final class ActivityManagerService extends ActivityManagerNative
private boolean updateConfigurationLocked(Configuration values, ActivityRecord starting,
boolean initLocale, boolean persistent, int userId, boolean deferResume) {
int changes = 0;
+ boolean kept = true;
if (mWindowManager != null) {
mWindowManager.deferSurfaceLayout();
}
- if (values != null) {
- Configuration newConfig = new Configuration(mGlobalConfiguration);
- changes = newConfig.updateFrom(values);
- if (changes != 0) {
- if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.i(TAG_CONFIGURATION,
- "Updating configuration to: " + values);
-
- EventLog.writeEvent(EventLogTags.CONFIGURATION_CHANGED, changes);
-
- if (!initLocale && !values.getLocales().isEmpty() && values.userSetLocale) {
- final LocaleList locales = values.getLocales();
- int bestLocaleIndex = 0;
- if (locales.size() > 1) {
- if (mSupportedSystemLocales == null) {
- mSupportedSystemLocales =
- Resources.getSystem().getAssets().getLocales();
- }
- bestLocaleIndex = Math.max(0,
- locales.getFirstMatchIndex(mSupportedSystemLocales));
- }
- SystemProperties.set("persist.sys.locale",
- locales.get(bestLocaleIndex).toLanguageTag());
- LocaleList.setDefault(locales, bestLocaleIndex);
- mHandler.sendMessage(mHandler.obtainMessage(SEND_LOCALE_TO_MOUNT_DAEMON_MSG,
- locales.get(bestLocaleIndex)));
- }
+ try {
+ if (values != null) {
+ changes = updateGlobalConfiguration(values, initLocale, persistent, userId,
+ deferResume);
+ }
- mConfigurationSeq++;
- if (mConfigurationSeq <= 0) {
- mConfigurationSeq = 1;
- }
- newConfig.seq = mConfigurationSeq;
- mGlobalConfiguration = newConfig;
- Slog.i(TAG, "Config changes=" + Integer.toHexString(changes) + " " + newConfig);
- mUsageStatsService.reportConfigurationChange(newConfig,
- mUserController.getCurrentUserIdLocked());
- //mUsageStatsService.noteStartConfig(newConfig);
+ kept = ensureConfigAndVisibilityAfterUpdate(starting, changes);
+ } finally {
+ if (mWindowManager != null) {
+ mWindowManager.continueSurfaceLayout();
+ }
+ }
+ return kept;
+ }
- final Configuration configCopy = new Configuration(mGlobalConfiguration);
+ /** Update default (global) configuration and notify listeners about changes. */
+ private int updateGlobalConfiguration(@NonNull Configuration values, boolean initLocale,
+ boolean persistent, int userId, boolean deferResume) {
+ mTempGlobalConfig.setTo(mGlobalConfiguration);
+ final int changes = mTempGlobalConfig.updateFrom(values);
+ if (changes == 0) {
+ return 0;
+ }
- // TODO: If our config changes, should we auto dismiss any currently
- // showing dialogs?
- mShowDialogs = shouldShowDialogs(newConfig, mInVrMode);
+ if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.i(TAG_CONFIGURATION,
+ "Updating global configuration to: " + values);
- AttributeCache ac = AttributeCache.instance();
- if (ac != null) {
- ac.updateConfiguration(configCopy);
+ EventLog.writeEvent(EventLogTags.CONFIGURATION_CHANGED, changes);
+
+ if (!initLocale && !values.getLocales().isEmpty() && values.userSetLocale) {
+ final LocaleList locales = values.getLocales();
+ int bestLocaleIndex = 0;
+ if (locales.size() > 1) {
+ if (mSupportedSystemLocales == null) {
+ mSupportedSystemLocales = Resources.getSystem().getAssets().getLocales();
}
+ bestLocaleIndex = Math.max(0, locales.getFirstMatchIndex(mSupportedSystemLocales));
+ }
+ SystemProperties.set("persist.sys.locale",
+ locales.get(bestLocaleIndex).toLanguageTag());
+ LocaleList.setDefault(locales, bestLocaleIndex);
+ mHandler.sendMessage(mHandler.obtainMessage(SEND_LOCALE_TO_MOUNT_DAEMON_MSG,
+ locales.get(bestLocaleIndex)));
+ }
- // Make sure all resources in our process are updated
- // right now, so that anyone who is going to retrieve
- // resource values after we return will be sure to get
- // the new ones. This is especially important during
- // boot, where the first config change needs to guarantee
- // all resources have that config before following boot
- // code is executed.
- mSystemThread.applyConfigurationToResources(configCopy);
+ mConfigurationSeq = Math.max(++mConfigurationSeq, 1);
+ mTempGlobalConfig.seq = mConfigurationSeq;
- if (persistent && Settings.System.hasInterestingConfigurationChanges(changes)) {
- Message msg = mHandler.obtainMessage(UPDATE_CONFIGURATION_MSG);
- msg.obj = new Configuration(configCopy);
- msg.arg1 = userId;
- mHandler.sendMessage(msg);
- }
+ mGlobalConfiguration.setTo(mTempGlobalConfig);
+ Slog.i(TAG, "Config changes=" + Integer.toHexString(changes) + " " + mTempGlobalConfig);
+ // TODO(multi-display): Update UsageEvents#Event to include displayId.
+ mUsageStatsService.reportConfigurationChange(mTempGlobalConfig,
+ mUserController.getCurrentUserIdLocked());
- final boolean isDensityChange = (changes & ActivityInfo.CONFIG_DENSITY) != 0;
- if (isDensityChange) {
- // Reset the unsupported display size dialog.
- mUiHandler.sendEmptyMessage(SHOW_UNSUPPORTED_DISPLAY_SIZE_DIALOG_MSG);
+ // TODO: If our config changes, should we auto dismiss any currently showing dialogs?
+ mShowDialogs = shouldShowDialogs(mTempGlobalConfig, mInVrMode);
- killAllBackgroundProcessesExcept(Build.VERSION_CODES.N,
- ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE);
- }
+ AttributeCache ac = AttributeCache.instance();
+ if (ac != null) {
+ ac.updateConfiguration(mTempGlobalConfig);
+ }
- for (int i=mLruProcesses.size()-1; i>=0; i--) {
- ProcessRecord app = mLruProcesses.get(i);
- try {
- if (app.thread != null) {
- if (DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION, "Sending to proc "
- + app.processName + " new config " + mGlobalConfiguration);
- app.thread.scheduleConfigurationChanged(configCopy);
- }
- } catch (Exception e) {
- }
+ // Make sure all resources in our process are updated right now, so that anyone who is going
+ // to retrieve resource values after we return will be sure to get the new ones. This is
+ // especially important during boot, where the first config change needs to guarantee all
+ // resources have that config before following boot code is executed.
+ mSystemThread.applyConfigurationToResources(mTempGlobalConfig);
+
+ // We need another copy of global config because we're scheduling some calls instead of
+ // running them in place. We need to be sure that object we send will be handled unchanged.
+ final Configuration configCopy = new Configuration(mGlobalConfiguration);
+ if (persistent && Settings.System.hasInterestingConfigurationChanges(changes)) {
+ Message msg = mHandler.obtainMessage(UPDATE_CONFIGURATION_MSG);
+ msg.obj = configCopy;
+ msg.arg1 = userId;
+ mHandler.sendMessage(msg);
+ }
+
+ // TODO(multi-display): Clear also on secondary display density change?
+ final boolean isDensityChange = (changes & ActivityInfo.CONFIG_DENSITY) != 0;
+ if (isDensityChange) {
+ // Reset the unsupported display size dialog.
+ mUiHandler.sendEmptyMessage(SHOW_UNSUPPORTED_DISPLAY_SIZE_DIALOG_MSG);
+
+ killAllBackgroundProcessesExcept(Build.VERSION_CODES.N,
+ ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE);
+ }
+
+ for (int i = mLruProcesses.size() - 1; i >= 0; i--) {
+ ProcessRecord app = mLruProcesses.get(i);
+ try {
+ if (app.thread != null) {
+ if (DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION, "Sending to proc "
+ + app.processName + " new config " + configCopy);
+ app.thread.scheduleConfigurationChanged(configCopy);
}
- Intent intent = new Intent(Intent.ACTION_CONFIGURATION_CHANGED);
- intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY
- | Intent.FLAG_RECEIVER_REPLACE_PENDING
- | Intent.FLAG_RECEIVER_FOREGROUND);
- broadcastIntentLocked(null, null, intent, null, null, 0, null, null,
- null, AppOpsManager.OP_NONE, null, false, false,
- MY_PID, Process.SYSTEM_UID, UserHandle.USER_ALL);
- if ((changes&ActivityInfo.CONFIG_LOCALE) != 0) {
- intent = new Intent(Intent.ACTION_LOCALE_CHANGED);
- intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
- if (!mProcessesReady) {
- intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
- }
- broadcastIntentLocked(null, null, intent,
- null, null, 0, null, null, null, AppOpsManager.OP_NONE,
- null, false, false, MY_PID, Process.SYSTEM_UID, UserHandle.USER_ALL);
- }
- }
- // Update the configuration with WM first and check if any of the stacks need to be
- // resized due to the configuration change. If so, resize the stacks now and do any
- // relaunches if necessary. This way we don't need to relaunch again below in
- // ensureActivityConfigurationLocked().
- if (mWindowManager != null) {
- final int[] resizedStacks =
- mWindowManager.setNewConfiguration(mGlobalConfiguration);
- if (resizedStacks != null) {
- for (int stackId : resizedStacks) {
- final Rect newBounds = mWindowManager.getBoundsForNewConfiguration(stackId);
- mStackSupervisor.resizeStackLocked(
- stackId, newBounds, null, null, false, false, deferResume);
- }
+ } catch (Exception e) {
+ }
+ }
+
+ Intent intent = new Intent(Intent.ACTION_CONFIGURATION_CHANGED);
+ intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY | Intent.FLAG_RECEIVER_REPLACE_PENDING
+ | Intent.FLAG_RECEIVER_FOREGROUND);
+ broadcastIntentLocked(null, null, intent, null, null, 0, null, null, null,
+ AppOpsManager.OP_NONE, null, false, false, MY_PID, Process.SYSTEM_UID,
+ UserHandle.USER_ALL);
+ if ((changes & ActivityInfo.CONFIG_LOCALE) != 0) {
+ intent = new Intent(Intent.ACTION_LOCALE_CHANGED);
+ intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
+ if (!mProcessesReady) {
+ intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
+ }
+ broadcastIntentLocked(null, null, intent, null, null, 0, null, null, null,
+ AppOpsManager.OP_NONE, null, false, false, MY_PID, Process.SYSTEM_UID,
+ UserHandle.USER_ALL);
+ }
+
+ // Update the configuration with WM first and check if any of the stacks need to be resized
+ // due to the configuration change. If so, resize the stacks now and do any relaunches if
+ // necessary. This way we don't need to relaunch again afterwards in
+ // ensureActivityConfigurationLocked().
+ if (mWindowManager != null) {
+ final int[] resizedStacks =
+ mWindowManager.setNewConfiguration(mTempGlobalConfig);
+ if (resizedStacks != null) {
+ for (int stackId : resizedStacks) {
+ resizeStackWithBoundsFromWindowManager(stackId, deferResume);
}
}
}
+ return changes;
+ }
+
+ /** Applies latest configuration and/or visibility updates if needed. */
+ private boolean ensureConfigAndVisibilityAfterUpdate(ActivityRecord starting, int changes) {
boolean kept = true;
final ActivityStack mainStack = mStackSupervisor.getFocusedStack();
// mainStack is null during startup.
@@ -19034,12 +19074,18 @@ public final class ActivityManagerService extends ActivityManagerNative
!PRESERVE_WINDOWS);
}
}
- if (mWindowManager != null) {
- mWindowManager.continueSurfaceLayout();
- }
+
return kept;
}
+ /** Helper method that requests bounds from WM and applies them to stack. */
+ private void resizeStackWithBoundsFromWindowManager(int stackId, boolean deferResume) {
+ final Rect newBounds = mWindowManager.getBoundsForNewConfiguration(stackId);
+ mStackSupervisor.resizeStackLocked(
+ stackId, newBounds, null /* tempTaskBounds */, null /* tempTaskInsetBounds */,
+ false /* preserveWindows */, false /* allowResizeInDockedMode */, deferResume);
+ }
+
/**
* Decide based on the configuration whether we should show the ANR,
* crash, etc dialogs. The idea is that if there is no affordance to
diff --git a/services/core/java/com/android/server/connectivity/MetricsLoggerService.java b/services/core/java/com/android/server/connectivity/MetricsLoggerService.java
index 05f1a6e6a3a4..168ce858eca5 100644
--- a/services/core/java/com/android/server/connectivity/MetricsLoggerService.java
+++ b/services/core/java/com/android/server/connectivity/MetricsLoggerService.java
@@ -56,8 +56,8 @@ public class MetricsLoggerService extends SystemService {
if (DBG) Log.d(TAG, "onBootPhase: PHASE_SYSTEM_SERVICES_READY");
publishBinderService(ConnectivityMetricsLogger.CONNECTIVITY_METRICS_LOGGER_SERVICE,
mBinder);
- mDnsListener = new DnsEventListenerService(getContext());
- publishBinderService(mDnsListener.SERVICE_NAME, mDnsListener);
+ mNetdListener = new NetdEventListenerService(getContext());
+ publishBinderService(mNetdListener.SERVICE_NAME, mNetdListener);
}
}
@@ -86,7 +86,7 @@ public class MetricsLoggerService extends SystemService {
private final ArrayDeque<ConnectivityMetricsEvent> mEvents = new ArrayDeque<>();
- private DnsEventListenerService mDnsListener;
+ private NetdEventListenerService mNetdListener;
private void enforceConnectivityInternalPermission() {
getContext().enforceCallingOrSelfPermission(
@@ -221,8 +221,8 @@ public class MetricsLoggerService extends SystemService {
}
pw.println();
- if (mDnsListener != null) {
- mDnsListener.dump(pw);
+ if (mNetdListener != null) {
+ mNetdListener.dump(pw);
}
}
diff --git a/services/core/java/com/android/server/connectivity/DnsEventListenerService.java b/services/core/java/com/android/server/connectivity/NetdEventListenerService.java
index 8d206ef90b94..e7198d3e7ee3 100644
--- a/services/core/java/com/android/server/connectivity/DnsEventListenerService.java
+++ b/services/core/java/com/android/server/connectivity/NetdEventListenerService.java
@@ -22,8 +22,8 @@ import android.net.ConnectivityManager.NetworkCallback;
import android.net.Network;
import android.net.NetworkRequest;
import android.net.metrics.DnsEvent;
-import android.net.metrics.IDnsEventListener;
import android.net.metrics.IpConnectivityLog;
+import android.net.metrics.INetdEventListener;
import android.util.Log;
import com.android.internal.annotations.GuardedBy;
@@ -37,13 +37,13 @@ import java.util.TreeMap;
/**
- * Implementation of the IDnsEventListener interface.
+ * Implementation of the INetdEventListener interface.
*/
-public class DnsEventListenerService extends IDnsEventListener.Stub {
+public class NetdEventListenerService extends INetdEventListener.Stub {
- public static final String SERVICE_NAME = "dns_listener";
+ public static final String SERVICE_NAME = "netd_listener";
- private static final String TAG = DnsEventListenerService.class.getSimpleName();
+ private static final String TAG = NetdEventListenerService.class.getSimpleName();
private static final boolean DBG = true;
private static final boolean VDBG = false;
@@ -110,7 +110,7 @@ public class DnsEventListenerService extends IDnsEventListener.Stub {
private final NetworkCallback mNetworkCallback = new NetworkCallback() {
@Override
public void onLost(Network network) {
- synchronized (DnsEventListenerService.this) {
+ synchronized (NetdEventListenerService.this) {
DnsEventBatch batch = mEventBatches.remove(network.netId);
if (batch != null) {
batch.logAndClear();
@@ -119,12 +119,12 @@ public class DnsEventListenerService extends IDnsEventListener.Stub {
}
};
- public DnsEventListenerService(Context context) {
+ public NetdEventListenerService(Context context) {
this(context.getSystemService(ConnectivityManager.class), new IpConnectivityLog());
}
@VisibleForTesting
- public DnsEventListenerService(ConnectivityManager cm, IpConnectivityLog log) {
+ public NetdEventListenerService(ConnectivityManager cm, IpConnectivityLog log) {
// We are started when boot is complete, so ConnectivityService should already be running.
mCm = cm;
mMetricsLog = log;
diff --git a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
index cb4bb8840b5a..2a618bcc2eac 100644
--- a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
+++ b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
@@ -140,12 +140,14 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> {
public boolean everValidated;
// The result of the last validation attempt on this network (true if validated, false if not).
- // This bit exists only because we never unvalidate a network once it's been validated, and that
- // is because the network scoring and revalidation code does not (may not?) deal properly with
- // networks becoming unvalidated.
- // TODO: Fix the network scoring code, remove this, and rename everValidated to validated.
public boolean lastValidated;
+ // If true, becoming unvalidated will lower the network's score. This is only meaningful if the
+ // system is configured not to do this for certain networks, e.g., if the
+ // config_networkAvoidBadWifi option is set to 0 and the user has not overridden that via
+ // Settings.Global.NETWORK_AVOID_BAD_WIFI.
+ public boolean avoidUnvalidated;
+
// Whether a captive portal was ever detected on this network.
// This is a sticky bit; once set it is never cleared.
public boolean everCaptivePortalDetected;
@@ -426,8 +428,10 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> {
// Return true on devices configured to ignore score penalty for wifi networks
// that become unvalidated (b/31075769).
private boolean ignoreWifiUnvalidationPenalty() {
- boolean isWifi = networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI);
- return isWifi && !mConnService.avoidBadWifi() && everValidated;
+ boolean isWifi = networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) &&
+ networkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET);
+ boolean avoidBadWifi = mConnService.avoidBadWifi() || avoidUnvalidated;
+ return isWifi && !avoidBadWifi && everValidated;
}
// Get the current score for this Network. This may be modified from what the
diff --git a/services/core/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachine.java b/services/core/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachine.java
index 9e7cb939cdf0..6ca4e271ec55 100644
--- a/services/core/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachine.java
+++ b/services/core/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachine.java
@@ -141,10 +141,17 @@ public class TetherInterfaceStateMachine extends StateMachine {
if (ifcg != null) {
InetAddress addr = NetworkUtils.numericToInetAddress(ipAsString);
ifcg.setLinkAddress(new LinkAddress(addr, prefixLen));
- if (enabled) {
- ifcg.setInterfaceUp();
+ if (mInterfaceType == ConnectivityManager.TETHERING_WIFI) {
+ // The WiFi stack has ownership of the interface up/down state.
+ // It is unclear whether the bluetooth or USB stacks will manage their own
+ // state.
+ ifcg.ignoreInterfaceUpDownStatus();
} else {
- ifcg.setInterfaceDown();
+ if (enabled) {
+ ifcg.setInterfaceUp();
+ } else {
+ ifcg.setInterfaceDown();
+ }
}
ifcg.clearFlag("running");
mNMService.setInterfaceConfig(mIfaceName, ifcg);
diff --git a/services/core/java/com/android/server/content/ContentService.java b/services/core/java/com/android/server/content/ContentService.java
index 12955f5771d2..4e236d164a69 100644
--- a/services/core/java/com/android/server/content/ContentService.java
+++ b/services/core/java/com/android/server/content/ContentService.java
@@ -482,7 +482,7 @@ public final class ContentService extends IContentService.Stub {
SyncManager syncManager = getSyncManager();
if (syncManager != null) {
syncManager.scheduleSync(account, userId, uId, authority, extras,
- false /* onlyThoseWithUnkownSyncableState */);
+ SyncStorageEngine.AuthorityInfo.UNDEFINED);
}
} finally {
restoreCallingIdentity(identityToken);
@@ -548,7 +548,7 @@ public final class ContentService extends IContentService.Stub {
} else {
syncManager.scheduleSync(
request.getAccount(), userId, callerUid, request.getProvider(), extras,
- false /* onlyThoseWithUnknownSyncableState */);
+ SyncStorageEngine.AuthorityInfo.UNDEFINED);
}
} finally {
restoreCallingIdentity(identityToken);
diff --git a/services/core/java/com/android/server/content/SyncManager.java b/services/core/java/com/android/server/content/SyncManager.java
index ef3c4b2a27ad..2d6bef4fb735 100644
--- a/services/core/java/com/android/server/content/SyncManager.java
+++ b/services/core/java/com/android/server/content/SyncManager.java
@@ -48,6 +48,7 @@ import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.pm.PackageManagerInternal;
import android.content.pm.ProviderInfo;
import android.content.pm.RegisteredServicesCache;
import android.content.pm.RegisteredServicesCacheListener;
@@ -324,6 +325,8 @@ public class SyncManager {
private final AccountManagerInternal mAccountManagerInternal;
+ private final PackageManagerInternal mPackageManagerInternal;
+
private List<UserInfo> getAllUsers() {
return mUserManager.getUsers();
}
@@ -504,7 +507,7 @@ public class SyncManager {
@Override
public void onSyncRequest(SyncStorageEngine.EndPoint info, int reason, Bundle extras) {
scheduleSync(info.account, info.userId, reason, info.provider, extras,
- false);
+ AuthorityInfo.UNDEFINED);
}
});
@@ -534,7 +537,7 @@ public class SyncManager {
if (!removed) {
scheduleSync(null, UserHandle.USER_ALL,
SyncOperation.REASON_SERVICE_CHANGED,
- type.authority, null, false /* onlyThoseWithUnkownSyncableState */);
+ type.authority, null, AuthorityInfo.UNDEFINED);
}
}
}, mSyncHandler);
@@ -575,6 +578,16 @@ public class SyncManager {
mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
mAccountManager = (AccountManager) mContext.getSystemService(Context.ACCOUNT_SERVICE);
mAccountManagerInternal = LocalServices.getService(AccountManagerInternal.class);
+ mPackageManagerInternal = LocalServices.getService(PackageManagerInternal.class);
+
+ mAccountManagerInternal.addOnAppPermissionChangeListener((Account account, int uid) -> {
+ // If the UID gained access to the account kick-off syncs lacking account access
+ if (mAccountManagerInternal.hasAccountAccess(account, uid)) {
+ scheduleSync(account, UserHandle.getUserId(uid),
+ SyncOperation.REASON_ACCOUNTS_UPDATED,
+ null, null, AuthorityInfo.SYNCABLE_NO_ACCOUNT_ACCESS);
+ }
+ });
mBatteryStats = IBatteryStats.Stub.asInterface(ServiceManager.getService(
BatteryStats.SERVICE_NAME));
@@ -671,7 +684,7 @@ public class SyncManager {
service.type.accountType, userHandle)) {
if (!canAccessAccount(account, packageName, userId)) {
mAccountManager.updateAppPermission(account,
- AccountManager.ACCOUNT_ACCESS_TOKEN, service.uid, true);
+ AccountManager.ACCOUNT_ACCESS_TOKEN_TYPE, service.uid, true);
}
}
}
@@ -778,10 +791,11 @@ public class SyncManager {
* @param extras a Map of SyncAdapter-specific information to control
* syncs of a specific provider. Can be null. Is ignored
* if the url is null.
- * @param onlyThoseWithUnkownSyncableState Only sync authorities that have unknown state.
+ * @param targetSyncState Only sync authorities that have the specified sync state.
+ * Use {@link AuthorityInfo#UNDEFINED} to sync all authorities.
*/
public void scheduleSync(Account requestedAccount, int userId, int reason,
- String requestedAuthority, Bundle extras, boolean onlyThoseWithUnkownSyncableState) {
+ String requestedAuthority, Bundle extras, int targetSyncState) {
final boolean isLoggable = Log.isLoggable(TAG, Log.VERBOSE);
if (extras == null) {
extras = new Bundle();
@@ -881,14 +895,18 @@ public class SyncManager {
+ "isSyncable == SYNCABLE_NO_ACCOUNT_ACCESS");
}
Bundle finalExtras = new Bundle(extras);
+ String packageName = syncAdapterInfo.componentName.getPackageName();
+ // If the app did not run and has no account access, done
+ if (!mPackageManagerInternal.wasPackageEverLaunched(packageName, userId)) {
+ continue;
+ }
mAccountManagerInternal.requestAccountAccess(account.account,
- syncAdapterInfo.componentName.getPackageName(),
- UserHandle.getUserId(owningUid),
+ packageName, userId,
new RemoteCallback((Bundle result) -> {
if (result != null
&& result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT)) {
scheduleSync(account.account, userId, reason, authority,
- finalExtras, onlyThoseWithUnkownSyncableState);
+ finalExtras, targetSyncState);
}
}
));
@@ -903,9 +921,10 @@ public class SyncManager {
isSyncable = AuthorityInfo.SYNCABLE;
}
- if (onlyThoseWithUnkownSyncableState && isSyncable >= 0) {
+ if (targetSyncState != AuthorityInfo.UNDEFINED && targetSyncState != isSyncable) {
continue;
}
+
if (!syncAdapterInfo.type.supportsUploading() && uploadOnly) {
continue;
}
@@ -931,7 +950,7 @@ public class SyncManager {
final String owningPackage = syncAdapterInfo.componentName.getPackageName();
- if (isSyncable < 0) {
+ if (isSyncable == AuthorityInfo.NOT_INITIALIZED) {
// Initialisation sync.
Bundle newExtras = new Bundle();
newExtras.putBoolean(ContentResolver.SYNC_EXTRAS_INITIALIZE, true);
@@ -950,8 +969,8 @@ public class SyncManager {
owningUid, owningPackage, reason, source,
authority, newExtras, allowParallelSyncs)
);
- }
- if (!onlyThoseWithUnkownSyncableState) {
+ } else if (targetSyncState == AuthorityInfo.UNDEFINED
+ || targetSyncState == isSyncable) {
if (isLoggable) {
Slog.v(TAG, "scheduleSync:"
+ " delay until " + delayUntil
@@ -1076,7 +1095,7 @@ public class SyncManager {
final Bundle extras = new Bundle();
extras.putBoolean(ContentResolver.SYNC_EXTRAS_UPLOAD, true);
scheduleSync(account, userId, reason, authority, extras,
- false /* onlyThoseWithUnkownSyncableState */);
+ AuthorityInfo.UNDEFINED);
}
public SyncAdapterType[] getSyncAdapterTypes(int userId) {
@@ -1535,7 +1554,7 @@ public class SyncManager {
mContext.getOpPackageName());
for (Account account : accounts) {
scheduleSync(account, userId, SyncOperation.REASON_USER_START, null, null,
- true /* onlyThoseWithUnknownSyncableState */);
+ AuthorityInfo.NOT_INITIALIZED);
}
}
@@ -2714,7 +2733,8 @@ public class SyncManager {
if (syncTargets != null) {
scheduleSync(syncTargets.account, syncTargets.userId,
- SyncOperation.REASON_ACCOUNTS_UPDATED, syncTargets.provider, null, true);
+ SyncOperation.REASON_ACCOUNTS_UPDATED, syncTargets.provider,
+ null, AuthorityInfo.NOT_INITIALIZED);
}
}
@@ -2786,9 +2806,14 @@ public class SyncManager {
final int syncOpState = computeSyncOpState(op);
switch (syncOpState) {
case SYNC_OP_STATE_INVALID_NO_ACCOUNT_ACCESS: {
+ String packageName = op.owningPackage;
+ final int userId = UserHandle.getUserId(op.owningUid);
+ // If the app did not run and has no account access, done
+ if (!mPackageManagerInternal.wasPackageEverLaunched(packageName, userId)) {
+ return;
+ }
mAccountManagerInternal.requestAccountAccess(op.target.account,
- op.owningPackage, UserHandle.getUserId(op.owningUid),
- new RemoteCallback((Bundle result) -> {
+ packageName, userId, new RemoteCallback((Bundle result) -> {
if (result != null
&& result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT)) {
updateOrAddPeriodicSync(target, pollFrequency, flex, extras);
diff --git a/services/core/java/com/android/server/content/SyncStorageEngine.java b/services/core/java/com/android/server/content/SyncStorageEngine.java
index 8289bae8793b..069ae7394319 100644
--- a/services/core/java/com/android/server/content/SyncStorageEngine.java
+++ b/services/core/java/com/android/server/content/SyncStorageEngine.java
@@ -211,6 +211,12 @@ public class SyncStorageEngine extends Handler {
public static class AuthorityInfo {
// Legal values of getIsSyncable
+
+ /**
+ * The syncable state is undefined.
+ */
+ public static final int UNDEFINED = -2;
+
/**
* Default state for a newly installed adapter. An uninitialized adapter will receive an
* initialization sync which are governed by a different set of rules to that of regular
diff --git a/services/core/java/com/android/server/dreams/DreamController.java b/services/core/java/com/android/server/dreams/DreamController.java
index a63399656bab..9fa93f4b8a6c 100644
--- a/services/core/java/com/android/server/dreams/DreamController.java
+++ b/services/core/java/com/android/server/dreams/DreamController.java
@@ -26,6 +26,7 @@ import android.content.ServiceConnection;
import android.os.Binder;
import android.os.Handler;
import android.os.IBinder;
+import android.os.PowerManager;
import android.os.RemoteException;
import android.os.IBinder.DeathRecipient;
import android.os.SystemClock;
@@ -116,19 +117,19 @@ final class DreamController {
}
public void startDream(Binder token, ComponentName name,
- boolean isTest, boolean canDoze, int userId) {
+ boolean isTest, boolean canDoze, int userId, PowerManager.WakeLock wakeLock) {
stopDream(true /*immediate*/);
Trace.traceBegin(Trace.TRACE_TAG_POWER, "startDream");
try {
- // Close the notification shade. Don't need to send to all, but better to be explicit.
+ // Close the notification shade. No need to send to all, but better to be explicit.
mContext.sendBroadcastAsUser(mCloseNotificationShadeIntent, UserHandle.ALL);
Slog.i(TAG, "Starting dream: name=" + name
+ ", isTest=" + isTest + ", canDoze=" + canDoze
+ ", userId=" + userId);
- mCurrentDream = new DreamRecord(token, name, isTest, canDoze, userId);
+ mCurrentDream = new DreamRecord(token, name, isTest, canDoze, userId, wakeLock);
mDreamStartTime = SystemClock.elapsedRealtime();
MetricsLogger.visible(mContext,
@@ -230,6 +231,7 @@ final class DreamController {
if (oldDream.mBound) {
mContext.unbindService(oldDream);
}
+ oldDream.releaseWakeLockIfNeeded();
try {
mIWindowManager.removeWindowToken(oldDream.mToken);
@@ -280,6 +282,7 @@ final class DreamController {
public final boolean mCanDoze;
public final int mUserId;
+ public PowerManager.WakeLock mWakeLock;
public boolean mBound;
public boolean mConnected;
public IDreamService mService;
@@ -288,12 +291,17 @@ final class DreamController {
public boolean mWakingGently;
public DreamRecord(Binder token, ComponentName name,
- boolean isTest, boolean canDoze, int userId) {
+ boolean isTest, boolean canDoze, int userId, PowerManager.WakeLock wakeLock) {
mToken = token;
mName = name;
mIsTest = isTest;
mCanDoze = canDoze;
mUserId = userId;
+ mWakeLock = wakeLock;
+ // Hold the lock while we're waiting for the service to connect. Released either when
+ // DreamService connects (and is then responsible for keeping the device awake) or
+ // dreaming stops.
+ mWakeLock.acquire();
}
// May be called on any thread.
@@ -316,14 +324,25 @@ final class DreamController {
mHandler.post(new Runnable() {
@Override
public void run() {
- mConnected = true;
- if (mCurrentDream == DreamRecord.this && mService == null) {
- attach(IDreamService.Stub.asInterface(service));
+ try {
+ mConnected = true;
+ if (mCurrentDream == DreamRecord.this && mService == null) {
+ attach(IDreamService.Stub.asInterface(service));
+ }
+ } finally {
+ releaseWakeLockIfNeeded();
}
}
});
}
+ private void releaseWakeLockIfNeeded() {
+ if (mWakeLock != null) {
+ mWakeLock.release();
+ mWakeLock = null;
+ }
+ }
+
// May be called on any thread.
@Override
public void onServiceDisconnected(ComponentName name) {
diff --git a/services/core/java/com/android/server/dreams/DreamManagerService.java b/services/core/java/com/android/server/dreams/DreamManagerService.java
index a783fa25ed45..20bccf19f131 100644
--- a/services/core/java/com/android/server/dreams/DreamManagerService.java
+++ b/services/core/java/com/android/server/dreams/DreamManagerService.java
@@ -370,12 +370,10 @@ public final class DreamManagerService extends SystemService {
mCurrentDreamCanDoze = canDoze;
mCurrentDreamUserId = userId;
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- mController.startDream(newToken, name, isTest, canDoze, userId);
- }
- });
+ PowerManager.WakeLock wakeLock = mPowerManager
+ .newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "startDream");
+ mHandler.post(wakeLock.wrap(
+ () -> mController.startDream(newToken, name, isTest, canDoze, userId, wakeLock)));
}
private void stopDreamLocked(final boolean immediate) {
diff --git a/services/core/java/com/android/server/lights/LightsService.java b/services/core/java/com/android/server/lights/LightsService.java
index 07048a491543..ca6481792dfe 100644
--- a/services/core/java/com/android/server/lights/LightsService.java
+++ b/services/core/java/com/android/server/lights/LightsService.java
@@ -172,10 +172,12 @@ public class LightsService extends SystemService {
if (phase == PHASE_SYSTEM_SERVICES_READY) {
IVrManager vrManager =
(IVrManager) getBinderService(VrManagerService.VR_MANAGER_BINDER_SERVICE);
- try {
- vrManager.registerListener(mVrStateCallbacks);
- } catch (RemoteException e) {
- Slog.e(TAG, "Failed to register VR mode state listener: " + e);
+ if (vrManager != null) {
+ try {
+ vrManager.registerListener(mVrStateCallbacks);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Failed to register VR mode state listener: " + e);
+ }
}
}
}
diff --git a/services/core/java/com/android/server/media/MediaSessionService.java b/services/core/java/com/android/server/media/MediaSessionService.java
index 768d338c75fe..4c58ffd5dc83 100644
--- a/services/core/java/com/android/server/media/MediaSessionService.java
+++ b/services/core/java/com/android/server/media/MediaSessionService.java
@@ -767,6 +767,13 @@ public class MediaSessionService extends SystemService implements Monitor {
+ "setup is in progress.");
return;
}
+ if (isGlobalPriorityActive() && uid != Process.SYSTEM_UID) {
+ // Prevent dispatching key event through reflection while the global priority
+ // session is active.
+ Slog.i(TAG, "Only the system can dispatch media key event "
+ + "to the global priority session.");
+ return;
+ }
synchronized (mLock) {
// If we don't have a media button receiver to fall back on
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index 1eef3a731c56..6c10ffdfcd40 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -2652,9 +2652,31 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
}
}
+ /**
+ * Toggle the firewall standby chain and inform listeners if the uid rules have effectively
+ * changed.
+ */
void updateRulesForAppIdleParoleUL() {
- boolean enableChain = !mUsageStats.isAppIdleParoleOn();
+ boolean paroled = mUsageStats.isAppIdleParoleOn();
+ boolean enableChain = !paroled;
enableFirewallChainUL(FIREWALL_CHAIN_STANDBY, enableChain);
+
+ int ruleCount = mUidFirewallStandbyRules.size();
+ for (int i = 0; i < ruleCount; i++) {
+ int uid = mUidFirewallStandbyRules.keyAt(i);
+ int oldRules = mUidRules.get(uid);
+ if (enableChain) {
+ // Chain wasn't enabled before and the other power-related
+ // chains are whitelists, so we can clear the
+ // MASK_ALL_NETWORKS part of the rules and re-inform listeners if
+ // the effective rules result in blocking network access.
+ oldRules &= MASK_METERED_NETWORKS;
+ } else {
+ // Skip if it had no restrictions to begin with
+ if ((oldRules & MASK_ALL_NETWORKS) == 0) continue;
+ }
+ updateRulesForPowerRestrictionsUL(uid, oldRules, paroled);
+ }
}
/**
@@ -3008,14 +3030,34 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
* <strong>NOTE: </strong>This method does not update the firewall rules on {@code netd}.
*/
private void updateRulesForPowerRestrictionsUL(int uid) {
+ final int oldUidRules = mUidRules.get(uid, RULE_NONE);
+
+ final int newUidRules = updateRulesForPowerRestrictionsUL(uid, oldUidRules, false);
+
+ if (newUidRules == RULE_NONE) {
+ mUidRules.delete(uid);
+ } else {
+ mUidRules.put(uid, newUidRules);
+ }
+ }
+
+ /**
+ * Similar to above but ignores idle state if app standby is currently disabled by parole.
+ *
+ * @param uid the uid of the app to update rules for
+ * @param oldUidRules the current rules for the uid, in order to determine if there's a change
+ * @param paroled whether to ignore idle state of apps and only look at other restrictions.
+ *
+ * @return the new computed rules for the uid
+ */
+ private int updateRulesForPowerRestrictionsUL(int uid, int oldUidRules, boolean paroled) {
if (!isUidValidForBlacklistRules(uid)) {
if (LOGD) Slog.d(TAG, "no need to update restrict power rules for uid " + uid);
- return;
+ return RULE_NONE;
}
- final boolean isIdle = isUidIdle(uid);
+ final boolean isIdle = !paroled && isUidIdle(uid);
final boolean restrictMode = isIdle || mRestrictPower || mDeviceIdleMode;
- final int oldUidRules = mUidRules.get(uid, RULE_NONE);
final boolean isForeground = isUidForegroundOnRestrictPowerUL(uid);
final boolean isWhitelisted = isWhitelistedBatterySaverUL(uid);
@@ -3049,12 +3091,6 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
+ ", oldUidRules=" + uidRulesToString(oldUidRules));
}
- if (newUidRules == RULE_NONE) {
- mUidRules.delete(uid);
- } else {
- mUidRules.put(uid, newUidRules);
- }
-
// Second step: notify listeners if state changed.
if (newRule != oldRule) {
if (newRule == RULE_NONE || (newRule & RULE_ALLOW_ALL) != 0) {
@@ -3071,6 +3107,8 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
}
mHandler.obtainMessage(MSG_RULES_CHANGED, uid, newUidRules).sendToTarget();
}
+
+ return newUidRules;
}
private class AppIdleStateChangeListener
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 6b2df73de8a6..0c7c8aa8a9b5 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -142,7 +142,6 @@ import com.android.server.lights.LightsManager;
import com.android.server.notification.ManagedServices.ManagedServiceInfo;
import com.android.server.policy.PhoneWindowManager;
import com.android.server.statusbar.StatusBarManagerInternal;
-import com.android.server.vr.VrManagerInternal;
import com.android.server.notification.ManagedServices.UserProfiles;
import libcore.io.IoUtils;
@@ -234,7 +233,6 @@ public class NotificationManagerService extends SystemService {
AudioManagerInternal mAudioManagerInternal;
@Nullable StatusBarManagerInternal mStatusBar;
Vibrator mVibrator;
- private VrManagerInternal mVrManagerInternal;
private WindowManagerInternal mWindowManagerInternal;
final IBinder mForegroundToken = new Binder();
@@ -1152,7 +1150,6 @@ public class NotificationManagerService extends SystemService {
// Grab our optional AudioService
mAudioManager = (AudioManager) getContext().getSystemService(Context.AUDIO_SERVICE);
mAudioManagerInternal = getLocalService(AudioManagerInternal.class);
- mVrManagerInternal = getLocalService(VrManagerInternal.class);
mWindowManagerInternal = LocalServices.getService(WindowManagerInternal.class);
mZenModeHelper.onSystemReady();
} else if (phase == SystemService.PHASE_THIRD_PARTY_APPS_CAN_START) {
diff --git a/services/core/java/com/android/server/os/DeviceIdentifiersPolicyService.java b/services/core/java/com/android/server/os/DeviceIdentifiersPolicyService.java
new file mode 100644
index 000000000000..759030bd949c
--- /dev/null
+++ b/services/core/java/com/android/server/os/DeviceIdentifiersPolicyService.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.os;
+
+import android.Manifest;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.Context;
+import android.os.Binder;
+import android.os.Build;
+import android.os.IDeviceIdentifiersPolicyService;
+import android.os.Process;
+import android.os.RemoteException;
+import android.os.SystemProperties;
+import android.os.UserHandle;
+import com.android.server.SystemService;
+
+/**
+ * This service defines the policy for accessing device identifiers.
+ */
+public final class DeviceIdentifiersPolicyService extends SystemService {
+ public DeviceIdentifiersPolicyService(Context context) {
+ super(context);
+ }
+
+ @Override
+ public void onStart() {
+ publishBinderService(Context.DEVICE_IDENTIFIERS_SERVICE,
+ new DeviceIdentifiersPolicy(getContext()));
+ }
+
+ private static final class DeviceIdentifiersPolicy
+ extends IDeviceIdentifiersPolicyService.Stub {
+ private final @NonNull Context mContext;
+
+ public DeviceIdentifiersPolicy(Context context) {
+ mContext = context;
+ }
+
+ @Override
+ public @Nullable String getSerial() throws RemoteException {
+ if (UserHandle.getAppId(Binder.getCallingUid()) != Process.SYSTEM_UID) {
+ mContext.enforceCallingOrSelfPermission(
+ Manifest.permission.READ_PHONE_STATE, "getSerial");
+ }
+ return SystemProperties.get("ro.serialno", Build.UNKNOWN);
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/pm/OtaDexoptService.java b/services/core/java/com/android/server/pm/OtaDexoptService.java
index 42079fb0df1b..689917cd670a 100644
--- a/services/core/java/com/android/server/pm/OtaDexoptService.java
+++ b/services/core/java/com/android/server/pm/OtaDexoptService.java
@@ -172,6 +172,7 @@ public class OtaDexoptService extends IOtaDexopt.Stub {
Log.i(TAG, "Cleaning up OTA Dexopt state.");
}
mDexoptCommands = null;
+ availableSpaceAfterDexopt = getAvailableSpace();
performMetricsLogging();
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 264252012347..51978f22ca5e 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -21134,6 +21134,13 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName());
public boolean isPackageDataProtected(int userId, String packageName) {
return mProtectedPackages.isPackageDataProtected(userId, packageName);
}
+
+ @Override
+ public boolean wasPackageEverLaunched(String packageName, int userId) {
+ synchronized (mPackages) {
+ return mSettings.wasPackageEverLaunchedLPr(packageName, userId);
+ }
+ }
}
@Override
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index 27ac3ad8852a..8cab355dc3bd 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -4161,6 +4161,14 @@ final class Settings {
return pkg.getCurrentEnabledStateLPr(classNameStr, userId);
}
+ boolean wasPackageEverLaunchedLPr(String packageName, int userId) {
+ final PackageSetting pkgSetting = mPackages.get(packageName);
+ if (pkgSetting == null) {
+ throw new IllegalArgumentException("Unknown package: " + packageName);
+ }
+ return !pkgSetting.getNotLaunched(userId);
+ }
+
boolean setPackageStoppedStateLPw(PackageManagerService pm, String packageName,
boolean stopped, boolean allowedByPermission, int uid, int userId) {
int appId = UserHandle.getAppId(uid);
diff --git a/services/core/java/com/android/server/policy/ImmersiveModeConfirmation.java b/services/core/java/com/android/server/policy/ImmersiveModeConfirmation.java
index c764833e08a6..9bf04768ba1a 100644
--- a/services/core/java/com/android/server/policy/ImmersiveModeConfirmation.java
+++ b/services/core/java/com/android/server/policy/ImmersiveModeConfirmation.java
@@ -25,7 +25,9 @@ import android.content.Intent;
import android.content.IntentFilter;
import android.graphics.PixelFormat;
import android.graphics.drawable.ColorDrawable;
+import android.os.Binder;
import android.os.Handler;
+import android.os.IBinder;
import android.os.Message;
import android.os.RemoteException;
import android.os.ServiceManager;
@@ -36,7 +38,6 @@ import android.service.vr.IVrManager;
import android.service.vr.IVrStateCallbacks;
import android.util.DisplayMetrics;
import android.util.Slog;
-import android.util.SparseBooleanArray;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.View;
@@ -66,6 +67,7 @@ public class ImmersiveModeConfirmation {
private final H mHandler;
private final long mShowDelayMs;
private final long mPanicThresholdMs;
+ private final IBinder mWindowToken = new Binder();
private boolean mConfirmed;
private ClingWindowView mClingWindow;
@@ -190,13 +192,13 @@ public class ImmersiveModeConfirmation {
WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL,
0
| WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
- | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
| WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED
,
PixelFormat.TRANSLUCENT);
lp.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS;
lp.setTitle("ImmersiveModeConfirmation");
lp.windowAnimations = com.android.internal.R.style.Animation_ImmersiveModeConfirmation;
+ lp.token = getWindowToken();
return lp;
}
@@ -208,6 +210,13 @@ public class ImmersiveModeConfirmation {
Gravity.CENTER_HORIZONTAL | Gravity.TOP);
}
+ /**
+ * @return the window token that's used by all ImmersiveModeConfirmation windows.
+ */
+ public IBinder getWindowToken() {
+ return mWindowToken;
+ }
+
private class ClingWindowView extends FrameLayout {
private static final int BGCOLOR = 0x80000000;
private static final int OFFSET_DP = 96;
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 61879784a186..b5559382ff2a 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -1932,6 +1932,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
public void setInitialDisplaySize(Display display, int width, int height, int density) {
// This method might be called before the policy has been fully initialized
// or for other displays we don't care about.
+ // TODO(multi-display): Define policy for secondary displays.
if (mContext == null || display.getDisplayId() != Display.DEFAULT_DISPLAY) {
return;
}
@@ -2027,6 +2028,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
@Override
public void setDisplayOverscan(Display display, int left, int top, int right, int bottom) {
+ // TODO(multi-display): Define policy for secondary displays.
if (display.getDisplayId() == Display.DEFAULT_DISPLAY) {
mOverscanLeft = left;
mOverscanTop = top;
@@ -2428,6 +2430,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
@Override
public void onConfigurationChanged() {
+ // TODO(multi-display): Define policy for secondary displays.
final Resources res = mContext.getResources();
mStatusBarHeight =
@@ -3964,11 +3967,19 @@ public class PhoneWindowManager implements WindowManagerPolicy {
};
@Override
+ public void setRecentsVisibilityLw(boolean visible) {
+ mRecentsVisible = visible;
+ }
+
+ @Override
+ public void setTvPipVisibilityLw(boolean visible) {
+ mTvPictureInPictureVisible = visible;
+ }
+
+ @Override
public int adjustSystemUiVisibilityLw(int visibility) {
mStatusBarController.adjustSystemUiVisibilityLw(mLastSystemUiFlags, visibility);
mNavigationBarController.adjustSystemUiVisibilityLw(mLastSystemUiFlags, visibility);
- mRecentsVisible = (visibility & View.RECENT_APPS_VISIBLE) > 0;
- mTvPictureInPictureVisible = (visibility & View.TV_PICTURE_IN_PICTURE_VISIBLE) > 0;
// Reset any bits in mForceClearingStatusBarVisibility that
// are now clear.
@@ -7533,11 +7544,20 @@ public class PhoneWindowManager implements WindowManagerPolicy {
private int updateSystemUiVisibilityLw() {
// If there is no window focused, there will be nobody to handle the events
// anyway, so just hang on in whatever state we're in until things settle down.
- final WindowState win = mFocusedWindow != null ? mFocusedWindow
+ WindowState winCandidate = mFocusedWindow != null ? mFocusedWindow
: mTopFullscreenOpaqueWindowState;
- if (win == null) {
+ if (winCandidate == null) {
return 0;
}
+ if (winCandidate.getAttrs().token == mImmersiveModeConfirmation.getWindowToken()) {
+ // The immersive mode confirmation should never affect the system bar visibility,
+ // otherwise it will unhide the navigation bar and hide itself.
+ winCandidate = isStatusBarKeyguard() ? mStatusBar : mTopFullscreenOpaqueWindowState;
+ if (winCandidate == null) {
+ return 0;
+ }
+ }
+ final WindowState win = winCandidate;
if ((win.getAttrs().privateFlags & PRIVATE_FLAG_KEYGUARD) != 0 && mHideLockScreen == true) {
// We are updating at a point where the keyguard has gotten
// focus, but we were last in a state where the top window is
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index a2b86e3bfd53..3f58c958814d 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -650,10 +650,12 @@ public final class PowerManagerService extends SystemService
false, mSettingsObserver, UserHandle.USER_ALL);
IVrManager vrManager =
(IVrManager) getBinderService(VrManagerService.VR_MANAGER_BINDER_SERVICE);
- try {
- vrManager.registerListener(mVrStateCallbacks);
- } catch (RemoteException e) {
- Slog.e(TAG, "Failed to register VR mode state listener: " + e);
+ if (vrManager != null) {
+ try {
+ vrManager.registerListener(mVrStateCallbacks);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Failed to register VR mode state listener: " + e);
+ }
}
// Go.
readConfigurationLocked();
diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
index 3075102bc641..3b20fb14c2ce 100644
--- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
+++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
@@ -89,6 +89,7 @@ import com.android.internal.os.BackgroundThread;
import com.android.internal.util.FastXmlSerializer;
import com.android.internal.util.JournaledFile;
import com.android.server.EventLogTags;
+import com.android.server.FgThread;
import com.android.server.SystemService;
import libcore.io.IoUtils;
@@ -589,6 +590,11 @@ public class WallpaperManagerService extends IWallpaperManager.Stub {
class WallpaperConnection extends IWallpaperConnection.Stub
implements ServiceConnection {
+
+ /** Time in milliseconds until we expect the wallpaper to reconnect (unless we're in the
+ * middle of an update). If exceeded, the wallpaper gets reset to the system default. */
+ private static final long WALLPAPER_RECONNECT_TIMEOUT_MS = 5000;
+
final WallpaperInfo mInfo;
final Binder mToken = new Binder();
IWallpaperService mService;
@@ -599,6 +605,18 @@ public class WallpaperManagerService extends IWallpaperManager.Stub {
boolean mDimensionsChanged = false;
boolean mPaddingChanged = false;
+ private Runnable mResetRunnable = () -> {
+ synchronized (mLock) {
+ if (!mWallpaper.wallpaperUpdating
+ && mWallpaper.userId == mCurrentUserId) {
+ Slog.w(TAG, "Wallpaper reconnect timed out, "
+ + "reverting to built-in wallpaper!");
+ clearWallpaperLocked(true, FLAG_SYSTEM, mWallpaper.userId,
+ null);
+ }
+ }
+ };
+
public WallpaperConnection(WallpaperInfo info, WallpaperData wallpaper) {
mInfo = info;
mWallpaper = wallpaper;
@@ -615,6 +633,7 @@ public class WallpaperManagerService extends IWallpaperManager.Stub {
// locking there and anyway we always need to be able to
// recover if there is something wrong.
saveSettingsLocked(mWallpaper.userId);
+ FgThread.getHandler().removeCallbacks(mResetRunnable);
}
}
}
@@ -641,6 +660,12 @@ public class WallpaperManagerService extends IWallpaperManager.Stub {
clearWallpaperLocked(true, FLAG_SYSTEM, mWallpaper.userId, null);
} else {
mWallpaper.lastDiedTime = SystemClock.uptimeMillis();
+
+ // If we didn't reset it right away, do so after we couldn't connect to
+ // it for an extended amount of time to avoid having a black wallpaper.
+ FgThread.getHandler().removeCallbacks(mResetRunnable);
+ FgThread.getHandler().postDelayed(mResetRunnable,
+ WALLPAPER_RECONNECT_TIMEOUT_MS);
}
final String flattened = name.flattenToString();
EventLog.writeEvent(EventLogTags.WP_WALLPAPER_CRASHED,
@@ -752,6 +777,10 @@ public class WallpaperManagerService extends IWallpaperManager.Stub {
if (wallpaper.wallpaperComponent != null
&& wallpaper.wallpaperComponent.getPackageName().equals(packageName)) {
wallpaper.wallpaperUpdating = true;
+ if (wallpaper.connection != null) {
+ FgThread.getHandler().removeCallbacks(
+ wallpaper.connection.mResetRunnable);
+ }
}
}
}
diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java
index f9aa66b825fc..4d12ba946a96 100644
--- a/services/core/java/com/android/server/wm/AppWindowToken.java
+++ b/services/core/java/com/android/server/wm/AppWindowToken.java
@@ -564,10 +564,7 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree
allDrawnExcludingSaved = false;
}
- @Override
- void removeWindow(WindowState win) {
- super.removeWindow(win);
-
+ void postWindowRemoveStartingWindowCleanup(WindowState win) {
// TODO: Something smells about the code below...Is there a better way?
if (startingWindow == win) {
if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Notify removed startingWindow " + win);
@@ -933,7 +930,8 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree
mService.mWindowsChanged = true;
if (DEBUG_ADD_REMOVE) Slog.v(TAG_WM,
"Removing starting " + tStartingWindow + " from " + fromToken);
- fromToken.removeWindow(tStartingWindow);
+ fromToken.removeChild(tStartingWindow);
+ fromToken.postWindowRemoveStartingWindowCleanup(tStartingWindow);
addWindow(tStartingWindow);
// Propagate other interesting state between the tokens. If the old token is displayed,
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index e1aa98d4b79e..4fc3ab0ec503 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -40,6 +40,7 @@ import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ORIENTATION;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
import static com.android.server.wm.WindowState.RESIZE_HANDLE_WIDTH_IN_DP;
+import android.annotation.NonNull;
import android.app.ActivityManager.StackId;
import android.graphics.Rect;
import android.graphics.Region;
@@ -60,6 +61,7 @@ import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.List;
class DisplayContentList extends ArrayList<DisplayContent> {
}
@@ -212,6 +214,23 @@ class DisplayContent {
return null;
}
+ /** Callback used to notify about configuration changes. */
+ void onConfigurationChanged(@NonNull List<Integer> changedStackList) {
+ // The display size information is heavily dependent on the resources in the current
+ // configuration, so we need to reconfigure it every time the configuration changes.
+ // See {@link PhoneWindowManager#setInitialDisplaySize}...sigh...
+ mService.reconfigureDisplayLocked(this);
+
+ getDockedDividerController().onConfigurationChanged();
+
+ for (int i = 0; i < mStacks.size(); i++) {
+ final TaskStack stack = mStacks.get(i);
+ if (stack.onConfigurationChanged()) {
+ changedStackList.add(stack.mStackId);
+ }
+ }
+ }
+
void checkAppWindowsReadyToShow() {
for (int i = mStacks.size() - 1; i >= 0; --i) {
final TaskStack stack = mStacks.get(i);
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 982f12e732d0..9e8c6091909e 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -68,7 +68,7 @@ class Task extends WindowContainer<AppWindowToken> implements DimLayer.DimLayerU
int mRotation;
// Whether mBounds is fullscreen
- private boolean mFullscreen = true;
+ private boolean mFillsParent = true;
/**
* Contains configurations settings that are different from the parent configuration due to
@@ -220,14 +220,14 @@ class Task extends WindowContainer<AppWindowToken> implements DimLayer.DimLayerU
if (bounds != null && Configuration.EMPTY.equals(overrideConfig)) {
throw new IllegalArgumentException("non null bounds, but empty configuration");
}
- boolean oldFullscreen = mFullscreen;
+ boolean oldFullscreen = mFillsParent;
int rotation = Surface.ROTATION_0;
final DisplayContent displayContent = mStack.getDisplayContent();
if (displayContent != null) {
displayContent.getLogicalDisplayRect(mTmpRect);
rotation = displayContent.getDisplayInfo().rotation;
- mFullscreen = bounds == null;
- if (mFullscreen) {
+ mFillsParent = bounds == null;
+ if (mFillsParent) {
bounds = mTmpRect;
}
}
@@ -236,7 +236,7 @@ class Task extends WindowContainer<AppWindowToken> implements DimLayer.DimLayerU
// Can't set to fullscreen if we don't have a display to get bounds from...
return BOUNDS_CHANGE_NONE;
}
- if (mBounds.equals(bounds) && oldFullscreen == mFullscreen && mRotation == rotation) {
+ if (mBounds.equals(bounds) && oldFullscreen == mFillsParent && mRotation == rotation) {
return BOUNDS_CHANGE_NONE;
}
@@ -254,7 +254,7 @@ class Task extends WindowContainer<AppWindowToken> implements DimLayer.DimLayerU
if (displayContent != null) {
displayContent.mDimLayerController.updateDimLayer(this);
}
- mOverrideConfig = mFullscreen ? Configuration.EMPTY : overrideConfig;
+ mOverrideConfig = mFillsParent ? Configuration.EMPTY : overrideConfig;
return boundsChange;
}
@@ -354,7 +354,7 @@ class Task extends WindowContainer<AppWindowToken> implements DimLayer.DimLayerU
/** Return true if the current bound can get outputted to the rest of the system as-is. */
private boolean useCurrentBounds() {
final DisplayContent displayContent = mStack.getDisplayContent();
- return mFullscreen
+ return mFillsParent
|| !StackId.isTaskResizeableByDockedStack(mStack.mStackId)
|| displayContent == null
|| displayContent.getDockedStackVisibleForUserLocked() != null;
@@ -432,7 +432,7 @@ class Task extends WindowContainer<AppWindowToken> implements DimLayer.DimLayerU
return;
}
- if (!mFullscreen) {
+ if (!mFillsParent) {
// When minimizing the docked stack when going home, we don't adjust the task bounds
// so we need to intersect the task bounds with the stack bounds here.
//
@@ -483,7 +483,7 @@ class Task extends WindowContainer<AppWindowToken> implements DimLayer.DimLayerU
if (displayContent == null) {
return;
}
- if (mFullscreen) {
+ if (mFillsParent) {
setBounds(null, Configuration.EMPTY);
return;
}
@@ -572,7 +572,7 @@ class Task extends WindowContainer<AppWindowToken> implements DimLayer.DimLayerU
boolean isFullscreen() {
if (useCurrentBounds()) {
- return mFullscreen;
+ return mFillsParent;
}
// The bounds has been adjusted to accommodate for a docked stack, but the docked stack
// is not currently visible. Go ahead a represent it as fullscreen to the rest of the
@@ -638,7 +638,7 @@ class Task extends WindowContainer<AppWindowToken> implements DimLayer.DimLayerU
@Override
boolean fillsParent() {
- return mFullscreen || !StackId.isTaskResizeAllowed(mStack.mStackId);
+ return mFillsParent || !StackId.isTaskResizeAllowed(mStack.mStackId);
}
@Override
@@ -659,7 +659,7 @@ class Task extends WindowContainer<AppWindowToken> implements DimLayer.DimLayerU
final String doublePrefix = prefix + " ";
pw.println(prefix + "taskId=" + mTaskId);
- pw.println(doublePrefix + "mFullscreen=" + mFullscreen);
+ pw.println(doublePrefix + "mFillsParent=" + mFillsParent);
pw.println(doublePrefix + "mBounds=" + mBounds.toShortString());
pw.println(doublePrefix + "mdr=" + mDeferRemoval);
pw.println(doublePrefix + "appTokens=" + mChildren);
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 0e0cf02951d2..a3c830a48a48 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -886,13 +886,6 @@ public class WindowManagerService extends IWindowManager.Stub
// since they won't be notified through the app window animator.
final List<IBinder> mNoAnimationNotifyOnTransitionFinished = new ArrayList<>();
- // List of displays to reconfigure after configuration changes.
- // Some of the information reported for a display is dependent on resources to do the right
- // calculations. For example, {@link DisplayInfo#smallestNominalAppWidth} and company are
- // dependent on the height and width of the status and nav bar which change depending on the
- // current configuration.
- private final DisplayContentList mReconfigureOnConfigurationChanged = new DisplayContentList();
-
// State for the RemoteSurfaceTrace system used in testing. If this is enabled SurfaceControl
// instances will be replaced with an instance that writes a binary representation of all
// commands to mSurfaceTraceFd.
@@ -2061,7 +2054,7 @@ public class WindowManagerService extends IWindowManager.Stub
final WindowToken token = win.mToken;
final AppWindowToken atoken = win.mAppToken;
if (DEBUG_ADD_REMOVE) Slog.v(TAG_WM, "Removing " + win + " from " + token);
- token.removeWindow(win);
+ // Window will already be removed from token before this post clean-up method is called.
if (token.isEmpty()) {
if (!token.explicit) {
mTokenMap.remove(token.token);
@@ -2074,7 +2067,7 @@ public class WindowManagerService extends IWindowManager.Stub
}
if (atoken != null) {
- atoken.removeWindow(win);
+ atoken.postWindowRemoveStartingWindowCleanup(win);
}
if (win.mAttrs.type == TYPE_WALLPAPER) {
@@ -3168,30 +3161,19 @@ public class WindowManagerService extends IWindowManager.Stub
}
}
+
private int[] onConfigurationChanged() {
mPolicy.onConfigurationChanged();
- final DisplayContent defaultDisplayContent = getDefaultDisplayContentLocked();
- if (!mReconfigureOnConfigurationChanged.contains(defaultDisplayContent)) {
- // The default display size information is heavily dependent on the resources in the
- // current configuration, so we need to reconfigure it everytime the configuration
- // changes. See {@link PhoneWindowManager#setInitialDisplaySize}...sigh...
- mReconfigureOnConfigurationChanged.add(defaultDisplayContent);
- }
- for (int i = mReconfigureOnConfigurationChanged.size() - 1; i >= 0; i--) {
- reconfigureDisplayLocked(mReconfigureOnConfigurationChanged.remove(i));
- }
-
- defaultDisplayContent.getDockedDividerController().onConfigurationChanged();
mChangedStackList.clear();
- for (int stackNdx = mStackIdToStack.size() - 1; stackNdx >= 0; stackNdx--) {
- final TaskStack stack = mStackIdToStack.valueAt(stackNdx);
- if (stack.onConfigurationChanged()) {
- mChangedStackList.add(stack.mStackId);
- }
+
+ final int numDisplays = mDisplayContents.size();
+ for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
+ final DisplayContent displayContent = mDisplayContents.valueAt(displayNdx);
+ displayContent.onConfigurationChanged(mChangedStackList);
}
- return mChangedStackList.isEmpty() ?
- null : ArrayUtils.convertToIntArray(mChangedStackList);
+
+ return mChangedStackList.isEmpty() ? null : ArrayUtils.convertToIntArray(mChangedStackList);
}
@Override
@@ -8130,9 +8112,7 @@ public class WindowManagerService extends IWindowManager.Stub
reconfigureDisplayLocked(displayContent);
}
- // displayContent must not be null
- private void reconfigureDisplayLocked(DisplayContent displayContent) {
- // TODO: Multidisplay: for now only use with default display.
+ void reconfigureDisplayLocked(@NonNull DisplayContent displayContent) {
if (!mDisplayReady) {
return;
}
@@ -8148,9 +8128,6 @@ public class WindowManagerService extends IWindowManager.Stub
mWaitingForConfig = true;
startFreezingDisplayLocked(false, 0, 0);
mH.sendEmptyMessage(H.SEND_NEW_CONFIGURATION);
- if (!mReconfigureOnConfigurationChanged.contains(displayContent)) {
- mReconfigureOnConfigurationChanged.add(displayContent);
- }
}
mWindowPlacerLocked.performSurfacePlacement();
@@ -8892,6 +8869,32 @@ public class WindowManagerService extends IWindowManager.Stub
}
@Override
+ public void setRecentsVisibility(boolean visible) {
+ if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.STATUS_BAR)
+ != PackageManager.PERMISSION_GRANTED) {
+ throw new SecurityException("Caller does not hold permission "
+ + android.Manifest.permission.STATUS_BAR);
+ }
+
+ synchronized (mWindowMap) {
+ mPolicy.setRecentsVisibilityLw(visible);
+ }
+ }
+
+ @Override
+ public void setTvPipVisibility(boolean visible) {
+ if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.STATUS_BAR)
+ != PackageManager.PERMISSION_GRANTED) {
+ throw new SecurityException("Caller does not hold permission "
+ + android.Manifest.permission.STATUS_BAR);
+ }
+
+ synchronized (mWindowMap) {
+ mPolicy.setTvPipVisibilityLw(visible);
+ }
+ }
+
+ @Override
public void statusBarVisibilityChanged(int visibility) {
if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.STATUS_BAR)
!= PackageManager.PERMISSION_GRANTED) {
diff --git a/services/core/java/com/android/server/wm/WindowToken.java b/services/core/java/com/android/server/wm/WindowToken.java
index 735efa962fac..7ed8e7844e0b 100644
--- a/services/core/java/com/android/server/wm/WindowToken.java
+++ b/services/core/java/com/android/server/wm/WindowToken.java
@@ -91,8 +91,10 @@ class WindowToken extends WindowContainer<WindowState> {
final WindowState win = mChildren.get(i);
if (DEBUG_WINDOW_MOVEMENT) Slog.w(TAG_WM, "removeAllWindows: removing win=" + win);
win.removeIfPossible();
+ if (mChildren.contains(win)) {
+ removeChild(win);
+ }
}
- mChildren.clear();
}
void setExiting() {
@@ -200,11 +202,6 @@ class WindowToken extends WindowContainer<WindowState> {
return null;
}
- @CallSuper
- void removeWindow(WindowState win) {
- mChildren.remove(win);
- }
-
/** Returns true if the token windows list is empty. */
boolean isEmpty() {
return mChildren.isEmpty();
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index c5e2840d9565..96e9cb4ae96c 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -16,7 +16,6 @@
package com.android.server;
-import android.app.ActivityManagerNative;
import android.app.ActivityThread;
import android.app.INotificationManager;
import android.app.usage.UsageStatsManagerInternal;
@@ -32,7 +31,6 @@ import android.os.Build;
import android.os.Environment;
import android.os.FactoryTest;
import android.os.FileUtils;
-import android.os.IPowerManager;
import android.os.Looper;
import android.os.PowerManager;
import android.os.RemoteException;
@@ -79,6 +77,7 @@ import com.android.server.media.projection.MediaProjectionManagerService;
import com.android.server.net.NetworkPolicyManagerService;
import com.android.server.net.NetworkStatsService;
import com.android.server.notification.NotificationManagerService;
+import com.android.server.os.DeviceIdentifiersPolicyService;
import com.android.server.os.SchedulingPolicyService;
import com.android.server.pm.BackgroundDexOptService;
import com.android.server.pm.Installer;
@@ -427,6 +426,12 @@ public final class SystemServer {
Installer installer = mSystemServiceManager.startService(Installer.class);
traceEnd();
+ // In some cases after launching an app we need to access device identifiers,
+ // therefore register the device identifier policy before the activity manager.
+ traceBeginAndSlog("DeviceIdentifiersPolicyService");
+ mSystemServiceManager.startService(DeviceIdentifiersPolicyService.class);
+ traceEnd();
+
// Activity manager runs the show.
traceBeginAndSlog("StartActivityManager");
mActivityManagerService = mSystemServiceManager.startService(
@@ -593,6 +598,7 @@ public final class SystemServer {
false);
boolean disableConsumerIr = SystemProperties.getBoolean("config.disable_consumerir", false);
+ boolean disableVrManager = SystemProperties.getBoolean("config.disable_vrmanager", false);
boolean isEmulator = SystemProperties.get("ro.kernel.qemu").equals("1");
@@ -677,9 +683,11 @@ public final class SystemServer {
ServiceManager.addService(Context.INPUT_SERVICE, inputManager);
traceEnd();
- traceBeginAndSlog("StartVrManagerService");
- mSystemServiceManager.startService(VrManagerService.class);
- traceEnd();
+ if (!disableVrManager) {
+ traceBeginAndSlog("StartVrManagerService");
+ mSystemServiceManager.startService(VrManagerService.class);
+ traceEnd();
+ }
mActivityManagerService.setWindowManager(wm);
diff --git a/services/net/java/android/net/ip/IpManager.java b/services/net/java/android/net/ip/IpManager.java
index 6d9020390bef..215059d563f6 100644
--- a/services/net/java/android/net/ip/IpManager.java
+++ b/services/net/java/android/net/ip/IpManager.java
@@ -45,6 +45,7 @@ import android.util.SparseArray;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.IndentingPrintWriter;
+import com.android.internal.util.IState;
import com.android.internal.util.State;
import com.android.internal.util.StateMachine;
import com.android.server.net.NetlinkTracker;
@@ -395,6 +396,7 @@ public class IpManager extends StateMachine {
private final WakeupMessage mProvisioningTimeoutAlarm;
private final WakeupMessage mDhcpActionTimeoutAlarm;
private final LocalLog mLocalLog;
+ private final MessageHandlingLogger mMsgStateLogger;
private final IpConnectivityLog mMetricsLog = new IpConnectivityLog();
private NetworkInterface mNetworkInterface;
@@ -482,6 +484,7 @@ public class IpManager extends StateMachine {
setInitialState(mStoppedState);
mLocalLog = new LocalLog(MAX_LOG_RECORDS);
+ mMsgStateLogger = new MessageHandlingLogger();
super.start();
}
@@ -591,9 +594,9 @@ public class IpManager extends StateMachine {
@Override
protected String getLogRecString(Message msg) {
final String logLine = String.format(
- "%s/%d %d %d %s",
+ "%s/%d %d %d %s [%s]",
mInterfaceName, mNetworkInterface == null ? -1 : mNetworkInterface.getIndex(),
- msg.arg1, msg.arg2, Objects.toString(msg.obj));
+ msg.arg1, msg.arg2, Objects.toString(msg.obj), mMsgStateLogger);
final String richerLogLine = getWhatToString(msg.what) + " " + logLine;
mLocalLog.log(richerLogLine);
@@ -601,6 +604,7 @@ public class IpManager extends StateMachine {
Log.d(mTag, richerLogLine);
}
+ mMsgStateLogger.reset();
return logLine;
}
@@ -609,7 +613,11 @@ public class IpManager extends StateMachine {
// Don't log EVENT_NETLINK_LINKPROPERTIES_CHANGED. They can be noisy,
// and we already log any LinkProperties change that results in an
// invocation of IpManager.Callback#onLinkPropertiesChange().
- return (msg.what != EVENT_NETLINK_LINKPROPERTIES_CHANGED);
+ final boolean shouldLog = (msg.what != EVENT_NETLINK_LINKPROPERTIES_CHANGED);
+ if (!shouldLog) {
+ mMsgStateLogger.reset();
+ }
+ return shouldLog;
}
private void getNetworkInterface() {
@@ -965,7 +973,6 @@ public class IpManager extends StateMachine {
}
}
-
class StoppedState extends State {
@Override
public void enter() {
@@ -1015,6 +1022,8 @@ public class IpManager extends StateMachine {
default:
return NOT_HANDLED;
}
+
+ mMsgStateLogger.handled(this, getCurrentState());
return HANDLED;
}
}
@@ -1031,6 +1040,13 @@ public class IpManager extends StateMachine {
@Override
public boolean processMessage(Message msg) {
switch (msg.what) {
+ case CMD_STOP:
+ break;
+
+ case DhcpClient.CMD_CLEAR_LINKADDRESS:
+ clearIPv4Address();
+ break;
+
case DhcpClient.CMD_ON_QUIT:
mDhcpClient = null;
transitionTo(mStoppedState);
@@ -1039,6 +1055,8 @@ public class IpManager extends StateMachine {
default:
deferMessage(msg);
}
+
+ mMsgStateLogger.handled(this, getCurrentState());
return HANDLED;
}
}
@@ -1095,6 +1113,8 @@ public class IpManager extends StateMachine {
// is EVENT_NETLINK_LINKPROPERTIES_CHANGED (handled above).
deferMessage(msg);
}
+
+ mMsgStateLogger.handled(this, getCurrentState());
return HANDLED;
}
@@ -1302,7 +1322,29 @@ public class IpManager extends StateMachine {
default:
return NOT_HANDLED;
}
+
+ mMsgStateLogger.handled(this, getCurrentState());
return HANDLED;
}
}
+
+ private static class MessageHandlingLogger {
+ public String processedInState;
+ public String receivedInState;
+
+ public void reset() {
+ processedInState = null;
+ receivedInState = null;
+ }
+
+ public void handled(State processedIn, IState receivedIn) {
+ processedInState = processedIn.getClass().getSimpleName();
+ receivedInState = receivedIn.getName();
+ }
+
+ public String toString() {
+ return String.format("rcvd_in=%s, proc_in=%s",
+ receivedInState, processedInState);
+ }
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java b/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java
index de90de81a05e..340be6222173 100644
--- a/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java
@@ -82,6 +82,7 @@ import com.android.server.net.NetworkPinner;
import java.net.InetAddress;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Objects;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.LinkedBlockingQueue;
@@ -601,6 +602,7 @@ public class ConnectivityServiceTest extends AndroidTestCase {
private class WrappedConnectivityService extends ConnectivityService {
private WrappedNetworkMonitor mLastCreatedNetworkMonitor;
+ public boolean configRestrictsAvoidBadWifi;
public WrappedConnectivityService(Context context, INetworkManagementService netManager,
INetworkStatsService statsService, INetworkPolicyManager policyManager,
@@ -656,6 +658,11 @@ public class ConnectivityServiceTest extends AndroidTestCase {
return new FakeWakeupMessage(context, handler, cmdName, cmd, 0, 0, obj);
}
+ @Override
+ public boolean configRestrictsAvoidBadWifi() {
+ return configRestrictsAvoidBadWifi;
+ }
+
public WrappedNetworkMonitor getLastCreatedWrappedNetworkMonitor() {
return mLastCreatedNetworkMonitor;
}
@@ -2041,8 +2048,48 @@ public class ConnectivityServiceTest extends AndroidTestCase {
@SmallTest
public void testAvoidBadWifiSetting() throws Exception {
+ final ContentResolver cr = mServiceContext.getContentResolver();
+ final String settingName = Settings.Global.NETWORK_AVOID_BAD_WIFI;
+
+ mService.configRestrictsAvoidBadWifi = false;
+ String[] values = new String[] {null, "0", "1"};
+ for (int i = 0; i < values.length; i++) {
+ Settings.Global.putInt(cr, settingName, 1);
+ mService.updateNetworkAvoidBadWifi();
+ mService.waitForIdle();
+ String msg = String.format("config=false, setting=%s", values[i]);
+ assertTrue(msg, mService.avoidBadWifi());
+ assertFalse(msg, mService.shouldNotifyWifiUnvalidated());
+ }
+
+ mService.configRestrictsAvoidBadWifi = true;
+
+ Settings.Global.putInt(cr, settingName, 0);
+ mService.updateNetworkAvoidBadWifi();
+ mService.waitForIdle();
+ assertFalse(mService.avoidBadWifi());
+ assertFalse(mService.shouldNotifyWifiUnvalidated());
+
+ Settings.Global.putInt(cr, settingName, 1);
+ mService.updateNetworkAvoidBadWifi();
+ mService.waitForIdle();
+ assertTrue(mService.avoidBadWifi());
+ assertFalse(mService.shouldNotifyWifiUnvalidated());
+
+ Settings.Global.putString(cr, settingName, null);
+ mService.updateNetworkAvoidBadWifi();
+ mService.waitForIdle();
+ assertFalse(mService.avoidBadWifi());
+ assertTrue(mService.shouldNotifyWifiUnvalidated());
+ }
+
+ @SmallTest
+ public void testAvoidBadWifi() throws Exception {
ContentResolver cr = mServiceContext.getContentResolver();
+ // Pretend we're on a carrier that restricts switching away from bad wifi.
+ mService.configRestrictsAvoidBadWifi = true;
+
// File a request for cell to ensure it doesn't go down.
final TestNetworkCallback cellNetworkCallback = new TestNetworkCallback();
final NetworkRequest cellRequest = new NetworkRequest.Builder()
@@ -2059,8 +2106,8 @@ public class ConnectivityServiceTest extends AndroidTestCase {
TestNetworkCallback validatedWifiCallback = new TestNetworkCallback();
mCm.registerNetworkCallback(validatedWifiRequest, validatedWifiCallback);
- // Takes effect on every rematch.
Settings.Global.putInt(cr, Settings.Global.NETWORK_AVOID_BAD_WIFI, 0);
+ mService.updateNetworkAvoidBadWifi();
// Bring up validated cell.
mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
@@ -2089,7 +2136,42 @@ public class ConnectivityServiceTest extends AndroidTestCase {
NET_CAPABILITY_VALIDATED));
assertEquals(mCm.getActiveNetwork(), wifiNetwork);
- // Simulate the user selecting "switch" on the dialog.
+ // Simulate switching to a carrier that does not restrict avoiding bad wifi, and expect
+ // that we switch back to cell.
+ mService.configRestrictsAvoidBadWifi = false;
+ mService.updateNetworkAvoidBadWifi();
+ defaultCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
+ assertEquals(mCm.getActiveNetwork(), cellNetwork);
+
+ // Switch back to a restrictive carrier.
+ mService.configRestrictsAvoidBadWifi = true;
+ mService.updateNetworkAvoidBadWifi();
+ defaultCallback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent);
+ assertEquals(mCm.getActiveNetwork(), wifiNetwork);
+
+ // Simulate the user selecting "switch" on the dialog, and check that we switch to cell.
+ mCm.setAvoidUnvalidated(wifiNetwork);
+ defaultCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
+ assertFalse(mCm.getNetworkCapabilities(wifiNetwork).hasCapability(
+ NET_CAPABILITY_VALIDATED));
+ assertTrue(mCm.getNetworkCapabilities(cellNetwork).hasCapability(
+ NET_CAPABILITY_VALIDATED));
+ assertEquals(mCm.getActiveNetwork(), cellNetwork);
+
+ // Disconnect and reconnect wifi to clear the one-time switch above.
+ mWiFiNetworkAgent.disconnect();
+ mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+ mWiFiNetworkAgent.connect(true);
+ defaultCallback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent);
+ validatedWifiCallback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent);
+ wifiNetwork = mWiFiNetworkAgent.getNetwork();
+
+ // Fail validation on wifi and expect the dialog to appear.
+ mWiFiNetworkAgent.getWrappedNetworkMonitor().gen204ProbeResult = 599;
+ mCm.reportNetworkConnectivity(wifiNetwork, false);
+ validatedWifiCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
+
+ // Simulate the user selecting "switch" and checking the don't ask again checkbox.
Settings.Global.putInt(cr, Settings.Global.NETWORK_AVOID_BAD_WIFI, 1);
mService.updateNetworkAvoidBadWifi();
@@ -2101,6 +2183,17 @@ public class ConnectivityServiceTest extends AndroidTestCase {
NET_CAPABILITY_VALIDATED));
assertEquals(mCm.getActiveNetwork(), cellNetwork);
+ // Simulate the user turning the cellular fallback setting off and then on.
+ // We switch to wifi and then to cell.
+ Settings.Global.putString(cr, Settings.Global.NETWORK_AVOID_BAD_WIFI, null);
+ mService.updateNetworkAvoidBadWifi();
+ defaultCallback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent);
+ assertEquals(mCm.getActiveNetwork(), wifiNetwork);
+ Settings.Global.putInt(cr, Settings.Global.NETWORK_AVOID_BAD_WIFI, 1);
+ mService.updateNetworkAvoidBadWifi();
+ defaultCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
+ assertEquals(mCm.getActiveNetwork(), cellNetwork);
+
// If cell goes down, we switch to wifi.
mCellNetworkAgent.disconnect();
defaultCallback.expectCallback(CallbackState.LOST, mCellNetworkAgent);
diff --git a/services/tests/servicestests/src/com/android/server/connectivity/DnsEventListenerServiceTest.java b/services/tests/servicestests/src/com/android/server/connectivity/NetdEventListenerServiceTest.java
index 033b2c96c8f5..11cf528458f0 100644
--- a/services/tests/servicestests/src/com/android/server/connectivity/DnsEventListenerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/connectivity/NetdEventListenerServiceTest.java
@@ -20,7 +20,7 @@ import android.net.ConnectivityManager.NetworkCallback;
import android.net.ConnectivityManager;
import android.net.Network;
import android.net.metrics.DnsEvent;
-import android.net.metrics.IDnsEventListener;
+import android.net.metrics.INetdEventListener;
import android.net.metrics.IpConnectivityLog;
import junit.framework.TestCase;
@@ -47,12 +47,12 @@ import java.util.List;
import java.util.OptionalInt;
import java.util.stream.IntStream;
-public class DnsEventListenerServiceTest extends TestCase {
+public class NetdEventListenerServiceTest extends TestCase {
- // TODO: read from DnsEventListenerService after this constant is read from system property
+ // TODO: read from NetdEventListenerService after this constant is read from system property
static final int BATCH_SIZE = 100;
- static final int EVENT_TYPE = IDnsEventListener.EVENT_GETADDRINFO;
- // TODO: read from IDnsEventListener
+ static final int EVENT_TYPE = INetdEventListener.EVENT_GETADDRINFO;
+ // TODO: read from INetdEventListener
static final int RETURN_CODE = 1;
static final byte[] EVENT_TYPES = new byte[BATCH_SIZE];
@@ -66,7 +66,7 @@ public class DnsEventListenerServiceTest extends TestCase {
}
}
- DnsEventListenerService mDnsService;
+ NetdEventListenerService mNetdService;
@Mock ConnectivityManager mCm;
@Mock IpConnectivityLog mLog;
@@ -77,7 +77,7 @@ public class DnsEventListenerServiceTest extends TestCase {
MockitoAnnotations.initMocks(this);
mCallbackCaptor = ArgumentCaptor.forClass(NetworkCallback.class);
mEvCaptor = ArgumentCaptor.forClass(DnsEvent.class);
- mDnsService = new DnsEventListenerService(mCm, mLog);
+ mNetdService = new NetdEventListenerService(mCm, mLog);
verify(mCm, times(1)).registerNetworkCallback(any(), mCallbackCaptor.capture());
}
@@ -131,7 +131,7 @@ public class DnsEventListenerServiceTest extends TestCase {
new Thread() {
public void run() {
while (System.currentTimeMillis() < stop) {
- mDnsService.dump(pw);
+ mNetdService.dump(pw);
}
}
}.start();
@@ -158,7 +158,7 @@ public class DnsEventListenerServiceTest extends TestCase {
void log(int netId, int[] latencies) {
for (int l : latencies) {
- mDnsService.onDnsEvent(netId, EVENT_TYPE, RETURN_CODE, l);
+ mNetdService.onDnsEvent(netId, EVENT_TYPE, RETURN_CODE, l);
}
}
diff --git a/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java b/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java
index 0afbd0ce5607..fee47831bb0c 100644
--- a/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java
+++ b/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java
@@ -730,4 +730,14 @@ public class TestWindowManagerPolicy implements WindowManagerPolicy {
public boolean shouldRotateSeamlessly(int oldRotation, int newRotation) {
return false;
}
+
+ @Override
+ public void setTvPipVisibilityLw(boolean visible) {
+
+ }
+
+ @Override
+ public void setRecentsVisibilityLw(boolean visible) {
+
+ }
}
diff --git a/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java b/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java
index 4a70060d5097..f4f92ec4d2b2 100644
--- a/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java
+++ b/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java
@@ -461,6 +461,16 @@ public class IWindowManagerImpl implements IWindowManager {
}
@Override
+ public void setRecentsVisibility(boolean visible) {
+ // TODO Auto-generated method stub
+ }
+
+ @Override
+ public void setTvPipVisibility(boolean visible) {
+ // TODO Auto-generated method stub
+ }
+
+ @Override
public void stopAppFreezingScreen(IBinder arg0, boolean arg1) throws RemoteException {
// TODO Auto-generated method stub
}
diff --git a/wifi/java/android/net/wifi/WifiScanner.java b/wifi/java/android/net/wifi/WifiScanner.java
index 06e1b681fbef..5847f798712d 100644
--- a/wifi/java/android/net/wifi/WifiScanner.java
+++ b/wifi/java/android/net/wifi/WifiScanner.java
@@ -34,9 +34,10 @@ import com.android.internal.util.AsyncChannel;
import com.android.internal.util.Preconditions;
import com.android.internal.util.Protocol;
+import java.util.ArrayList;
+import java.util.Arrays;
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
@@ -822,6 +823,22 @@ public class WifiScanner {
mAsyncChannel.sendMessage(CMD_STOP_SINGLE_SCAN, 0, key);
}
+ /**
+ * Retrieve the most recent scan results from a single scan request.
+ * {@hide}
+ */
+ public List<ScanResult> getSingleScanResults() {
+ validateChannel();
+ Message reply = mAsyncChannel.sendMessageSynchronously(CMD_GET_SINGLE_SCAN_RESULTS, 0);
+ if (reply.what == WifiScanner.CMD_OP_SUCCEEDED) {
+ return Arrays.asList(((ParcelableScanResults) reply.obj).getResults());
+ }
+ OperationResult result = (OperationResult) reply.obj;
+ Log.e(TAG, "Error retrieving SingleScan results reason: " + result.reason
+ + " description: " + result.description);
+ return new ArrayList<ScanResult>();
+ }
+
private void startPnoScan(ScanSettings scanSettings, PnoSettings pnoSettings, int key) {
// Bundle up both the settings and send it across.
Bundle pnoParams = new Bundle();
@@ -1201,6 +1218,8 @@ public class WifiScanner {
public static final int CMD_REGISTER_SCAN_LISTENER = BASE + 27;
/** @hide */
public static final int CMD_DEREGISTER_SCAN_LISTENER = BASE + 28;
+ /** @hide */
+ public static final int CMD_GET_SINGLE_SCAN_RESULTS = BASE + 29;
private Context mContext;
private IWifiScanner mService;
diff --git a/wifi/java/android/net/wifi/nan/IWifiNanSessionCallback.aidl b/wifi/java/android/net/wifi/nan/IWifiNanDiscoverySessionCallback.aidl
index ff2c409c1dd5..8c1b892f6730 100644
--- a/wifi/java/android/net/wifi/nan/IWifiNanSessionCallback.aidl
+++ b/wifi/java/android/net/wifi/nan/IWifiNanDiscoverySessionCallback.aidl
@@ -21,7 +21,7 @@ package android.net.wifi.nan;
*
* {@hide}
*/
-oneway interface IWifiNanSessionCallback
+oneway interface IWifiNanDiscoverySessionCallback
{
void onSessionStarted(int sessionId);
void onSessionConfigSuccess();
diff --git a/wifi/java/android/net/wifi/nan/IWifiNanManager.aidl b/wifi/java/android/net/wifi/nan/IWifiNanManager.aidl
index 17ec1bc240e0..4711bad31f12 100644
--- a/wifi/java/android/net/wifi/nan/IWifiNanManager.aidl
+++ b/wifi/java/android/net/wifi/nan/IWifiNanManager.aidl
@@ -19,8 +19,8 @@ package android.net.wifi.nan;
import android.app.PendingIntent;
import android.net.wifi.nan.ConfigRequest;
+import android.net.wifi.nan.IWifiNanDiscoverySessionCallback;
import android.net.wifi.nan.IWifiNanEventCallback;
-import android.net.wifi.nan.IWifiNanSessionCallback;
import android.net.wifi.nan.PublishConfig;
import android.net.wifi.nan.SubscribeConfig;
import android.net.wifi.RttManager;
@@ -42,9 +42,10 @@ interface IWifiNanManager
in ConfigRequest configRequest);
void disconnect(int clientId, in IBinder binder);
- void publish(int clientId, in PublishConfig publishConfig, in IWifiNanSessionCallback callback);
+ void publish(int clientId, in PublishConfig publishConfig,
+ in IWifiNanDiscoverySessionCallback callback);
void subscribe(int clientId, in SubscribeConfig subscribeConfig,
- in IWifiNanSessionCallback callback);
+ in IWifiNanDiscoverySessionCallback callback);
// session API
void updatePublish(int clientId, int sessionId, in PublishConfig publishConfig);
diff --git a/wifi/java/android/net/wifi/nan/PublishConfig.java b/wifi/java/android/net/wifi/nan/PublishConfig.java
index 6203f9539e7c..f988c0b03ca5 100644
--- a/wifi/java/android/net/wifi/nan/PublishConfig.java
+++ b/wifi/java/android/net/wifi/nan/PublishConfig.java
@@ -32,8 +32,8 @@ import java.util.Arrays;
/**
* Defines the configuration of a NAN publish session. Built using
* {@link PublishConfig.Builder}. A publish session is created using
- * {@link WifiNanManager#publish(PublishConfig, WifiNanSessionCallback)} or updated using
- * {@link WifiNanPublishSession#updatePublish(PublishConfig)}.
+ * {@link WifiNanManager#publish(PublishConfig, WifiNanDiscoverySessionCallback)} or updated using
+ * {@link WifiNanPublishDiscoverySession#updatePublish(PublishConfig)}.
*
* @hide PROPOSED_NAN_API
*/
@@ -318,12 +318,13 @@ public final class PublishConfig implements Parcelable {
* Sets the number of times an unsolicited (configured using
* {@link PublishConfig.Builder#setPublishType(int)}) publish session
* will be broadcast. When the count is reached an event will be
- * generated for {@link WifiNanSessionCallback#onSessionTerminated(int)}
- * with {@link WifiNanSessionCallback#TERMINATE_REASON_DONE} [unless
+ * generated for {@link WifiNanDiscoverySessionCallback#onSessionTerminated(int)}
+ * with {@link WifiNanDiscoverySessionCallback#TERMINATE_REASON_DONE} [unless
* {@link #setEnableTerminateNotification(boolean)} disables the callback].
* <p>
* Optional. 0 by default - indicating the session doesn't terminate on its own.
- * Session will be terminated when {@link WifiNanSession#terminate()} is called.
+ * Session will be terminated when {@link WifiNanDiscoveryBaseSession#terminate()} is
+ * called.
*
* @param publishCount Number of publish packets to broadcast.
*
@@ -343,12 +344,13 @@ public final class PublishConfig implements Parcelable {
* {@link PublishConfig.Builder#setPublishType(int)}) publish session
* will be alive - broadcasting a packet. When the TTL is reached
* an event will be generated for
- * {@link WifiNanSessionCallback#onSessionTerminated(int)} with
- * {@link WifiNanSessionCallback#TERMINATE_REASON_DONE} [unless
+ * {@link WifiNanDiscoverySessionCallback#onSessionTerminated(int)} with
+ * {@link WifiNanDiscoverySessionCallback#TERMINATE_REASON_DONE} [unless
* {@link #setEnableTerminateNotification(boolean)} disables the callback].
* <p>
* Optional. 0 by default - indicating the session doesn't terminate on its own.
- * Session will be terminated when {@link WifiNanSession#terminate()} is called.
+ * Session will be terminated when {@link WifiNanDiscoveryBaseSession#terminate()} is
+ * called.
*
* @param ttlSec Lifetime of a publish session in seconds.
*
@@ -365,7 +367,7 @@ public final class PublishConfig implements Parcelable {
/**
* Configure whether a publish terminate notification
- * {@link WifiNanSessionCallback#onSessionTerminated(int)} is reported
+ * {@link WifiNanDiscoverySessionCallback#onSessionTerminated(int)} is reported
* back to the callback.
*
* @param enable If true the terminate callback will be called when the
diff --git a/wifi/java/android/net/wifi/nan/SubscribeConfig.java b/wifi/java/android/net/wifi/nan/SubscribeConfig.java
index 5a2c76272f78..47f9398b642f 100644
--- a/wifi/java/android/net/wifi/nan/SubscribeConfig.java
+++ b/wifi/java/android/net/wifi/nan/SubscribeConfig.java
@@ -32,8 +32,8 @@ import java.util.Arrays;
/**
* Defines the configuration of a NAN subscribe session. Built using
* {@link SubscribeConfig.Builder}. Subscribe is done using
- * {@link WifiNanManager#subscribe(SubscribeConfig, WifiNanSessionCallback)} or
- * {@link WifiNanSubscribeSession#updateSubscribe(SubscribeConfig)}.
+ * {@link WifiNanManager#subscribe(SubscribeConfig, WifiNanDiscoverySessionCallback)} or
+ * {@link WifiNanSubscribeDiscoverySession#updateSubscribe(SubscribeConfig)}.
*
* @hide PROPOSED_NAN_API
*/
@@ -350,11 +350,12 @@ public final class SubscribeConfig implements Parcelable {
* Sets the number of times an active (
* {@link SubscribeConfig.Builder#setSubscribeType(int)}) subscribe session
* will broadcast. When the count is reached an event will be
- * generated for {@link WifiNanSessionCallback#onSessionTerminated(int)}
- * with {@link WifiNanSessionCallback#TERMINATE_REASON_DONE}.
+ * generated for {@link WifiNanDiscoverySessionCallback#onSessionTerminated(int)}
+ * with {@link WifiNanDiscoverySessionCallback#TERMINATE_REASON_DONE}.
* <p>
* Optional. 0 by default - indicating the session doesn't terminate on its own.
- * Session will be terminated when {@link WifiNanSession#terminate()} is called.
+ * Session will be terminated when {@link WifiNanDiscoveryBaseSession#terminate()} is
+ * called.
*
* @param subscribeCount Number of subscribe packets to broadcast.
*
@@ -374,11 +375,12 @@ public final class SubscribeConfig implements Parcelable {
* {@link SubscribeConfig.Builder#setSubscribeType(int)}) subscribe session
* will be alive - i.e. broadcasting a packet. When the TTL is reached
* an event will be generated for
- * {@link WifiNanSessionCallback#onSessionTerminated(int)} with
- * {@link WifiNanSessionCallback#TERMINATE_REASON_DONE}.
+ * {@link WifiNanDiscoverySessionCallback#onSessionTerminated(int)} with
+ * {@link WifiNanDiscoverySessionCallback#TERMINATE_REASON_DONE}.
* <p>
* Optional. 0 by default - indicating the session doesn't terminate on its own.
- * Session will be terminated when {@link WifiNanSession#terminate()} is called.
+ * Session will be terminated when {@link WifiNanDiscoveryBaseSession#terminate()} is
+ * called.
*
* @param ttlSec Lifetime of a subscribe session in seconds.
*
@@ -397,7 +399,7 @@ public final class SubscribeConfig implements Parcelable {
* Sets the match style of the subscription - how are matches from a
* single match session (corresponding to the same publish action on the
* peer) reported to the host (using the
- * {@link WifiNanSessionCallback#onMatch(int, byte[], byte[])}
+ * {@link WifiNanDiscoverySessionCallback#onMatch(int, byte[], byte[])}
* ). The options are: only report the first match and ignore the rest
* {@link SubscribeConfig#MATCH_STYLE_FIRST_ONLY} or report every single
* match {@link SubscribeConfig#MATCH_STYLE_ALL} (the default).
@@ -417,7 +419,7 @@ public final class SubscribeConfig implements Parcelable {
/**
* Configure whether a subscribe terminate notification
- * {@link WifiNanSessionCallback#onSessionTerminated(int)} is reported
+ * {@link WifiNanDiscoverySessionCallback#onSessionTerminated(int)} is reported
* back to the callback.
*
* @param enable If true the terminate callback will be called when the
diff --git a/wifi/java/android/net/wifi/nan/WifiNanSession.java b/wifi/java/android/net/wifi/nan/WifiNanDiscoveryBaseSession.java
index 005ca291cbf5..58971dbdae28 100644
--- a/wifi/java/android/net/wifi/nan/WifiNanSession.java
+++ b/wifi/java/android/net/wifi/nan/WifiNanDiscoveryBaseSession.java
@@ -17,7 +17,6 @@
package android.net.wifi.nan;
import android.annotation.Nullable;
-import android.annotation.SystemApi;
import android.net.wifi.RttManager;
import android.util.Log;
@@ -28,8 +27,8 @@ import java.lang.ref.WeakReference;
/**
* A class representing a single publish or subscribe NAN session. This object
* will not be created directly - only its child classes are available:
- * {@link WifiNanPublishSession} and {@link WifiNanSubscribeSession}. This class provides
- * functionality common to both publish and subscribe discovery sessions:
+ * {@link WifiNanPublishDiscoverySession} and {@link WifiNanSubscribeDiscoverySession}. This
+ * class provides functionality common to both publish and subscribe discovery sessions:
* <ul>
* <li>Sending messages: {@link #sendMessage(int, byte[], int)} or
* {@link #sendMessage(int, byte[], int, int)} methods.
@@ -41,8 +40,8 @@ import java.lang.ref.WeakReference;
*
* @hide PROPOSED_NAN_API
*/
-public class WifiNanSession {
- private static final String TAG = "WifiNanSession";
+public class WifiNanDiscoveryBaseSession {
+ private static final String TAG = "WifiNanDiscoveryBaseSsn";
private static final boolean DBG = false;
private static final boolean VDBG = false; // STOPSHIP if true
@@ -68,7 +67,7 @@ public class WifiNanSession {
}
/** @hide */
- public WifiNanSession(WifiNanManager manager, int sessionId) {
+ public WifiNanDiscoveryBaseSession(WifiNanManager manager, int sessionId) {
if (VDBG) Log.v(TAG, "New client created: manager=" + manager + ", sessionId=" + sessionId);
mMgr = new WeakReference<>(manager);
@@ -86,7 +85,7 @@ public class WifiNanSession {
* This operation must be done on a session which is no longer needed. Otherwise system
* resources will continue to be utilized until the application terminates. The only
* exception is a session for which we received a termination callback,
- * {@link WifiNanSessionCallback#onSessionTerminated(int)}.
+ * {@link WifiNanDiscoverySessionCallback#onSessionTerminated(int)}.
*/
public void terminate() {
WifiNanManager mgr = mMgr.get();
@@ -132,20 +131,20 @@ public class WifiNanSession {
/**
* Sends a message to the specified destination. NAN messages are transmitted in the context
* of a discovery session - executed subsequent to a publish/subscribe
- * {@link WifiNanSessionCallback#onMatch(int, byte[], byte[])} event.
+ * {@link WifiNanDiscoverySessionCallback#onMatch(int, byte[], byte[])} event.
* <p>
- * NAN messages are not guaranteed delivery. Callbacks on {@link WifiNanSessionCallback}
- * indicate message was transmitted successfully,
- * {@link WifiNanSessionCallback#onMessageSendSuccess(int)}, or transmission failed
+ * NAN messages are not guaranteed delivery. Callbacks on
+ * {@link WifiNanDiscoverySessionCallback} indicate message was transmitted successfully,
+ * {@link WifiNanDiscoverySessionCallback#onMessageSendSuccess(int)}, or transmission failed
* (possibly after several retries) -
- * {@link WifiNanSessionCallback#onMessageSendFail(int, int)}.
+ * {@link WifiNanDiscoverySessionCallback#onMessageSendFail(int, int)}.
* <p>
* The peer will get a callback indicating a message was received using
- * {@link WifiNanSessionCallback#onMessageReceived(int, byte[])}.
+ * {@link WifiNanDiscoverySessionCallback#onMessageReceived(int, byte[])}.
*
* @param peerId The peer's ID for the message. Must be a result of an
- * {@link WifiNanSessionCallback#onMatch(int, byte[], byte[])} or
- * {@link WifiNanSessionCallback#onMessageReceived(int, byte[])} events.
+ * {@link WifiNanDiscoverySessionCallback#onMatch(int, byte[], byte[])} or
+ * {@link WifiNanDiscoverySessionCallback#onMessageReceived(int, byte[])} events.
* @param message The message to be transmitted.
* @param messageId An arbitrary integer used by the caller to identify the message. The same
* integer ID will be returned in the callbacks indicating message send success or
@@ -174,22 +173,22 @@ public class WifiNanSession {
/**
* Sends a message to the specified destination. NAN messages are transmitted in the context
* of a discovery session - executed subsequent to a publish/subscribe
- * {@link WifiNanSessionCallback#onMatch(int, byte[], byte[])} event.
+ * {@link WifiNanDiscoverySessionCallback#onMatch(int, byte[], byte[])} event.
* <p>
- * NAN messages are not guaranteed delivery. Callbacks on {@link WifiNanSessionCallback}
- * indicate message was transmitted successfully,
- * {@link WifiNanSessionCallback#onMessageSendSuccess(int)}, or transmission failed
+ * NAN messages are not guaranteed delivery. Callbacks on
+ * {@link WifiNanDiscoverySessionCallback} indicate message was transmitted successfully,
+ * {@link WifiNanDiscoverySessionCallback#onMessageSendSuccess(int)}, or transmission failed
* (possibly after several retries) -
- * {@link WifiNanSessionCallback#onMessageSendFail(int, int)}.
+ * {@link WifiNanDiscoverySessionCallback#onMessageSendFail(int, int)}.
* <p>
* The peer will get a callback indicating a message was received using
- * {@link WifiNanSessionCallback#onMessageReceived(int, byte[])}.
+ * {@link WifiNanDiscoverySessionCallback#onMessageReceived(int, byte[])}.
* Equivalent to {@link #sendMessage(int, byte[], int, int)} with a {@code retryCount} of
* 0.
*
* @param peerId The peer's ID for the message. Must be a result of an
- * {@link WifiNanSessionCallback#onMatch(int, byte[], byte[])} or
- * {@link WifiNanSessionCallback#onMessageReceived(int, byte[])} events.
+ * {@link WifiNanDiscoverySessionCallback#onMatch(int, byte[], byte[])} or
+ * {@link WifiNanDiscoverySessionCallback#onMessageReceived(int, byte[])} events.
* @param message The message to be transmitted.
* @param messageId An arbitrary integer used by the caller to identify the message. The same
* integer ID will be returned in the callbacks indicating message send success or
@@ -202,8 +201,8 @@ public class WifiNanSession {
/**
* Start a ranging operation with the specified peers. The peer IDs are obtained from an
- * {@link WifiNanSessionCallback#onMatch(int, byte[], byte[])} or
- * {@link WifiNanSessionCallback#onMessageReceived(int, byte[])} operation - can only
+ * {@link WifiNanDiscoverySessionCallback#onMatch(int, byte[], byte[])} or
+ * {@link WifiNanDiscoverySessionCallback#onMessageReceived(int, byte[])} operation - can only
* range devices which are part of an ongoing discovery session.
*
* @param params RTT parameters - each corresponding to a specific peer ID (the array sizes
@@ -245,8 +244,8 @@ public class WifiNanSession {
* {@link WifiNanManager#WIFI_NAN_DATA_PATH_ROLE_INITIATOR} or
* {@link WifiNanManager#WIFI_NAN_DATA_PATH_ROLE_RESPONDER}
* @param peerId The peer ID obtained through
- * {@link WifiNanSessionCallback#onMatch(int, byte[], byte[])} or
- * {@link WifiNanSessionCallback#onMessageReceived(int, byte[])}. On a RESPONDER this
+ * {@link WifiNanDiscoverySessionCallback#onMatch(int, byte[], byte[])} or
+ * {@link WifiNanDiscoverySessionCallback#onMessageReceived(int, byte[])}. On a RESPONDER this
* value is used to gate the acceptance of a connection request from only that
* peer. A RESPONDER may specified a 0 - indicating that it will accept
* connection requests from any device.
diff --git a/wifi/java/android/net/wifi/nan/WifiNanSessionCallback.java b/wifi/java/android/net/wifi/nan/WifiNanDiscoverySessionCallback.java
index 8433b99315ce..685e1524a27a 100644
--- a/wifi/java/android/net/wifi/nan/WifiNanSessionCallback.java
+++ b/wifi/java/android/net/wifi/nan/WifiNanDiscoverySessionCallback.java
@@ -26,14 +26,14 @@ import java.lang.annotation.RetentionPolicy;
* Base class for NAN session events callbacks. Should be extended by
* applications wanting notifications. The callbacks are set when a
* publish or subscribe session is created using
- * {@link WifiNanManager#publish(PublishConfig, WifiNanSessionCallback)} or
- * {@link WifiNanManager#subscribe(SubscribeConfig, WifiNanSessionCallback)} .
+ * {@link WifiNanManager#publish(PublishConfig, WifiNanDiscoverySessionCallback)} or
+ * {@link WifiNanManager#subscribe(SubscribeConfig, WifiNanDiscoverySessionCallback)} .
* <p>
* A single callback is set at session creation - it cannot be replaced.
*
* @hide PROPOSED_NAN_API
*/
-public class WifiNanSessionCallback {
+public class WifiNanDiscoverySessionCallback {
/** @hide */
@IntDef({
REASON_NO_RESOURCES, REASON_INVALID_ARGS, REASON_NO_MATCH_SESSION,
@@ -51,20 +51,20 @@ public class WifiNanSessionCallback {
/**
* Indicates no resources to execute the requested operation.
- * Failure reason flag for {@link WifiNanSessionCallback} callbacks.
+ * Failure reason flag for {@link WifiNanDiscoverySessionCallback} callbacks.
*/
public static final int REASON_NO_RESOURCES = 0;
/**
* Indicates invalid argument in the requested operation.
- * Failure reason flag for {@link WifiNanSessionCallback} callbacks.
+ * Failure reason flag for {@link WifiNanDiscoverySessionCallback} callbacks.
*/
public static final int REASON_INVALID_ARGS = 1;
/**
* Indicates a message is transmitted without a match (a discovery) or received message
* from peer occurring first.
- * Failure reason flag for {@link WifiNanSessionCallback} callbacks.
+ * Failure reason flag for {@link WifiNanDiscoverySessionCallback} callbacks.
*/
public static final int REASON_NO_MATCH_SESSION = 2;
@@ -72,13 +72,13 @@ public class WifiNanSessionCallback {
* Indicates transmission failure: this may be due to local transmission
* failure or to no ACK received - remote device didn't receive the
* sent message. Failure reason flag for
- * {@link WifiNanSessionCallback#onMessageSendFail(int, int)} callback.
+ * {@link WifiNanDiscoverySessionCallback#onMessageSendFail(int, int)} callback.
*/
public static final int REASON_TX_FAIL = 3;
/**
* Indicates an unspecified error occurred during the operation.
- * Failure reason flag for {@link WifiNanSessionCallback} callbacks.
+ * Failure reason flag for {@link WifiNanDiscoverySessionCallback} callbacks.
*/
public static final int REASON_OTHER = 4;
@@ -86,7 +86,7 @@ public class WifiNanSessionCallback {
* Indicates that publish or subscribe session is done - all the
* requested operations (per {@link PublishConfig} or
* {@link SubscribeConfig}) have been executed. Failure reason flag for
- * {@link WifiNanSessionCallback#onSessionTerminated(int)} callback.
+ * {@link WifiNanDiscoverySessionCallback#onSessionTerminated(int)} callback.
*/
public static final int TERMINATE_REASON_DONE = 100;
@@ -94,36 +94,37 @@ public class WifiNanSessionCallback {
* Indicates that publish or subscribe session is terminated due to a
* failure.
* Failure reason flag for
- * {@link WifiNanSessionCallback#onSessionTerminated(int)} callback.
+ * {@link WifiNanDiscoverySessionCallback#onSessionTerminated(int)} callback.
*/
public static final int TERMINATE_REASON_FAIL = 101;
/**
* Called when a publish operation is started successfully in response to a
- * {@link WifiNanManager#publish(PublishConfig, WifiNanSessionCallback)} operation.
+ * {@link WifiNanManager#publish(PublishConfig, WifiNanDiscoverySessionCallback)} operation.
*
- * @param session The {@link WifiNanPublishSession} used to control the
+ * @param session The {@link WifiNanPublishDiscoverySession} used to control the
* discovery session.
*/
- public void onPublishStarted(@NonNull WifiNanPublishSession session) {
+ public void onPublishStarted(@NonNull WifiNanPublishDiscoverySession session) {
/* empty */
}
/**
* Called when a subscribe operation is started successfully in response to a
- * {@link WifiNanManager#subscribe(SubscribeConfig, WifiNanSessionCallback)} operation.
+ * {@link WifiNanManager#subscribe(SubscribeConfig, WifiNanDiscoverySessionCallback)} operation.
*
- * @param session The {@link WifiNanSubscribeSession} used to control the
+ * @param session The {@link WifiNanSubscribeDiscoverySession} used to control the
* discovery session.
*/
- public void onSubscribeStarted(@NonNull WifiNanSubscribeSession session) {
+ public void onSubscribeStarted(@NonNull WifiNanSubscribeDiscoverySession session) {
/* empty */
}
/**
* Called when a publish or subscribe discovery session configuration is update request
- * succeeds. Called in response to {@link WifiNanPublishSession#updatePublish(PublishConfig)}
- * or {@link WifiNanSubscribeSession#updateSubscribe(SubscribeConfig)}.
+ * succeeds. Called in response to
+ * {@link WifiNanPublishDiscoverySession#updatePublish(PublishConfig)} or
+ * {@link WifiNanSubscribeDiscoverySession#updateSubscribe(SubscribeConfig)}.
*/
public void onSessionConfigSuccess() {
/* empty */
@@ -131,17 +132,17 @@ public class WifiNanSessionCallback {
/**
* Called when a publish or subscribe discovery session cannot be created:
- * {@link WifiNanManager#publish(PublishConfig, WifiNanSessionCallback)} or
- * {@link WifiNanManager#subscribe(SubscribeConfig, WifiNanSessionCallback)},
+ * {@link WifiNanManager#publish(PublishConfig, WifiNanDiscoverySessionCallback)} or
+ * {@link WifiNanManager#subscribe(SubscribeConfig, WifiNanDiscoverySessionCallback)},
* or when a configuration update fails:
- * {@link WifiNanPublishSession#updatePublish(PublishConfig)} or
- * {@link WifiNanSubscribeSession#updateSubscribe(SubscribeConfig)}.
+ * {@link WifiNanPublishDiscoverySession#updatePublish(PublishConfig)} or
+ * {@link WifiNanSubscribeDiscoverySession#updateSubscribe(SubscribeConfig)}.
* <p>
* For discovery session updates failure leaves the session running with its previous
* configuration - the discovery session is not terminated.
*
* @param reason The failure reason using
- * {@code WifiNanSessionCallback.REASON_*} codes.
+ * {@code WifiNanDiscoverySessionCallback.REASON_*} codes.
*/
public void onSessionConfigFail(@SessionReasonCodes int reason) {
/* empty */
@@ -149,12 +150,12 @@ public class WifiNanSessionCallback {
/**
* Called when a discovery session (publish or subscribe) terminates. Termination may be due
- * to user-request (either directly through {@link WifiNanSession#terminate()} or
+ * to user-request (either directly through {@link WifiNanDiscoveryBaseSession#terminate()} or
* application-specified expiration, e.g. {@link PublishConfig.Builder#setPublishCount(int)}
* or {@link SubscribeConfig.Builder#setTtlSec(int)}) or due to a failure.
*
* @param reason The termination reason using
- * {@code WifiNanSessionCallback.TERMINATE_*} codes.
+ * {@code WifiNanDiscoverySessionCallback.TERMINATE_*} codes.
*/
public void onSessionTerminated(@SessionTerminateCodes int reason) {
/* empty */
@@ -176,12 +177,12 @@ public class WifiNanSessionCallback {
}
/**
- * Called in response to {@link WifiNanSession#sendMessage(int, byte[], int)} when a message
- * is transmitted successfully - when it was received successfully by the peer
+ * Called in response to {@link WifiNanDiscoveryBaseSession#sendMessage(int, byte[], int)}
+ * when a message is transmitted successfully - when it was received successfully by the peer
* (corresponds to an ACK being received).
* <p>
* Note that either this callback or
- * {@link WifiNanSessionCallback#onMessageSendFail(int, int)} will be
+ * {@link WifiNanDiscoverySessionCallback#onMessageSendFail(int, int)} will be
* received - never both.
*
* @param messageId The arbitrary message ID specified when sending the message.
@@ -193,16 +194,16 @@ public class WifiNanSessionCallback {
/**
* Called when message transmission fails - when no ACK is received from the peer.
* Retries when ACKs are not received are done by hardware, MAC, and in the NAN stack (using
- * the {@link WifiNanSession#sendMessage(int, byte[], int, int)} method) - this
+ * the {@link WifiNanDiscoveryBaseSession#sendMessage(int, byte[], int, int)} method) - this
* event is received after all retries are exhausted.
* <p>
* Note that either this callback or
- * {@link WifiNanSessionCallback#onMessageSendSuccess(int)} will be received
+ * {@link WifiNanDiscoverySessionCallback#onMessageSendSuccess(int)} will be received
* - never both.
*
* @param messageId The arbitrary message ID specified when sending the message.
* @param reason The failure reason using
- * {@code WifiNanSessionCallback.REASON_*} codes.
+ * {@code WifiNanDiscoverySessionCallback.REASON_*} codes.
*/
public void onMessageSendFail(@SuppressWarnings("unused") int messageId,
@SessionReasonCodes int reason) {
@@ -211,8 +212,8 @@ public class WifiNanSessionCallback {
/**
* Called when a message is received from a discovery session peer - in response to the
- * peer's {@link WifiNanSession#sendMessage(int, byte[], int)} or
- * {@link WifiNanSession#sendMessage(int, byte[], int, int)}.
+ * peer's {@link WifiNanDiscoveryBaseSession#sendMessage(int, byte[], int)} or
+ * {@link WifiNanDiscoveryBaseSession#sendMessage(int, byte[], int, int)}.
*
* @param peerId The ID of the peer sending the message.
* @param message A byte array containing the message.
diff --git a/wifi/java/android/net/wifi/nan/WifiNanEventCallback.java b/wifi/java/android/net/wifi/nan/WifiNanEventCallback.java
index 029e36a41be6..a66afc189c4c 100644
--- a/wifi/java/android/net/wifi/nan/WifiNanEventCallback.java
+++ b/wifi/java/android/net/wifi/nan/WifiNanEventCallback.java
@@ -25,7 +25,7 @@ import java.lang.annotation.RetentionPolicy;
* Base class for NAN events callbacks. Should be extended by applications and set when calling
* {@link WifiNanManager#connect(android.os.Handler, WifiNanEventCallback)}. These are callbacks
* applying to the NAN connection as a whole - not to specific publish or subscribe sessions -
- * for that see {@link WifiNanSessionCallback}.
+ * for that see {@link WifiNanDiscoverySessionCallback}.
*
* @hide PROPOSED_NAN_API
*/
diff --git a/wifi/java/android/net/wifi/nan/WifiNanManager.java b/wifi/java/android/net/wifi/nan/WifiNanManager.java
index 24ee640a63df..6eb476d229ad 100644
--- a/wifi/java/android/net/wifi/nan/WifiNanManager.java
+++ b/wifi/java/android/net/wifi/nan/WifiNanManager.java
@@ -21,7 +21,6 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
-import android.annotation.SystemApi;
import android.content.Context;
import android.net.ConnectivityManager;
import android.net.NetworkRequest;
@@ -62,12 +61,12 @@ import java.util.Arrays;
* <li>Initialize a NAN cluster (peer-to-peer synchronization). Refer to
* {@link #connect(Handler, WifiNanEventCallback)}.
* <li>Create discovery sessions (publish or subscribe sessions).
- * Refer to {@link #publish(PublishConfig, WifiNanSessionCallback)} and
- * {@link #subscribe(SubscribeConfig, WifiNanSessionCallback)}.
+ * Refer to {@link #publish(PublishConfig, WifiNanDiscoverySessionCallback)} and
+ * {@link #subscribe(SubscribeConfig, WifiNanDiscoverySessionCallback)}.
* <li>Create a NAN network specifier to be used with
* {@link ConnectivityManager#requestNetwork(NetworkRequest, ConnectivityManager.NetworkCallback)}
* to set-up a NAN connection with a peer. Refer to
- * {@link WifiNanSession#createNetworkSpecifier(int, int, byte[])} and
+ * {@link WifiNanDiscoveryBaseSession#createNetworkSpecifier(int, int, byte[])} and
* {@link #createNetworkSpecifier(int, byte[], byte[])}.
* </ul>
* <p>
@@ -89,19 +88,21 @@ import java.util.Arrays;
* device will actually disconnect from the NAN cluster once the last application disconnects.
* <p>
* Once a NAN connection is confirmed use the
- * {@link #publish(PublishConfig, WifiNanSessionCallback)} or
- * {@link #subscribe(SubscribeConfig, WifiNanSessionCallback)} to create publish or subscribe
- * NAN discovery sessions. Events are called on the provided callback object
- * {@link WifiNanSessionCallback}. Specifically, the
- * {@link WifiNanSessionCallback#onPublishStarted(WifiNanPublishSession)} and
- * {@link WifiNanSessionCallback#onSubscribeStarted(WifiNanSubscribeSession)} return
- * {@link WifiNanPublishSession} and {@link WifiNanSubscribeSession} objects respectively on
- * which additional session operations can be performed, e.g. updating the session
- * {@link WifiNanPublishSession#updatePublish(PublishConfig)} and
- * {@link WifiNanSubscribeSession#updateSubscribe(SubscribeConfig)}. Sessions can also be
- * used to send messages using the {@link WifiNanSession#sendMessage(int, byte[], int)} APIs.
- * When an application is finished with a discovery session it <b>must</b> terminate it using
- * the {@link WifiNanSession#terminate()} API.
+ * {@link #publish(PublishConfig, WifiNanDiscoverySessionCallback)} or
+ * {@link #subscribe(SubscribeConfig, WifiNanDiscoverySessionCallback)} to create publish or
+ * subscribe NAN discovery sessions. Events are called on the provided callback object
+ * {@link WifiNanDiscoverySessionCallback}. Specifically, the
+ * {@link WifiNanDiscoverySessionCallback#onPublishStarted(WifiNanPublishDiscoverySession)}
+ * and
+ * {@link WifiNanDiscoverySessionCallback#onSubscribeStarted(WifiNanSubscribeDiscoverySession)}
+ * return {@link WifiNanPublishDiscoverySession} and {@link WifiNanSubscribeDiscoverySession}
+ * objects respectively on which additional session operations can be performed, e.g. updating
+ * the session {@link WifiNanPublishDiscoverySession#updatePublish(PublishConfig)} and
+ * {@link WifiNanSubscribeDiscoverySession#updateSubscribe(SubscribeConfig)}. Sessions can also
+ * be used to send messages using the
+ * {@link WifiNanDiscoveryBaseSession#sendMessage(int, byte[], int)} APIs. When an application
+ * is finished with a discovery session it <b>must</b> terminate it using the
+ * {@link WifiNanDiscoveryBaseSession#terminate()} API.
* <p>
* Creating connections between NAN devices is managed by the standard
* {@link ConnectivityManager#requestNetwork(NetworkRequest, ConnectivityManager.NetworkCallback)}.
@@ -111,7 +112,7 @@ import java.util.Arrays;
* {@link android.net.NetworkCapabilities#TRANSPORT_WIFI_NAN}.
* <li>{@link NetworkRequest.Builder#setNetworkSpecifier(String)} using
* {@link #createNetworkSpecifier(int, byte[], byte[])} or
- * {@link WifiNanSession#createNetworkSpecifier(int, int, byte[])}.
+ * {@link WifiNanDiscoveryBaseSession#createNetworkSpecifier(int, int, byte[])}.
* </ul>
*
* @hide PROPOSED_NAN_API
@@ -249,7 +250,7 @@ public class WifiNanManager {
* Connection creation role is that of INITIATOR. Used to create a network specifier string
* when requesting a NAN network.
*
- * @see WifiNanSession#createNetworkSpecifier(int, int, byte[])
+ * @see WifiNanDiscoveryBaseSession#createNetworkSpecifier(int, int, byte[])
* @see #createNetworkSpecifier(int, byte[], byte[])
*/
public static final int WIFI_NAN_DATA_PATH_ROLE_INITIATOR = 0;
@@ -258,7 +259,7 @@ public class WifiNanManager {
* Connection creation role is that of RESPONDER. Used to create a network specifier string
* when requesting a NAN network.
*
- * @see WifiNanSession#createNetworkSpecifier(int, int, byte[])
+ * @see WifiNanDiscoveryBaseSession#createNetworkSpecifier(int, int, byte[])
* @see #createNetworkSpecifier(int, byte[], byte[])
*/
public static final int WIFI_NAN_DATA_PATH_ROLE_RESPONDER = 1;
@@ -445,30 +446,30 @@ public class WifiNanManager {
/**
* Issue a request to the NAN service to create a new NAN publish discovery session, using
* the specified {@code publishConfig} configuration. The results of the publish operation
- * are routed to the callbacks of {@link WifiNanSessionCallback}:
+ * are routed to the callbacks of {@link WifiNanDiscoverySessionCallback}:
* <ul>
- * <li>{@link WifiNanSessionCallback#onPublishStarted(WifiNanPublishSession)} is called
- * when the publish session is created and provides a handle to the session. Further
- * operations on the publish session can be executed on that object.
- * <li>{@link WifiNanSessionCallback#onSessionConfigFail(int)} is called if the publish
- * operation failed.
+ * <li>{@link WifiNanDiscoverySessionCallback#onPublishStarted(WifiNanPublishDiscoverySession)}
+ * is called when the publish session is created and provides a handle to the session.
+ * Further operations on the publish session can be executed on that object.
+ * <li>{@link WifiNanDiscoverySessionCallback#onSessionConfigFail(int)} is called if the
+ * publish operation failed.
* </ul>
* <p>
* Other results of the publish session operations will also be routed to callbacks
* on the {@code callback} object. The resulting publish session can be modified using
- * {@link WifiNanPublishSession#updatePublish(PublishConfig)}.
+ * {@link WifiNanPublishDiscoverySession#updatePublish(PublishConfig)}.
* <p>
- * An application must use the {@link WifiNanSession#terminate()} to terminate the publish
- * discovery session once it isn't needed. This will free resources as well terminate
- * any on-air transmissions.
+ * An application must use the {@link WifiNanDiscoveryBaseSession#terminate()} to
+ * terminate the publish discovery session once it isn't needed. This will free
+ * resources as well terminate any on-air transmissions.
*
* @param publishConfig The {@link PublishConfig} specifying the
* configuration of the requested publish session.
- * @param callback A {@link WifiNanSessionCallback} derived object to be used for session
- * event callbacks.
+ * @param callback A {@link WifiNanDiscoverySessionCallback} derived object to be used for
+ * session event callbacks.
*/
public void publish(@NonNull PublishConfig publishConfig,
- @NonNull WifiNanSessionCallback callback) {
+ @NonNull WifiNanDiscoverySessionCallback callback) {
if (VDBG) Log.v(TAG, "publish(): config=" + publishConfig);
int clientId;
@@ -485,7 +486,7 @@ public class WifiNanManager {
}
try {
mService.publish(clientId, publishConfig,
- new WifiNanSessionCallbackProxy(this, looper, true, callback));
+ new WifiNanDiscoverySessionCallbackProxy(this, looper, true, callback));
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -514,30 +515,30 @@ public class WifiNanManager {
/**
* Issue a request to the NAN service to create a new NAN subscribe discovery session, using
* the specified {@code subscribeConfig} configuration. The results of the subscribe
- * operation are routed to the callbacks of {@link WifiNanSessionCallback}:
+ * operation are routed to the callbacks of {@link WifiNanDiscoverySessionCallback}:
* <ul>
- * <li>{@link WifiNanSessionCallback#onSubscribeStarted(WifiNanSubscribeSession)} is called
- * when the subscribe session is created and provides a handle to the session. Further
- * operations on the subscribe session can be executed on that object.
- * <li>{@link WifiNanSessionCallback#onSessionConfigFail(int)} is called if the subscribe
- * operation failed.
+ * <li>{@link WifiNanDiscoverySessionCallback#onSubscribeStarted(WifiNanSubscribeDiscoverySession)}
+ * is called when the subscribe session is created and provides a handle to the session.
+ * Further operations on the subscribe session can be executed on that object.
+ * <li>{@link WifiNanDiscoverySessionCallback#onSessionConfigFail(int)} is called if the
+ * subscribe operation failed.
* </ul>
* <p>
* Other results of the subscribe session operations will also be routed to callbacks
* on the {@code callback} object. The resulting subscribe session can be modified using
- * {@link WifiNanSubscribeSession#updateSubscribe(SubscribeConfig)}.
+ * {@link WifiNanSubscribeDiscoverySession#updateSubscribe(SubscribeConfig)}.
* <p>
- * An application must use the {@link WifiNanSession#terminate()} to terminate the
- * subscribe discovery session once it isn't needed. This will free resources as well
- * terminate any on-air transmissions.
+ * An application must use the {@link WifiNanDiscoveryBaseSession#terminate()} to
+ * terminate the subscribe discovery session once it isn't needed. This will free
+ * resources as well terminate any on-air transmissions.
*
* @param subscribeConfig The {@link SubscribeConfig} specifying the
* configuration of the requested subscribe session.
- * @param callback A {@link WifiNanSessionCallback} derived object to be used for session
- * event callbacks.
+ * @param callback A {@link WifiNanDiscoverySessionCallback} derived object to be used for
+ * session event callbacks.
*/
public void subscribe(@NonNull SubscribeConfig subscribeConfig,
- @NonNull WifiNanSessionCallback callback) {
+ @NonNull WifiNanDiscoverySessionCallback callback) {
if (VDBG) {
Log.v(TAG, "subscribe(): config=" + subscribeConfig);
}
@@ -557,7 +558,7 @@ public class WifiNanManager {
try {
mService.subscribe(clientId, subscribeConfig,
- new WifiNanSessionCallbackProxy(this, looper, false, callback));
+ new WifiNanDiscoverySessionCallbackProxy(this, looper, false, callback));
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -744,7 +745,7 @@ public class WifiNanManager {
* This API is targeted for applications which can obtain the peer MAC address using OOB
* (out-of-band) discovery. NAN discovery does not provide the MAC address of the peer -
* when using NAN discovery use the alternative network specifier method -
- * {@link WifiNanSession#createNetworkSpecifier(int, int, byte[])}.
+ * {@link WifiNanDiscoveryBaseSession#createNetworkSpecifier(int, int, byte[])}.
*
* @param role The role of this device:
* {@link WifiNanManager#WIFI_NAN_DATA_PATH_ROLE_INITIATOR} or
@@ -760,8 +761,8 @@ public class WifiNanManager {
* not the same as a null token and requires the peer token to be empty as well.
*
* @return A string to be used to construct
- * {@link android.net.NetworkRequest.Builder#setNetworkSpecifier(String)} to pass to {@link
- * android.net.ConnectivityManager#requestNetwork(NetworkRequest, ConnectivityManager.NetworkCallback)}
+ * {@link android.net.NetworkRequest.Builder#setNetworkSpecifier(String)} to pass to
+ * {@link android.net.ConnectivityManager#requestNetwork(NetworkRequest, ConnectivityManager.NetworkCallback)}
* [or other varieties of that API].
*/
public String createNetworkSpecifier(@DataPathRole int role, @Nullable byte[] peer,
@@ -999,7 +1000,8 @@ public class WifiNanManager {
}
}
- private static class WifiNanSessionCallbackProxy extends IWifiNanSessionCallback.Stub {
+ private static class WifiNanDiscoverySessionCallbackProxy extends
+ IWifiNanDiscoverySessionCallback.Stub {
private static final int CALLBACK_SESSION_STARTED = 0;
private static final int CALLBACK_SESSION_CONFIG_SUCCESS = 1;
private static final int CALLBACK_SESSION_CONFIG_FAIL = 2;
@@ -1014,18 +1016,20 @@ public class WifiNanManager {
private final WeakReference<WifiNanManager> mNanManager;
private final boolean mIsPublish;
- private final WifiNanSessionCallback mOriginalCallback;
+ private final WifiNanDiscoverySessionCallback mOriginalCallback;
private final Handler mHandler;
- private WifiNanSession mSession;
+ private WifiNanDiscoveryBaseSession mSession;
- WifiNanSessionCallbackProxy(WifiNanManager mgr, Looper looper, boolean isPublish,
- WifiNanSessionCallback originalCallback) {
+ WifiNanDiscoverySessionCallbackProxy(WifiNanManager mgr, Looper looper, boolean isPublish,
+ WifiNanDiscoverySessionCallback originalCallback) {
mNanManager = new WeakReference<>(mgr);
mIsPublish = isPublish;
mOriginalCallback = originalCallback;
- if (VDBG) Log.v(TAG, "WifiNanSessionCallbackProxy ctor: isPublish=" + isPublish);
+ if (VDBG) {
+ Log.v(TAG, "WifiNanDiscoverySessionCallbackProxy ctor: isPublish=" + isPublish);
+ }
mHandler = new Handler(looper) {
@Override
@@ -1033,7 +1037,7 @@ public class WifiNanManager {
if (DBG) Log.d(TAG, "What=" + msg.what + ", msg=" + msg);
if (mNanManager.get() == null) {
- Log.w(TAG, "WifiNanSessionCallbackProxy: handleMessage post GC");
+ Log.w(TAG, "WifiNanDiscoverySessionCallbackProxy: handleMessage post GC");
return;
}
@@ -1176,11 +1180,13 @@ public class WifiNanManager {
}
if (mIsPublish) {
- WifiNanPublishSession session = new WifiNanPublishSession(mgr, sessionId);
+ WifiNanPublishDiscoverySession session = new WifiNanPublishDiscoverySession(mgr,
+ sessionId);
mSession = session;
mOriginalCallback.onPublishStarted(session);
} else {
- WifiNanSubscribeSession session = new WifiNanSubscribeSession(mgr, sessionId);
+ WifiNanSubscribeDiscoverySession
+ session = new WifiNanSubscribeDiscoverySession(mgr, sessionId);
mSession = session;
mOriginalCallback.onSubscribeStarted(session);
}
diff --git a/wifi/java/android/net/wifi/nan/WifiNanPublishSession.java b/wifi/java/android/net/wifi/nan/WifiNanPublishDiscoverySession.java
index ccd7faee8476..cacbdbf751d8 100644
--- a/wifi/java/android/net/wifi/nan/WifiNanPublishSession.java
+++ b/wifi/java/android/net/wifi/nan/WifiNanPublishDiscoverySession.java
@@ -21,32 +21,33 @@ import android.util.Log;
/**
* A class representing a NAN publish session. Created when
- * {@link WifiNanManager#publish(PublishConfig, WifiNanSessionCallback)} is called and a
+ * {@link WifiNanManager#publish(PublishConfig, WifiNanDiscoverySessionCallback)} is called and a
* discovery session is created and returned in
- * {@link WifiNanSessionCallback#onPublishStarted(WifiNanPublishSession)}. See baseline
- * functionality of all discovery sessions in {@link WifiNanSession}. This object allows updating
- * an existing/running publish discovery session using {@link #updatePublish(PublishConfig)}.
+ * {@link WifiNanDiscoverySessionCallback#onPublishStarted(WifiNanPublishDiscoverySession)}. See
+ * baseline functionality of all discovery sessions in {@link WifiNanDiscoveryBaseSession}. This
+ * object allows updating an existing/running publish discovery session using
+ * {@link #updatePublish(PublishConfig)}.
*
* @hide PROPOSED_NAN_API
*/
-public class WifiNanPublishSession extends WifiNanSession {
- private static final String TAG = "WifiNanPublishSession";
+public class WifiNanPublishDiscoverySession extends WifiNanDiscoveryBaseSession {
+ private static final String TAG = "WifiNanPublishDiscSsn";
/** @hide */
- public WifiNanPublishSession(WifiNanManager manager, int sessionId) {
+ public WifiNanPublishDiscoverySession(WifiNanManager manager, int sessionId) {
super(manager, sessionId);
}
/**
* Re-configure the currently active publish session. The
- * {@link WifiNanSessionCallback} is not replaced - the same listener used
+ * {@link WifiNanDiscoverySessionCallback} is not replaced - the same listener used
* at creation is still used. The results of the configuration are returned using
- * {@link WifiNanSessionCallback}:
+ * {@link WifiNanDiscoverySessionCallback}:
* <ul>
- * <li>{@link WifiNanSessionCallback#onSessionConfigSuccess()}: configuration update
- * succeeded.
- * <li>{@link WifiNanSessionCallback#onSessionConfigFail(int)}: configuration update
- * failed. The publish discovery session is still running using its previous
+ * <li>{@link WifiNanDiscoverySessionCallback#onSessionConfigSuccess()}: configuration
+ * update succeeded.
+ * <li>{@link WifiNanDiscoverySessionCallback#onSessionConfigFail(int)}: configuration
+ * update failed. The publish discovery session is still running using its previous
* configuration (i.e. update failure does not terminate the session).
* </ul>
*
diff --git a/wifi/java/android/net/wifi/nan/WifiNanSubscribeSession.java b/wifi/java/android/net/wifi/nan/WifiNanSubscribeDiscoverySession.java
index d0e56c521525..58c52d5faf72 100644
--- a/wifi/java/android/net/wifi/nan/WifiNanSubscribeSession.java
+++ b/wifi/java/android/net/wifi/nan/WifiNanSubscribeDiscoverySession.java
@@ -21,34 +21,35 @@ import android.util.Log;
/**
* A class representing a NAN subscribe session. Created when
- * {@link WifiNanManager#subscribe(SubscribeConfig, WifiNanSessionCallback)} is called and a
- * discovery session is created and returned in
- * {@link WifiNanSessionCallback#onSubscribeStarted(WifiNanSubscribeSession)}. See baseline
- * functionality of all discovery sessions in {@link WifiNanSession}. This object allows updating
- * an existing/running subscribe discovery session using {@link #updateSubscribe(SubscribeConfig)}.
+ * {@link WifiNanManager#subscribe(SubscribeConfig, WifiNanDiscoverySessionCallback)} is called
+ * and a discovery session is created and returned in
+ * {@link WifiNanDiscoverySessionCallback#onSubscribeStarted(WifiNanSubscribeDiscoverySession)}.
+ * See baseline functionality of all discovery sessions in {@link WifiNanDiscoveryBaseSession}.
+ * This object allows updating an existing/running subscribe discovery session using
+ * {@link #updateSubscribe(SubscribeConfig)}.
*
* @hide PROPOSED_NAN_API
*/
-public class WifiNanSubscribeSession extends WifiNanSession {
- private static final String TAG = "WifiNanSubscribeSession";
+public class WifiNanSubscribeDiscoverySession extends WifiNanDiscoveryBaseSession {
+ private static final String TAG = "WifiNanSubscribeDiscSsn";
/**
* {@hide}
*/
- public WifiNanSubscribeSession(WifiNanManager manager, int sessionId) {
+ public WifiNanSubscribeDiscoverySession(WifiNanManager manager, int sessionId) {
super(manager, sessionId);
}
/**
* Re-configure the currently active subscribe session. The
- * {@link WifiNanSessionCallback} is not replaced - the same listener used
+ * {@link WifiNanDiscoverySessionCallback} is not replaced - the same listener used
* at creation is still used. The results of the configuration are returned using
- * {@link WifiNanSessionCallback}:
+ * {@link WifiNanDiscoverySessionCallback}:
* <ul>
- * <li>{@link WifiNanSessionCallback#onSessionConfigSuccess()}: configuration update
- * succeeded.
- * <li>{@link WifiNanSessionCallback#onSessionConfigFail(int)}: configuration update
- * failed. The subscribe discovery session is still running using its previous
+ * <li>{@link WifiNanDiscoverySessionCallback#onSessionConfigSuccess()}: configuration
+ * update succeeded.
+ * <li>{@link WifiNanDiscoverySessionCallback#onSessionConfigFail(int)}: configuration
+ * update failed. The subscribe discovery session is still running using its previous
* configuration (i.e. update failure does not terminate the session).
* </ul>
*