summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--core/java/android/accounts/AccountManager.java17
-rw-r--r--core/java/android/accounts/IAccountManager.aidl14
-rw-r--r--core/java/android/app/AppOpsManager.java15
-rw-r--r--core/java/android/hardware/fingerprint/FingerprintManager.java11
-rw-r--r--core/java/android/hardware/fingerprint/IFingerprintServiceLockoutResetCallback.aidl4
-rw-r--r--core/java/android/net/ConnectivityManager.java2
-rw-r--r--core/java/android/net/NetworkFactory.java6
-rw-r--r--core/java/android/nfc/cardemulation/AidGroup.java16
-rw-r--r--core/java/android/nfc/cardemulation/HostApduService.java16
-rw-r--r--core/java/android/nfc/cardemulation/OffHostApduService.java16
-rw-r--r--core/java/android/provider/Settings.java9
-rw-r--r--core/java/com/android/internal/logging/MetricsLogger.java2
-rw-r--r--core/java/com/android/internal/widget/LockPatternUtils.java11
-rw-r--r--core/res/AndroidManifest.xml5
-rw-r--r--[-rwxr-xr-x]core/res/res/values/config.xml7
-rw-r--r--core/res/res/values/dimens.xml2
-rw-r--r--[-rwxr-xr-x]core/res/res/values/symbols.xml2
-rw-r--r--packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java3
-rw-r--r--packages/SystemUI/res/drawable-hdpi/ic_sysbar_back_ime_land.pngbin1443 -> 0 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/ic_sysbar_back_land.pngbin1377 -> 0 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/ic_sysbar_home_land.pngbin1571 -> 0 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/ic_sysbar_menu_land.pngbin942 -> 0 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/ic_sysbar_recent_land.pngbin780 -> 0 bytes
-rw-r--r--packages/SystemUI/res/drawable-ldrtl-hdpi/ic_sysbar_back_land.pngbin1603 -> 0 bytes
-rw-r--r--packages/SystemUI/res/drawable-ldrtl-mdpi/ic_sysbar_back_land.pngbin1015 -> 0 bytes
-rw-r--r--packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_sysbar_back_land.pngbin2117 -> 0 bytes
-rw-r--r--packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_sysbar_back_land.pngbin1325 -> 0 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/ic_sysbar_back_ime_land.pngbin1007 -> 0 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/ic_sysbar_back_land.pngbin1037 -> 0 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/ic_sysbar_home_land.pngbin1062 -> 0 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/ic_sysbar_menu_land.pngbin613 -> 0 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/ic_sysbar_recent_land.pngbin698 -> 0 bytes
-rw-r--r--packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back_ime_land.pngbin1889 -> 0 bytes
-rw-r--r--packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back_land.pngbin1968 -> 0 bytes
-rw-r--r--packages/SystemUI/res/drawable-xhdpi/ic_sysbar_home_land.pngbin2340 -> 0 bytes
-rw-r--r--packages/SystemUI/res/drawable-xhdpi/ic_sysbar_menu_land.pngbin1290 -> 0 bytes
-rw-r--r--packages/SystemUI/res/drawable-xhdpi/ic_sysbar_recent_land.pngbin838 -> 0 bytes
-rw-r--r--packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_back_ime_land.pngbin3029 -> 0 bytes
-rw-r--r--packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_back_land.pngbin2799 -> 0 bytes
-rw-r--r--packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_home_land.pngbin3615 -> 0 bytes
-rw-r--r--packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_menu_land.pngbin919 -> 0 bytes
-rw-r--r--packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_recent_land.pngbin1068 -> 0 bytes
-rw-r--r--packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_back_ime_land.pngbin3523 -> 0 bytes
-rw-r--r--packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_back_land.pngbin3369 -> 0 bytes
-rw-r--r--packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_home_land.pngbin4158 -> 0 bytes
-rw-r--r--packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_recent_land.pngbin1661 -> 0 bytes
-rw-r--r--packages/SystemUI/res/layout/navigation_bar.xml8
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java21
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/SecureCameraLaunchManager.java284
-rw-r--r--services/core/java/com/android/server/ConnectivityService.java18
-rw-r--r--services/core/java/com/android/server/GestureLauncherService.java140
-rw-r--r--services/core/java/com/android/server/MountService.java8
-rw-r--r--services/core/java/com/android/server/accounts/AccountManagerService.java87
-rw-r--r--services/core/java/com/android/server/connectivity/KeepalivePacketData.java3
-rw-r--r--services/core/java/com/android/server/connectivity/KeepaliveTracker.java24
-rw-r--r--services/core/java/com/android/server/content/SyncManager.java6
-rw-r--r--services/core/java/com/android/server/display/DisplayPowerState.java30
-rw-r--r--services/core/java/com/android/server/fingerprint/FingerprintService.java53
-rw-r--r--services/core/java/com/android/server/policy/PhoneWindowManager.java11
-rw-r--r--services/tests/servicestests/AndroidManifest.xml1
-rw-r--r--services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java776
-rw-r--r--services/tests/servicestests/src/com/android/server/accounts/AccountManagerServiceTest.java6
-rw-r--r--telephony/java/android/telephony/CarrierConfigManager.java25
67 files changed, 946 insertions, 737 deletions
diff --git a/core/java/android/accounts/AccountManager.java b/core/java/android/accounts/AccountManager.java
index 8c84b4d..9ef13de 100644
--- a/core/java/android/accounts/AccountManager.java
+++ b/core/java/android/accounts/AccountManager.java
@@ -426,7 +426,7 @@ public class AccountManager {
@RequiresPermission(GET_ACCOUNTS)
public Account[] getAccounts() {
try {
- return mService.getAccounts(null);
+ return mService.getAccounts(null, mContext.getOpPackageName());
} catch (RemoteException e) {
// won't ever happen
throw new RuntimeException(e);
@@ -451,7 +451,7 @@ public class AccountManager {
@RequiresPermission(GET_ACCOUNTS)
public Account[] getAccountsAsUser(int userId) {
try {
- return mService.getAccountsAsUser(null, userId);
+ return mService.getAccountsAsUser(null, userId, mContext.getOpPackageName());
} catch (RemoteException e) {
// won't ever happen
throw new RuntimeException(e);
@@ -468,7 +468,7 @@ public class AccountManager {
*/
public Account[] getAccountsForPackage(String packageName, int uid) {
try {
- return mService.getAccountsForPackage(packageName, uid);
+ return mService.getAccountsForPackage(packageName, uid, mContext.getOpPackageName());
} catch (RemoteException re) {
// won't ever happen
throw new RuntimeException(re);
@@ -485,7 +485,8 @@ public class AccountManager {
*/
public Account[] getAccountsByTypeForPackage(String type, String packageName) {
try {
- return mService.getAccountsByTypeForPackage(type, packageName);
+ return mService.getAccountsByTypeForPackage(type, packageName,
+ mContext.getOpPackageName());
} catch (RemoteException re) {
// won't ever happen
throw new RuntimeException(re);
@@ -522,7 +523,8 @@ public class AccountManager {
/** @hide Same as {@link #getAccountsByType(String)} but for a specific user. */
public Account[] getAccountsByTypeAsUser(String type, UserHandle userHandle) {
try {
- return mService.getAccountsAsUser(type, userHandle.getIdentifier());
+ return mService.getAccountsAsUser(type, userHandle.getIdentifier(),
+ mContext.getOpPackageName());
} catch (RemoteException e) {
// won't ever happen
throw new RuntimeException(e);
@@ -610,7 +612,7 @@ public class AccountManager {
if (features == null) throw new IllegalArgumentException("features is null");
return new Future2Task<Boolean>(handler, callback) {
public void doWork() throws RemoteException {
- mService.hasFeatures(mResponse, account, features);
+ mService.hasFeatures(mResponse, account, features, mContext.getOpPackageName());
}
public Boolean bundleToResult(Bundle bundle) throws AuthenticatorException {
if (!bundle.containsKey(KEY_BOOLEAN_RESULT)) {
@@ -662,7 +664,8 @@ public class AccountManager {
if (type == null) throw new IllegalArgumentException("type is null");
return new Future2Task<Account[]>(handler, callback) {
public void doWork() throws RemoteException {
- mService.getAccountsByFeatures(mResponse, type, features);
+ mService.getAccountsByFeatures(mResponse, type, features,
+ mContext.getOpPackageName());
}
public Account[] bundleToResult(Bundle bundle) throws AuthenticatorException {
if (!bundle.containsKey(KEY_ACCOUNTS)) {
diff --git a/core/java/android/accounts/IAccountManager.aidl b/core/java/android/accounts/IAccountManager.aidl
index 04b3c88..4378df4 100644
--- a/core/java/android/accounts/IAccountManager.aidl
+++ b/core/java/android/accounts/IAccountManager.aidl
@@ -30,12 +30,14 @@ interface IAccountManager {
String getPassword(in Account account);
String getUserData(in Account account, String key);
AuthenticatorDescription[] getAuthenticatorTypes(int userId);
- Account[] getAccounts(String accountType);
- Account[] getAccountsForPackage(String packageName, int uid);
- Account[] getAccountsByTypeForPackage(String type, String packageName);
- Account[] getAccountsAsUser(String accountType, int userId);
- void hasFeatures(in IAccountManagerResponse response, in Account account, in String[] features);
- void getAccountsByFeatures(in IAccountManagerResponse response, String accountType, in String[] features);
+ Account[] getAccounts(String accountType, String opPackageName);
+ Account[] getAccountsForPackage(String packageName, int uid, String opPackageName);
+ Account[] getAccountsByTypeForPackage(String type, String packageName, String opPackageName);
+ Account[] getAccountsAsUser(String accountType, int userId, String opPackageName);
+ void hasFeatures(in IAccountManagerResponse response, in Account account, in String[] features,
+ String opPackageName);
+ void getAccountsByFeatures(in IAccountManagerResponse response, String accountType,
+ in String[] features, String opPackageName);
boolean addAccountExplicitly(in Account account, String password, in Bundle extras);
void removeAccount(in IAccountManagerResponse response, in Account account,
boolean expectActivityLaunch);
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index 42ac67c..09c0a6e 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -235,8 +235,10 @@ public class AppOpsManager {
public static final int OP_WRITE_EXTERNAL_STORAGE = 60;
/** @hide Turned on the screen. */
public static final int OP_TURN_SCREEN_ON = 61;
+ /** @hide Get device accounts. */
+ public static final int OP_GET_ACCOUNTS = 62;
/** @hide */
- public static final int _NUM_OP = 62;
+ public static final int _NUM_OP = 63;
/** Access to coarse location information. */
public static final String OPSTR_COARSE_LOCATION = "android:coarse_location";
@@ -331,6 +333,9 @@ public class AppOpsManager {
/** Required to write/modify/update system settingss. */
public static final String OPSTR_WRITE_SETTINGS
= "android:write_settings";
+ /** @hide Get device accounts. */
+ public static final String OPSTR_GET_ACCOUNTS
+ = "android:get_accounts";
/**
* This maps each operation to the operation that serves as the
@@ -403,6 +408,7 @@ public class AppOpsManager {
OP_READ_EXTERNAL_STORAGE,
OP_WRITE_EXTERNAL_STORAGE,
OP_TURN_SCREEN_ON,
+ OP_GET_ACCOUNTS,
};
/**
@@ -472,6 +478,7 @@ public class AppOpsManager {
OPSTR_READ_EXTERNAL_STORAGE,
OPSTR_WRITE_EXTERNAL_STORAGE,
null,
+ OPSTR_GET_ACCOUNTS
};
/**
@@ -541,6 +548,7 @@ public class AppOpsManager {
"READ_EXTERNAL_STORAGE",
"WRITE_EXTERNAL_STORAGE",
"TURN_ON_SCREEN",
+ "GET_ACCOUNTS",
};
/**
@@ -610,6 +618,7 @@ public class AppOpsManager {
Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.WRITE_EXTERNAL_STORAGE,
null, // no permission for turning the screen on
+ Manifest.permission.GET_ACCOUNTS
};
/**
@@ -680,6 +689,7 @@ public class AppOpsManager {
null, // READ_EXTERNAL_STORAGE
null, // WRITE_EXTERNAL_STORAGE
null, // TURN_ON_SCREEN
+ null, // GET_ACCOUNTS
};
/**
@@ -749,6 +759,7 @@ public class AppOpsManager {
false, // READ_EXTERNAL_STORAGE
false, // WRITE_EXTERNAL_STORAGE
false, // TURN_ON_SCREEN
+ false, // GET_ACCOUNTS
};
/**
@@ -817,6 +828,7 @@ public class AppOpsManager {
AppOpsManager.MODE_ALLOWED,
AppOpsManager.MODE_ALLOWED,
AppOpsManager.MODE_ALLOWED, // OP_TURN_ON_SCREEN
+ AppOpsManager.MODE_ALLOWED,
};
/**
@@ -889,6 +901,7 @@ public class AppOpsManager {
false,
false,
false,
+ false
};
/**
diff --git a/core/java/android/hardware/fingerprint/FingerprintManager.java b/core/java/android/hardware/fingerprint/FingerprintManager.java
index 1f23c0a..7fef5e1 100644
--- a/core/java/android/hardware/fingerprint/FingerprintManager.java
+++ b/core/java/android/hardware/fingerprint/FingerprintManager.java
@@ -27,6 +27,7 @@ import android.os.CancellationSignal.OnCancelListener;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
+import android.os.PowerManager;
import android.os.RemoteException;
import android.os.UserHandle;
import android.security.keystore.AndroidKeyStoreProvider;
@@ -705,15 +706,23 @@ public class FingerprintManager {
public void addLockoutResetCallback(final LockoutResetCallback callback) {
if (mService != null) {
try {
+ final PowerManager powerManager = mContext.getSystemService(PowerManager.class);
mService.addLockoutResetCallback(
new IFingerprintServiceLockoutResetCallback.Stub() {
@Override
public void onLockoutReset(long deviceId) throws RemoteException {
+ final PowerManager.WakeLock wakeLock = powerManager.newWakeLock(
+ PowerManager.PARTIAL_WAKE_LOCK, "lockoutResetCallback");
+ wakeLock.acquire();
mHandler.post(new Runnable() {
@Override
public void run() {
- callback.onLockoutReset();
+ try {
+ callback.onLockoutReset();
+ } finally {
+ wakeLock.release();
+ }
}
});
}
diff --git a/core/java/android/hardware/fingerprint/IFingerprintServiceLockoutResetCallback.aidl b/core/java/android/hardware/fingerprint/IFingerprintServiceLockoutResetCallback.aidl
index c9a5d59..e027a2b 100644
--- a/core/java/android/hardware/fingerprint/IFingerprintServiceLockoutResetCallback.aidl
+++ b/core/java/android/hardware/fingerprint/IFingerprintServiceLockoutResetCallback.aidl
@@ -23,6 +23,8 @@ import android.os.UserHandle;
* Callback when lockout period expired and clients are allowed to authenticate again.
* @hide
*/
-oneway interface IFingerprintServiceLockoutResetCallback {
+interface IFingerprintServiceLockoutResetCallback {
+
+ /** Method is synchronous so wakelock is held when this is called from a WAKEUP alarm. */
void onLockoutReset(long deviceId);
}
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index 4055836..9a2a241 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -1243,6 +1243,8 @@ public class ConnectivityManager {
/** The hardware does not support this request. */
public static final int ERROR_HARDWARE_UNSUPPORTED = -30;
+ /** The hardware returned an error. */
+ public static final int ERROR_HARDWARE_ERROR = -31;
public static final int NATT_PORT = 4500;
diff --git a/core/java/android/net/NetworkFactory.java b/core/java/android/net/NetworkFactory.java
index 5f46c73..cab88b9 100644
--- a/core/java/android/net/NetworkFactory.java
+++ b/core/java/android/net/NetworkFactory.java
@@ -169,7 +169,8 @@ public class NetworkFactory extends Handler {
}
}
- private void handleAddRequest(NetworkRequest request, int score) {
+ @VisibleForTesting
+ protected void handleAddRequest(NetworkRequest request, int score) {
NetworkRequestInfo n = mNetworkRequests.get(request.requestId);
if (n == null) {
if (DBG) log("got request " + request + " with score " + score);
@@ -184,7 +185,8 @@ public class NetworkFactory extends Handler {
evalRequest(n);
}
- private void handleRemoveRequest(NetworkRequest request) {
+ @VisibleForTesting
+ protected void handleRemoveRequest(NetworkRequest request) {
NetworkRequestInfo n = mNetworkRequests.get(request.requestId);
if (n != null) {
mNetworkRequests.remove(request.requestId);
diff --git a/core/java/android/nfc/cardemulation/AidGroup.java b/core/java/android/nfc/cardemulation/AidGroup.java
index 4407c9d..78a9401 100644
--- a/core/java/android/nfc/cardemulation/AidGroup.java
+++ b/core/java/android/nfc/cardemulation/AidGroup.java
@@ -1,3 +1,19 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
package android.nfc.cardemulation;
import java.io.IOException;
diff --git a/core/java/android/nfc/cardemulation/HostApduService.java b/core/java/android/nfc/cardemulation/HostApduService.java
index ad34e61..a299479 100644
--- a/core/java/android/nfc/cardemulation/HostApduService.java
+++ b/core/java/android/nfc/cardemulation/HostApduService.java
@@ -1,3 +1,19 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
package android.nfc.cardemulation;
import android.annotation.SdkConstant;
diff --git a/core/java/android/nfc/cardemulation/OffHostApduService.java b/core/java/android/nfc/cardemulation/OffHostApduService.java
index 0d01762..6a8aeee 100644
--- a/core/java/android/nfc/cardemulation/OffHostApduService.java
+++ b/core/java/android/nfc/cardemulation/OffHostApduService.java
@@ -1,3 +1,19 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
package android.nfc.cardemulation;
import android.annotation.SdkConstant;
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 78be3cd..2053dbe 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -5719,6 +5719,15 @@ public final class Settings {
public static final String CAMERA_GESTURE_DISABLED = "camera_gesture_disabled";
/**
+ * Whether the camera launch gesture to double tap the power button when the screen is off
+ * should be disabled.
+ *
+ * @hide
+ */
+ public static final String CAMERA_DOUBLE_TAP_POWER_GESTURE_DISABLED =
+ "camera_double_tap_power_gesture_disabled";
+
+ /**
* This are the settings to be backed up.
*
* NOTE: Settings are backed up and restored in the order they appear
diff --git a/core/java/com/android/internal/logging/MetricsLogger.java b/core/java/com/android/internal/logging/MetricsLogger.java
index 6da0f63..b6240e4 100644
--- a/core/java/com/android/internal/logging/MetricsLogger.java
+++ b/core/java/com/android/internal/logging/MetricsLogger.java
@@ -44,6 +44,8 @@ public class MetricsLogger implements MetricsConstants {
public static final int ACTION_FINGERPRINT_AUTH = 252;
public static final int ACTION_FINGERPRINT_DELETE = 253;
public static final int ACTION_FINGERPRINT_RENAME = 254;
+ public static final int ACTION_DOUBLE_TAP_POWER_CAMERA_GESTURE = 255;
+ public static final int ACTION_WIGGLE_CAMERA_GESTURE = 256;
public static void visible(Context context, int category) throws IllegalArgumentException {
if (Build.IS_DEBUGGABLE && category == VIEW_UNKNOWN) {
diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java
index 4ac2958..a873ef8 100644
--- a/core/java/com/android/internal/widget/LockPatternUtils.java
+++ b/core/java/com/android/internal/widget/LockPatternUtils.java
@@ -1174,7 +1174,7 @@ public class LockPatternUtils {
* @param userId either an explicit user id or {@link android.os.UserHandle#USER_ALL}
*/
public void requireCredentialEntry(int userId) {
- requireStrongAuth(StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_USER_REQUEST, userId);
+ requireStrongAuth(StrongAuthTracker.SOME_AUTH_REQUIRED_AFTER_USER_REQUEST, userId);
}
/**
@@ -1251,7 +1251,7 @@ public class LockPatternUtils {
value = { STRONG_AUTH_NOT_REQUIRED,
STRONG_AUTH_REQUIRED_AFTER_BOOT,
STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW,
- STRONG_AUTH_REQUIRED_AFTER_USER_REQUEST})
+ SOME_AUTH_REQUIRED_AFTER_USER_REQUEST})
@Retention(RetentionPolicy.SOURCE)
public @interface StrongAuthFlags {}
@@ -1266,14 +1266,14 @@ public class LockPatternUtils {
public static final int STRONG_AUTH_REQUIRED_AFTER_BOOT = 0x1;
/**
- * Strong authentication is required because a device admin has temporarily requested it.
+ * Strong authentication is required because a device admin has requested it.
*/
public static final int STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW = 0x2;
/**
- * Strong authentication is required because the user has temporarily requested it.
+ * Some authentication is required because the user has temporarily disabled trust.
*/
- public static final int STRONG_AUTH_REQUIRED_AFTER_USER_REQUEST = 0x4;
+ public static final int SOME_AUTH_REQUIRED_AFTER_USER_REQUEST = 0x4;
/**
* Strong authentication is required because the user has been locked out after too many
@@ -1289,6 +1289,7 @@ public class LockPatternUtils {
public static final int DEFAULT = STRONG_AUTH_REQUIRED_AFTER_BOOT;
private static final int ALLOWING_FINGERPRINT = STRONG_AUTH_NOT_REQUIRED
+ | SOME_AUTH_REQUIRED_AFTER_USER_REQUEST
| SOME_AUTH_REQUIRED_AFTER_WRONG_CREDENTIAL;
private final SparseIntArray mStrongAuthRequiredForUser = new SparseIntArray();
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index c8bb675..b8b6444 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -1056,6 +1056,11 @@
<permission android:name="android.permission.CONNECTIVITY_INTERNAL"
android:protectionLevel="signature|privileged" />
+ <!-- Allows a system application to access hardware packet offload capabilities.
+ @hide -->
+ <permission android:name="android.permission.PACKET_KEEPALIVE_OFFLOAD"
+ android:protectionLevel="signature|privileged" />
+
<!-- @SystemApi
@hide -->
<permission android:name="android.permission.RECEIVE_DATA_ACTIVITY_CHANGE"
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index d7658d1..fd600e3 100755..100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -2285,9 +2285,16 @@
<string-array name="config_cell_retries_per_error_code">
</string-array>
+ <!-- Set initial MaxRetry value for operators -->
+ <integer name="config_mdc_initial_max_retry">1</integer>
+
<!-- The OEM specified sensor type for the gesture to launch the camear app. -->
<integer name="config_cameraLaunchGestureSensorType">-1</integer>
<!-- The OEM specified sensor string type for the gesture to launch camera app, this value
must match the value of config_cameraLaunchGestureSensorType in OEM's HAL -->
<string translatable="false" name="config_cameraLaunchGestureSensorStringType"></string>
+
+ <!-- Allow the gesture to double tap the power button twice to start the camera while the device
+ is non-interactive. -->
+ <bool name="config_cameraDoubleTapPowerGestureEnabled">true</bool>
</resources>
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index 09c1e6f..8635a4f 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -37,7 +37,7 @@
<!-- Height of the bottom navigation bar in portrait; often the same as @dimen/navigation_bar_height -->
<dimen name="navigation_bar_height_landscape">48dp</dimen>
<!-- Width of the navigation bar when it is placed vertically on the screen -->
- <dimen name="navigation_bar_width">42dp</dimen>
+ <dimen name="navigation_bar_width">48dp</dimen>
<!-- Height of notification icons in the status bar -->
<dimen name="status_bar_icon_size">24dip</dimen>
<!-- Size of the giant number (unread count) in the notifications -->
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 4c8e55e..357d4c3 100755..100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -404,6 +404,7 @@
<java-symbol type="integer" name="config_volte_replacement_rat"/>
<java-symbol type="integer" name="config_valid_wappush_index" />
<java-symbol type="integer" name="config_overrideHasPermanentMenuKey" />
+ <java-symbol type="integer" name="config_mdc_initial_max_retry" />
<java-symbol type="bool" name="config_hasPermanentDpad" />
<java-symbol type="color" name="tab_indicator_text_v4" />
@@ -2323,6 +2324,7 @@
<!-- Gesture -->
<java-symbol type="integer" name="config_cameraLaunchGestureSensorType" />
<java-symbol type="string" name="config_cameraLaunchGestureSensorStringType" />
+ <java-symbol type="bool" name="config_cameraDoubleTapPowerGestureEnabled" />
<java-symbol type="drawable" name="platlogo_m" />
</resources>
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
index b752c9b..47d8e28 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -1032,7 +1032,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener {
}
private boolean shouldListenForFingerprint() {
- return (mKeyguardIsVisible || !mDeviceInteractive) && !mSwitchingUser
+ return (mKeyguardIsVisible || !mDeviceInteractive || mBouncer) && !mSwitchingUser
&& !mFingerprintAlreadyAuthenticated && !isFingerprintDisabled(getCurrentUser());
}
@@ -1365,6 +1365,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener {
cb.onKeyguardBouncerChanged(isBouncer);
}
}
+ updateFingerprintListeningState();
}
/**
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back_ime_land.png b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back_ime_land.png
deleted file mode 100644
index 165ef4f..0000000
--- a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back_ime_land.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back_land.png b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back_land.png
deleted file mode 100644
index f95f09f..0000000
--- a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back_land.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_home_land.png b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_home_land.png
deleted file mode 100644
index 860a906..0000000
--- a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_home_land.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_menu_land.png b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_menu_land.png
deleted file mode 100644
index bcb203e..0000000
--- a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_menu_land.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_recent_land.png b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_recent_land.png
deleted file mode 100644
index bab268e..0000000
--- a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_recent_land.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_sysbar_back_land.png b/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_sysbar_back_land.png
deleted file mode 100644
index 2f4dbbe..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_sysbar_back_land.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_sysbar_back_land.png b/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_sysbar_back_land.png
deleted file mode 100644
index d04d84f5..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_sysbar_back_land.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_sysbar_back_land.png b/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_sysbar_back_land.png
deleted file mode 100644
index 1500ae5..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_sysbar_back_land.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_sysbar_back_land.png b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_sysbar_back_land.png
deleted file mode 100644
index a7fec49..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_sysbar_back_land.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back_ime_land.png b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back_ime_land.png
deleted file mode 100644
index 0feb405..0000000
--- a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back_ime_land.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back_land.png b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back_land.png
deleted file mode 100644
index cabab0d..0000000
--- a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back_land.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_home_land.png b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_home_land.png
deleted file mode 100644
index 16e1bf5..0000000
--- a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_home_land.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_menu_land.png b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_menu_land.png
deleted file mode 100644
index 94c9743..0000000
--- a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_menu_land.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_recent_land.png b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_recent_land.png
deleted file mode 100644
index 40375de..0000000
--- a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_recent_land.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back_ime_land.png b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back_ime_land.png
deleted file mode 100644
index b7b8f98..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back_ime_land.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back_land.png b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back_land.png
deleted file mode 100644
index 69b7449..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back_land.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_home_land.png b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_home_land.png
deleted file mode 100644
index 57d243c..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_home_land.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_menu_land.png b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_menu_land.png
deleted file mode 100644
index 8a7ac4f..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_menu_land.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_recent_land.png b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_recent_land.png
deleted file mode 100644
index e53eaff..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_recent_land.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_back_ime_land.png b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_back_ime_land.png
deleted file mode 100644
index 695e7a4..0000000
--- a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_back_ime_land.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_back_land.png b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_back_land.png
deleted file mode 100644
index 88294c0..0000000
--- a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_back_land.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_home_land.png b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_home_land.png
deleted file mode 100644
index 09d684a..0000000
--- a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_home_land.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_menu_land.png b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_menu_land.png
deleted file mode 100644
index 62f44e8..0000000
--- a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_menu_land.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_recent_land.png b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_recent_land.png
deleted file mode 100644
index e31ea32..0000000
--- a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_recent_land.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_back_ime_land.png b/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_back_ime_land.png
deleted file mode 100644
index 24f12d7..0000000
--- a/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_back_ime_land.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_back_land.png b/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_back_land.png
deleted file mode 100644
index 51482f5..0000000
--- a/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_back_land.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_home_land.png b/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_home_land.png
deleted file mode 100644
index 46c7b18..0000000
--- a/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_home_land.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_recent_land.png b/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_recent_land.png
deleted file mode 100644
index 396ad7d..0000000
--- a/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_recent_land.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/layout/navigation_bar.xml b/packages/SystemUI/res/layout/navigation_bar.xml
index c92ba45..d58664f 100644
--- a/packages/SystemUI/res/layout/navigation_bar.xml
+++ b/packages/SystemUI/res/layout/navigation_bar.xml
@@ -213,7 +213,7 @@
android:layout_width="match_parent"
android:layout_height="40dp"
android:contentDescription="@string/accessibility_menu"
- android:src="@drawable/ic_sysbar_menu_land"
+ android:src="@drawable/ic_sysbar_menu"
android:scaleType="centerInside"
android:layout_gravity="top"
android:visibility="invisible"
@@ -223,7 +223,7 @@
<com.android.systemui.statusbar.policy.KeyButtonView android:id="@+id/recent_apps"
android:layout_height="@dimen/navigation_key_width"
android:layout_width="match_parent"
- android:src="@drawable/ic_sysbar_recent_land"
+ android:src="@drawable/ic_sysbar_recent"
android:scaleType="center"
android:layout_weight="0"
android:contentDescription="@string/accessibility_recent"
@@ -237,7 +237,7 @@
<com.android.systemui.statusbar.policy.KeyButtonView android:id="@+id/home"
android:layout_height="@dimen/navigation_key_width"
android:layout_width="match_parent"
- android:src="@drawable/ic_sysbar_home_land"
+ android:src="@drawable/ic_sysbar_home"
android:scaleType="center"
systemui:keyCode="3"
systemui:keyRepeat="false"
@@ -253,7 +253,7 @@
<com.android.systemui.statusbar.policy.KeyButtonView android:id="@+id/back"
android:layout_height="@dimen/navigation_key_width"
android:layout_width="match_parent"
- android:src="@drawable/ic_sysbar_back_land"
+ android:src="@drawable/ic_sysbar_back"
android:scaleType="center"
systemui:keyCode="4"
android:layout_weight="0"
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
index f4439bf..012dc9c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
@@ -390,7 +390,8 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL
serviceIntent.setAction(CameraPrewarmService.ACTION_PREWARM);
try {
if (getContext().bindServiceAsUser(serviceIntent, mPrewarmConnection,
- Context.BIND_AUTO_CREATE, new UserHandle(UserHandle.USER_CURRENT))) {
+ Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE,
+ new UserHandle(UserHandle.USER_CURRENT))) {
mPrewarmBound = true;
}
} catch (SecurityException e) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java
index 030501b..8e58d14 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java
@@ -166,13 +166,10 @@ public class LockIcon extends KeyguardAffordanceView {
if (mAccessibilityController == null) {
return;
}
- boolean trustManagedOrFingerprintAllowed = mUnlockMethodCache.isTrustManaged()
- || KeyguardUpdateMonitor.getInstance(mContext).isUnlockingWithFingerprintAllowed();
-
boolean clickToUnlock = mAccessibilityController.isTouchExplorationEnabled();
- boolean clickToForceLock = trustManagedOrFingerprintAllowed
+ boolean clickToForceLock = mUnlockMethodCache.isTrustManaged()
&& !mAccessibilityController.isAccessibilityEnabled();
- boolean longClickToForceLock = trustManagedOrFingerprintAllowed
+ boolean longClickToForceLock = mUnlockMethodCache.isTrustManaged()
&& !clickToForceLock;
setClickable(clickToForceLock || clickToUnlock);
setLongClickable(longClickToForceLock);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
index cc31476..8046eb5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
@@ -257,11 +257,11 @@ public class NavigationBarView extends LinearLayout {
private void getIcons(Resources res) {
mBackIcon = res.getDrawable(R.drawable.ic_sysbar_back);
- mBackLandIcon = res.getDrawable(R.drawable.ic_sysbar_back_land);
+ mBackLandIcon = mBackIcon;
mBackAltIcon = res.getDrawable(R.drawable.ic_sysbar_back_ime);
- mBackAltLandIcon = res.getDrawable(R.drawable.ic_sysbar_back_ime_land);
+ mBackAltLandIcon = mBackAltIcon;
mRecentIcon = res.getDrawable(R.drawable.ic_sysbar_recent);
- mRecentLandIcon = res.getDrawable(R.drawable.ic_sysbar_recent_land);
+ mRecentLandIcon = mRecentIcon;
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
index b93586e..9321938 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -111,12 +111,6 @@ public class NotificationPanelView extends PanelView implements
private boolean mQsTracking;
/**
- * Handles launching the secure camera properly even when other applications may be using the
- * camera hardware.
- */
- private SecureCameraLaunchManager mSecureCameraLaunchManager;
-
- /**
* If set, the ongoing touch gesture might both trigger the expansion in {@link PanelView} and
* the expansion for quick settings.
*/
@@ -262,8 +256,6 @@ public class NotificationPanelView extends PanelView implements
mKeyguardBottomArea = (KeyguardBottomAreaView) findViewById(R.id.keyguard_bottom_area);
mQsNavbarScrim = findViewById(R.id.qs_navbar_scrim);
mAfforanceHelper = new KeyguardAffordanceHelper(this, getContext());
- mSecureCameraLaunchManager =
- new SecureCameraLaunchManager(getContext(), mKeyguardBottomArea);
mLastOrientation = getResources().getConfiguration().orientation;
// recompute internal state when qspanel height changes
@@ -368,16 +360,6 @@ public class NotificationPanelView extends PanelView implements
updateMaxHeadsUpTranslation();
}
- @Override
- public void onAttachedToWindow() {
- mSecureCameraLaunchManager.create();
- }
-
- @Override
- public void onDetachedFromWindow() {
- mSecureCameraLaunchManager.destroy();
- }
-
private void startQsSizeChangeAnimation(int oldHeight, final int newHeight) {
if (mQsSizeChangeAnimator != null) {
oldHeight = (int) mQsSizeChangeAnimator.getAnimatedValue();
@@ -1963,7 +1945,7 @@ public class NotificationPanelView extends PanelView implements
} else {
EventLogTags.writeSysuiLockscreenGesture(
EventLogConstants.SYSUI_LOCKSCREEN_GESTURE_SWIPE_CAMERA, lengthDp, velocityDp);
- mSecureCameraLaunchManager.startSecureCameraLaunch();
+ mKeyguardBottomArea.launchCamera();
}
mStatusBar.startLaunchTransitionTimeout();
mBlockTouches = true;
@@ -2010,7 +1992,6 @@ public class NotificationPanelView extends PanelView implements
boolean camera = getLayoutDirection() == LAYOUT_DIRECTION_RTL ? !rightIcon
: rightIcon;
if (camera) {
- mSecureCameraLaunchManager.onSwipingStarted();
mKeyguardBottomArea.bindCameraPrewarmService();
}
requestDisallowInterceptTouchEvent(true);
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 55b1127..548125d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -289,6 +289,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
private DozeServiceHost mDozeServiceHost;
private boolean mWakeUpComingFromTouch;
private PointF mWakeUpTouchLocation;
+ private boolean mScreenTurningOn;
int mPixelFormat;
Object mQueueLock = new Object();
@@ -3535,6 +3536,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
mHandler.removeMessages(MSG_LAUNCH_TRANSITION_TIMEOUT);
releaseGestureWakeLock();
mNotificationPanel.onAffordanceLaunchEnded();
+ mNotificationPanel.animate().cancel();
mNotificationPanel.setAlpha(1f);
return staying;
}
@@ -3920,6 +3922,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
}
public void onScreenTurningOn() {
+ mScreenTurningOn = true;
mNotificationPanel.onScreenTurningOn();
if (mLaunchCameraOnScreenTurningOn) {
mNotificationPanel.launchCamera(false);
@@ -3928,10 +3931,11 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
}
private void vibrateForCameraGesture() {
- mVibrator.vibrate(1000L);
+ mVibrator.vibrate(750L);
}
public void onScreenTurnedOn() {
+ mScreenTurningOn = false;
mDozeScrimController.onScreenTurnedOn();
}
@@ -4107,7 +4111,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
mScrimController.dontAnimateBouncerChangesUntilNextFrame();
mGestureWakeLock.acquire(LAUNCH_TRANSITION_TIMEOUT_MS + 1000L);
}
- if (mStatusBarKeyguardViewManager.isScreenTurnedOn()) {
+ if (mScreenTurningOn || mStatusBarKeyguardViewManager.isScreenTurnedOn()) {
mNotificationPanel.launchCamera(mDeviceInteractive /* animate */);
} else {
// We need to defer the camera launch until the screen comes on, since otherwise
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/SecureCameraLaunchManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SecureCameraLaunchManager.java
deleted file mode 100644
index 45c8938..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/SecureCameraLaunchManager.java
+++ /dev/null
@@ -1,284 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.statusbar.phone;
-
-import android.content.Context;
-import android.content.Intent;
-import android.content.pm.PackageManager;
-import android.content.pm.ResolveInfo;
-import android.hardware.camera2.CameraManager;
-import android.os.AsyncTask;
-import android.os.Handler;
-import android.provider.MediaStore;
-import android.util.Log;
-
-import com.android.internal.widget.LockPatternUtils;
-import com.android.keyguard.KeyguardUpdateMonitor;
-
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-/**
- * Handles launching the secure camera properly even when other applications may be using the camera
- * hardware.
- *
- * When other applications (e.g., Face Unlock) are using the camera, they must close the camera to
- * allow the secure camera to open it. Since we want to minimize the delay when opening the secure
- * camera, other apps should close the camera at the first possible opportunity (i.e., as soon as
- * the user begins swiping to go to the secure camera).
- *
- * If the camera is unavailable when the user begins to swipe, the SecureCameraLaunchManager sends a
- * broadcast to tell other apps to close the camera. When and if the user completes their swipe to
- * launch the secure camera, the SecureCameraLaunchManager delays launching the secure camera until
- * a callback indicates that the camera has become available. If it doesn't receive that callback
- * within a specified timeout period, the secure camera is launched anyway.
- *
- * Ideally, the secure camera would handle waiting for the camera to become available. This allows
- * some of the time necessary to close the camera to happen in parallel with starting the secure
- * camera app. We can't rely on all third-party camera apps to handle this. However, an app can
- * put com.android.systemui.statusbar.phone.will_wait_for_camera_available in its meta-data to
- * indicate that it will be responsible for waiting for the camera to become available.
- *
- * It is assumed that the functions in this class, including the constructor, will be called from
- * the UI thread.
- */
-public class SecureCameraLaunchManager {
- private static final boolean DEBUG = false;
- private static final String TAG = "SecureCameraLaunchManager";
-
- // Action sent as a broadcast to tell other apps to stop using the camera. Other apps that use
- // the camera from keyguard (e.g., Face Unlock) should listen for this broadcast and close the
- // camera as soon as possible after receiving it.
- private static final String CLOSE_CAMERA_ACTION_NAME =
- "com.android.systemui.statusbar.phone.CLOSE_CAMERA";
-
- // Apps should put this field in their meta-data to indicate that they will take on the
- // responsibility of waiting for the camera to become available. If this field is present, the
- // SecureCameraLaunchManager launches the secure camera even if the camera hardware has not
- // become available. Having the secure camera app do the waiting is the optimal approach, but
- // without this field, the SecureCameraLaunchManager doesn't launch the secure camera until the
- // camera hardware is available.
- private static final String META_DATA_WILL_WAIT_FOR_CAMERA_AVAILABLE =
- "com.android.systemui.statusbar.phone.will_wait_for_camera_available";
-
- // If the camera hardware hasn't become available after this period of time, the
- // SecureCameraLaunchManager launches the secure camera anyway.
- private static final int CAMERA_AVAILABILITY_TIMEOUT_MS = 1000;
-
- private Context mContext;
- private Handler mHandler;
- private LockPatternUtils mLockPatternUtils;
- private KeyguardBottomAreaView mKeyguardBottomArea;
-
- private CameraManager mCameraManager;
- private CameraAvailabilityCallback mCameraAvailabilityCallback;
- private Map<String, Boolean> mCameraAvailabilityMap;
- private boolean mWaitingToLaunchSecureCamera;
- private Runnable mLaunchCameraRunnable;
-
- private class CameraAvailabilityCallback extends CameraManager.AvailabilityCallback {
- @Override
- public void onCameraUnavailable(String cameraId) {
- if (DEBUG) Log.d(TAG, "onCameraUnavailble(" + cameraId + ")");
- mCameraAvailabilityMap.put(cameraId, false);
- }
-
- @Override
- public void onCameraAvailable(String cameraId) {
- if (DEBUG) Log.d(TAG, "onCameraAvailable(" + cameraId + ")");
- mCameraAvailabilityMap.put(cameraId, true);
-
- // If we were waiting for the camera hardware to become available to launch the
- // secure camera, we can launch it now if all cameras are available. If one or more
- // cameras are still not available, we will get this callback again for those
- // cameras.
- if (mWaitingToLaunchSecureCamera && areAllCamerasAvailable()) {
- mKeyguardBottomArea.launchCamera();
- mWaitingToLaunchSecureCamera = false;
-
- // We no longer need to launch the camera after the timeout hits.
- mHandler.removeCallbacks(mLaunchCameraRunnable);
- }
- }
- }
-
- public SecureCameraLaunchManager(Context context, KeyguardBottomAreaView keyguardBottomArea) {
- mContext = context;
- mHandler = new Handler();
- mLockPatternUtils = new LockPatternUtils(context);
- mKeyguardBottomArea = keyguardBottomArea;
-
- mCameraManager = (CameraManager) context.getSystemService(Context.CAMERA_SERVICE);
- mCameraAvailabilityCallback = new CameraAvailabilityCallback();
-
- // An onCameraAvailable() or onCameraUnavailable() callback will be received for each camera
- // when the availability callback is registered, thus initializing the map.
- //
- // Keeping track of the state of all cameras using the onCameraAvailable() and
- // onCameraUnavailable() callbacks can get messy when dealing with hot-pluggable cameras.
- // However, we have a timeout in place such that we will never hang waiting for cameras.
- mCameraAvailabilityMap = new HashMap<String, Boolean>();
-
- mWaitingToLaunchSecureCamera = false;
- mLaunchCameraRunnable = new Runnable() {
- @Override
- public void run() {
- if (mWaitingToLaunchSecureCamera) {
- Log.w(TAG, "Timeout waiting for camera availability");
- mKeyguardBottomArea.launchCamera();
- mWaitingToLaunchSecureCamera = false;
- }
- }
- };
- }
-
- /**
- * Initializes the SecureCameraManager and starts listening for camera availability.
- */
- public void create() {
- mCameraManager.registerAvailabilityCallback(mCameraAvailabilityCallback, mHandler);
- }
-
- /**
- * Stops listening for camera availability and cleans up the SecureCameraManager.
- */
- public void destroy() {
- mCameraManager.unregisterAvailabilityCallback(mCameraAvailabilityCallback);
- }
-
- /**
- * Called when the user is starting to swipe horizontally, possibly to start the secure camera.
- * Although this swipe ultimately may not result in the secure camera opening, we need to stop
- * all other camera usage (e.g., Face Unlock) as soon as possible. We send out a broadcast to
- * notify other apps that they should close the camera immediately. The broadcast is sent even
- * if the camera appears to be available, because there could be an app that is about to open
- * the camera.
- */
- public void onSwipingStarted() {
- if (DEBUG) Log.d(TAG, "onSwipingStarted");
- AsyncTask.execute(new Runnable() {
- @Override
- public void run() {
- Intent intent = new Intent();
- intent.setAction(CLOSE_CAMERA_ACTION_NAME);
- intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
- mContext.sendBroadcast(intent);
- }
- });
- }
-
- /**
- * Called when the secure camera should be started. If the camera is available or the secure
- * camera app has indicated that it will wait for camera availability, the secure camera app is
- * launched immediately. Otherwise, we wait for the camera to become available (or timeout)
- * before launching the secure camera.
- */
- public void startSecureCameraLaunch() {
- if (DEBUG) Log.d(TAG, "startSecureCameraLunch");
- if (areAllCamerasAvailable() || targetWillWaitForCameraAvailable()) {
- mKeyguardBottomArea.launchCamera();
- } else {
- mWaitingToLaunchSecureCamera = true;
- mHandler.postDelayed(mLaunchCameraRunnable, CAMERA_AVAILABILITY_TIMEOUT_MS);
- }
- }
-
- /**
- * Returns true if all of the cameras we are tracking are currently available.
- */
- private boolean areAllCamerasAvailable() {
- for (boolean cameraAvailable: mCameraAvailabilityMap.values()) {
- if (!cameraAvailable) {
- return false;
- }
- }
- return true;
- }
-
- /**
- * Determines if the secure camera app will wait for the camera hardware to become available
- * before trying to open the camera. If so, we can fire off an intent to start the secure
- * camera app before the camera is available. Otherwise, it is our responsibility to wait for
- * the camera hardware to become available before firing off the intent to start the secure
- * camera.
- *
- * Ideally we are able to fire off the secure camera intent as early as possibly so that, if the
- * camera is closing, it can continue to close while the secure camera app is opening. This
- * improves secure camera startup time.
- */
- private boolean targetWillWaitForCameraAvailable() {
- // Create intent that would launch the secure camera.
- Intent intent = new Intent(MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA_SECURE)
- .addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
- PackageManager packageManager = mContext.getPackageManager();
-
- // Get the list of applications that can handle the intent.
- final List<ResolveInfo> appList = packageManager.queryIntentActivitiesAsUser(
- intent, PackageManager.MATCH_DEFAULT_ONLY, KeyguardUpdateMonitor.getCurrentUser());
- if (appList.size() == 0) {
- if (DEBUG) Log.d(TAG, "No targets found for secure camera intent");
- return false;
- }
-
- // Get the application that the intent resolves to.
- ResolveInfo resolved = packageManager.resolveActivityAsUser(intent,
- PackageManager.MATCH_DEFAULT_ONLY | PackageManager.GET_META_DATA,
- KeyguardUpdateMonitor.getCurrentUser());
-
- if (resolved == null || resolved.activityInfo == null) {
- return false;
- }
-
- // If we would need to launch the resolver activity, then we can't assume that the target
- // is one that would wait for the camera.
- if (wouldLaunchResolverActivity(resolved, appList)) {
- if (DEBUG) Log.d(TAG, "Secure camera intent would launch resolver");
- return false;
- }
-
- // If the target doesn't have meta-data we must assume it won't wait for the camera.
- if (resolved.activityInfo.metaData == null || resolved.activityInfo.metaData.isEmpty()) {
- if (DEBUG) Log.d(TAG, "No meta-data found for secure camera application");
- return false;
- }
-
- // Check the secure camera app meta-data to see if it indicates that it will wait for the
- // camera to become available.
- boolean willWaitForCameraAvailability =
- resolved.activityInfo.metaData.getBoolean(META_DATA_WILL_WAIT_FOR_CAMERA_AVAILABLE);
-
- if (DEBUG) Log.d(TAG, "Target will wait for camera: " + willWaitForCameraAvailability);
-
- return willWaitForCameraAvailability;
- }
-
- /**
- * Determines if the activity that would be launched by the intent is the ResolverActivity.
- */
- private boolean wouldLaunchResolverActivity(ResolveInfo resolved, List<ResolveInfo> appList) {
- // If the list contains the resolved activity, then it can't be the ResolverActivity itself.
- for (int i = 0; i < appList.size(); i++) {
- ResolveInfo tmp = appList.get(i);
- if (tmp.activityInfo.name.equals(resolved.activityInfo.name)
- && tmp.activityInfo.packageName.equals(resolved.activityInfo.packageName)) {
- return false;
- }
- }
- return true;
- }
-}
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 1f4427f..d1e1683 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -359,6 +359,9 @@ public class ConnectivityService extends IConnectivityManager.Stub
*/
private static final int EVENT_REGISTER_NETWORK_LISTENER_WITH_INTENT = 31;
+ /** Handler thread used for both of the handlers below. */
+ @VisibleForTesting
+ protected final HandlerThread mHandlerThread;
/** Handler used for internal events. */
final private InternalHandler mHandler;
/** Handler used for incoming {@link NetworkStateTracker} events. */
@@ -614,6 +617,11 @@ public class ConnectivityService extends IConnectivityManager.Stub
}
private LegacyTypeTracker mLegacyTypeTracker = new LegacyTypeTracker();
+ @VisibleForTesting
+ protected HandlerThread createHandlerThread() {
+ return new HandlerThread("ConnectivityServiceThread");
+ }
+
public ConnectivityService(Context context, INetworkManagementService netManager,
INetworkStatsService statsService, INetworkPolicyManager policyManager) {
if (DBG) log("ConnectivityService starting up");
@@ -627,10 +635,10 @@ public class ConnectivityService extends IConnectivityManager.Stub
mDefaultMobileDataRequest = createInternetRequestForTransport(
NetworkCapabilities.TRANSPORT_CELLULAR);
- HandlerThread handlerThread = new HandlerThread("ConnectivityServiceThread");
- handlerThread.start();
- mHandler = new InternalHandler(handlerThread.getLooper());
- mTrackerHandler = new NetworkStateTrackerHandler(handlerThread.getLooper());
+ mHandlerThread = createHandlerThread();
+ mHandlerThread.start();
+ mHandler = new InternalHandler(mHandlerThread.getLooper());
+ mTrackerHandler = new NetworkStateTrackerHandler(mHandlerThread.getLooper());
// setup our unique device name
if (TextUtils.isEmpty(SystemProperties.get("net.hostname"))) {
@@ -1458,7 +1466,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
}
private void enforceKeepalivePermission() {
- mContext.enforceCallingPermission(KeepaliveTracker.PERMISSION, "ConnectivityService");
+ mContext.enforceCallingOrSelfPermission(KeepaliveTracker.PERMISSION, "ConnectivityService");
}
public void sendConnectedBroadcast(NetworkInfo info) {
diff --git a/services/core/java/com/android/server/GestureLauncherService.java b/services/core/java/com/android/server/GestureLauncherService.java
index 342a3ef..69f0cef 100644
--- a/services/core/java/com/android/server/GestureLauncherService.java
+++ b/services/core/java/com/android/server/GestureLauncherService.java
@@ -17,7 +17,6 @@
package com.android.server;
import android.app.ActivityManager;
-import android.app.KeyguardManager;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
@@ -33,10 +32,11 @@ import android.os.PowerManager;
import android.os.PowerManager.WakeLock;
import android.os.SystemClock;
import android.os.SystemProperties;
-import android.os.Vibrator;
import android.provider.Settings;
import android.util.Slog;
+import android.view.KeyEvent;
+import com.android.internal.logging.MetricsLogger;
import com.android.server.statusbar.StatusBarManagerInternal;
/**
@@ -46,10 +46,16 @@ import com.android.server.statusbar.StatusBarManagerInternal;
* added.</p>
* @hide
*/
-class GestureLauncherService extends SystemService {
+public class GestureLauncherService extends SystemService {
private static final boolean DBG = false;
private static final String TAG = "GestureLauncherService";
+ /**
+ * Time in milliseconds in which the power button must be pressed twice so it will be considered
+ * as a camera launch.
+ */
+ private static final long CAMERA_POWER_DOUBLE_TAP_TIME_MS = 300;
+
/** The listener that receives the gesture event. */
private final GestureEventListener mGestureListener = new GestureEventListener();
@@ -91,13 +97,20 @@ class GestureLauncherService extends SystemService {
*/
private int mCameraLaunchLastEventExtra = 0;
+ /**
+ * Whether camera double tap power button gesture is currently enabled;
+ */
+ private boolean mCameraDoubleTapPowerEnabled;
+ private long mLastPowerDownWhileNonInteractive = 0;
+
+
public GestureLauncherService(Context context) {
super(context);
mContext = context;
}
public void onStart() {
- // Nothing to publish.
+ LocalServices.addService(GestureLauncherService.class, this);
}
public void onBootPhase(int phase) {
@@ -113,17 +126,21 @@ class GestureLauncherService extends SystemService {
mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
"GestureLauncherService");
updateCameraRegistered();
+ updateCameraDoubleTapPowerEnabled();
mUserId = ActivityManager.getCurrentUser();
mContext.registerReceiver(mUserReceiver, new IntentFilter(Intent.ACTION_USER_SWITCHED));
- registerContentObserver();
+ registerContentObservers();
}
}
- private void registerContentObserver() {
+ private void registerContentObservers() {
mContext.getContentResolver().registerContentObserver(
Settings.Secure.getUriFor(Settings.Secure.CAMERA_GESTURE_DISABLED),
false, mSettingObserver, mUserId);
+ mContext.getContentResolver().registerContentObserver(
+ Settings.Secure.getUriFor(Settings.Secure.CAMERA_DOUBLE_TAP_POWER_GESTURE_DISABLED),
+ false, mSettingObserver, mUserId);
}
private void updateCameraRegistered() {
@@ -135,6 +152,13 @@ class GestureLauncherService extends SystemService {
}
}
+ private void updateCameraDoubleTapPowerEnabled() {
+ boolean enabled = isCameraDoubleTapPowerSettingEnabled(mContext, mUserId);
+ synchronized (this) {
+ mCameraDoubleTapPowerEnabled = enabled;
+ }
+ }
+
private void unregisterCameraLaunchGesture() {
if (mRegistered) {
mRegistered = false;
@@ -197,6 +221,12 @@ class GestureLauncherService extends SystemService {
Settings.Secure.CAMERA_GESTURE_DISABLED, 0, userId) == 0);
}
+ public static boolean isCameraDoubleTapPowerSettingEnabled(Context context, int userId) {
+ return isCameraDoubleTapPowerEnabled(context.getResources())
+ && (Settings.Secure.getIntForUser(context.getContentResolver(),
+ Settings.Secure.CAMERA_DOUBLE_TAP_POWER_GESTURE_DISABLED, 0, userId) == 0);
+ }
+
/**
* Whether to enable the camera launch gesture.
*/
@@ -207,13 +237,64 @@ class GestureLauncherService extends SystemService {
!SystemProperties.getBoolean("gesture.disable_camera_launch", false);
}
+ public static boolean isCameraDoubleTapPowerEnabled(Resources resources) {
+ return resources.getBoolean(
+ com.android.internal.R.bool.config_cameraDoubleTapPowerGestureEnabled);
+ }
+
/**
* Whether GestureLauncherService should be enabled according to system properties.
*/
public static boolean isGestureLauncherEnabled(Resources resources) {
- // For now, the only supported gesture is camera launch gesture, so whether to enable this
- // service equals to isCameraLaunchEnabled();
- return isCameraLaunchEnabled(resources);
+ return isCameraLaunchEnabled(resources) || isCameraDoubleTapPowerEnabled(resources);
+ }
+
+ public boolean interceptPowerKeyDown(KeyEvent event, boolean interactive) {
+ boolean launched = false;
+ synchronized (this) {
+ if (!mCameraDoubleTapPowerEnabled) {
+ mLastPowerDownWhileNonInteractive = 0;
+ return false;
+ }
+ if (event.getEventTime() - mLastPowerDownWhileNonInteractive
+ < CAMERA_POWER_DOUBLE_TAP_TIME_MS) {
+ launched = true;
+ }
+ mLastPowerDownWhileNonInteractive = interactive ? 0 : event.getEventTime();
+ }
+ if (launched) {
+ Slog.i(TAG, "Power button double tap gesture detected, launching camera.");
+ launched = handleCameraLaunchGesture(false /* useWakelock */,
+ MetricsLogger.ACTION_DOUBLE_TAP_POWER_CAMERA_GESTURE);
+ }
+ return launched;
+ }
+
+ /**
+ * @return true if camera was launched, false otherwise.
+ */
+ private boolean handleCameraLaunchGesture(boolean useWakelock, int logCategory) {
+ boolean userSetupComplete = Settings.Secure.getInt(mContext.getContentResolver(),
+ Settings.Secure.USER_SETUP_COMPLETE, 0) != 0;
+ if (!userSetupComplete) {
+ if (DBG) Slog.d(TAG, String.format(
+ "userSetupComplete = %s, ignoring camera launch gesture.",
+ userSetupComplete));
+ return false;
+ }
+ if (DBG) Slog.d(TAG, String.format(
+ "userSetupComplete = %s, performing camera launch gesture.",
+ userSetupComplete));
+
+ if (useWakelock) {
+ // Make sure we don't sleep too early
+ mWakeLock.acquire(500L);
+ }
+ StatusBarManagerInternal service = LocalServices.getService(
+ StatusBarManagerInternal.class);
+ service.onCameraLaunchGestureDetected();
+ MetricsLogger.action(mContext, logCategory);
+ return true;
}
private final BroadcastReceiver mUserReceiver = new BroadcastReceiver() {
@@ -222,8 +303,9 @@ class GestureLauncherService extends SystemService {
if (Intent.ACTION_USER_SWITCHED.equals(intent.getAction())) {
mUserId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0);
mContext.getContentResolver().unregisterContentObserver(mSettingObserver);
- registerContentObserver();
+ registerContentObservers();
updateCameraRegistered();
+ updateCameraDoubleTapPowerEnabled();
}
}
};
@@ -232,6 +314,7 @@ class GestureLauncherService extends SystemService {
public void onChange(boolean selfChange, android.net.Uri uri, int userId) {
if (userId == mUserId) {
updateCameraRegistered();
+ updateCameraDoubleTapPowerEnabled();
}
}
};
@@ -244,36 +327,17 @@ class GestureLauncherService extends SystemService {
return;
}
if (event.sensor == mCameraLaunchSensor) {
- handleCameraLaunchGesture(event);
- return;
- }
- }
-
- private void handleCameraLaunchGesture(SensorEvent event) {
- if (DBG) {
- float[] values = event.values;
- Slog.d(TAG, String.format("Received a camera launch event: " +
- "values=[%.4f, %.4f, %.4f].", values[0], values[1], values[2]));
- }
- boolean userSetupComplete = Settings.Secure.getInt(mContext.getContentResolver(),
- Settings.Secure.USER_SETUP_COMPLETE, 0) != 0;
- if (!userSetupComplete) {
- if (DBG) Slog.d(TAG, String.format(
- "userSetupComplete = %s, ignoring camera launch gesture.",
- userSetupComplete));
+ if (DBG) {
+ float[] values = event.values;
+ Slog.d(TAG, String.format("Received a camera launch event: " +
+ "values=[%.4f, %.4f, %.4f].", values[0], values[1], values[2]));
+ }
+ if (handleCameraLaunchGesture(true /* useWakelock */,
+ MetricsLogger.ACTION_WIGGLE_CAMERA_GESTURE)) {
+ trackCameraLaunchEvent(event);
+ }
return;
}
- if (DBG) Slog.d(TAG, String.format(
- "userSetupComplete = %s, performing camera launch gesture.",
- userSetupComplete));
-
- // Make sure we don't sleep too early
- mWakeLock.acquire(500L);
- StatusBarManagerInternal service = LocalServices.getService(
- StatusBarManagerInternal.class);
- service.onCameraLaunchGestureDetected();
- trackCameraLaunchEvent(event);
- mWakeLock.release();
}
@Override
diff --git a/services/core/java/com/android/server/MountService.java b/services/core/java/com/android/server/MountService.java
index 0d64540..4e721da 100644
--- a/services/core/java/com/android/server/MountService.java
+++ b/services/core/java/com/android/server/MountService.java
@@ -368,11 +368,17 @@ class MountService extends IMountService.Stub
private boolean shouldBenchmark() {
final long benchInterval = Settings.Global.getLong(mContext.getContentResolver(),
Settings.Global.STORAGE_BENCHMARK_INTERVAL, DateUtils.WEEK_IN_MILLIS);
+ if (benchInterval == -1) {
+ return false;
+ } else if (benchInterval == 0) {
+ return true;
+ }
+
synchronized (mLock) {
for (int i = 0; i < mVolumes.size(); i++) {
final VolumeInfo vol = mVolumes.valueAt(i);
final VolumeRecord rec = mRecords.get(vol.fsUuid);
- if (vol.isMountedReadable() && rec != null) {
+ if (vol.isMountedWritable() && rec != null) {
final long benchAge = System.currentTimeMillis() - rec.lastBenchMillis;
if (benchAge >= benchInterval) {
return true;
diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java
index 8b0e6f2..d5e9a32 100644
--- a/services/core/java/com/android/server/accounts/AccountManagerService.java
+++ b/services/core/java/com/android/server/accounts/AccountManagerService.java
@@ -32,6 +32,7 @@ import android.accounts.IAccountManagerResponse;
import android.app.ActivityManager;
import android.app.ActivityManagerNative;
import android.app.AppGlobals;
+import android.app.AppOpsManager;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
@@ -122,6 +123,7 @@ public class AccountManagerService
private final Context mContext;
private final PackageManager mPackageManager;
+ private final AppOpsManager mAppOpsManager;
private UserManager mUserManager;
private final MessageHandler mMessageHandler;
@@ -266,6 +268,7 @@ public class AccountManagerService
IAccountAuthenticatorCache authenticatorCache) {
mContext = context;
mPackageManager = packageManager;
+ mAppOpsManager = mContext.getSystemService(AppOpsManager.class);
mMessageHandler = new MessageHandler(FgThread.get().getLooper());
@@ -510,7 +513,7 @@ public class AccountManagerService
// Check if there's a shared account that needs to be created as an account
Account[] sharedAccounts = getSharedAccountsAsUser(userId);
if (sharedAccounts == null || sharedAccounts.length == 0) return;
- Account[] accounts = getAccountsAsUser(null, userId);
+ Account[] accounts = getAccountsAsUser(null, userId, mContext.getOpPackageName());
for (Account sa : sharedAccounts) {
if (ArrayUtils.contains(accounts, sa)) continue;
// Account doesn't exist. Copy it now.
@@ -868,7 +871,8 @@ public class AccountManagerService
// Confirm that the owner's account still exists before this step.
UserAccounts owner = getUserAccounts(UserHandle.USER_OWNER);
synchronized (owner.cacheLock) {
- for (Account acc : getAccounts(UserHandle.USER_OWNER)) {
+ for (Account acc : getAccounts(UserHandle.USER_OWNER,
+ mContext.getOpPackageName())) {
if (acc.equals(account)) {
mAuthenticator.addAccountFromCredentials(
this, account, accountCredentials);
@@ -988,7 +992,7 @@ public class AccountManagerService
@Override
public void hasFeatures(IAccountManagerResponse response,
- Account account, String[] features) {
+ Account account, String[] features, String opPackageName) {
int callingUid = Binder.getCallingUid();
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "hasFeatures: " + account
@@ -1001,7 +1005,8 @@ public class AccountManagerService
if (account == null) throw new IllegalArgumentException("account is null");
if (features == null) throw new IllegalArgumentException("features is null");
int userId = UserHandle.getCallingUserId();
- checkReadAccountsPermitted(callingUid, account.type, userId);
+ checkReadAccountsPermitted(callingUid, account.type, userId,
+ opPackageName);
long identityToken = clearCallingIdentity();
try {
@@ -2507,9 +2512,10 @@ public class AccountManagerService
* Returns the accounts visible to the client within the context of a specific user
* @hide
*/
- public Account[] getAccounts(int userId) {
+ public Account[] getAccounts(int userId, String opPackageName) {
int callingUid = Binder.getCallingUid();
- List<String> visibleAccountTypes = getTypesVisibleToCaller(callingUid, userId);
+ List<String> visibleAccountTypes = getTypesVisibleToCaller(callingUid, userId,
+ opPackageName);
if (visibleAccountTypes.isEmpty()) {
return new Account[0];
}
@@ -2571,15 +2577,16 @@ public class AccountManagerService
}
@Override
- public Account[] getAccountsAsUser(String type, int userId) {
- return getAccountsAsUser(type, userId, null, -1);
+ public Account[] getAccountsAsUser(String type, int userId, String opPackageName) {
+ return getAccountsAsUser(type, userId, null, -1, opPackageName);
}
private Account[] getAccountsAsUser(
String type,
int userId,
String callingPackage,
- int packageUid) {
+ int packageUid,
+ String opPackageName) {
int callingUid = Binder.getCallingUid();
// Only allow the system process to read accounts of other users
if (userId != UserHandle.getCallingUserId()
@@ -2600,9 +2607,11 @@ public class AccountManagerService
// be passed in the original caller's uid here, which is what should be used for filtering.
if (packageUid != -1 && UserHandle.isSameApp(callingUid, Process.myUid())) {
callingUid = packageUid;
+ opPackageName = callingPackage;
}
- List<String> visibleAccountTypes = getTypesVisibleToCaller(callingUid, userId);
+ List<String> visibleAccountTypes = getTypesVisibleToCaller(callingUid, userId,
+ opPackageName);
if (visibleAccountTypes.isEmpty()
|| (type != null && !visibleAccountTypes.contains(type))) {
return new Account[0];
@@ -2741,22 +2750,24 @@ public class AccountManagerService
}
@Override
- public Account[] getAccounts(String type) {
- return getAccountsAsUser(type, UserHandle.getCallingUserId());
+ public Account[] getAccounts(String type, String opPackageName) {
+ return getAccountsAsUser(type, UserHandle.getCallingUserId(), opPackageName);
}
@Override
- public Account[] getAccountsForPackage(String packageName, int uid) {
+ public Account[] getAccountsForPackage(String packageName, int uid, String opPackageName) {
int callingUid = Binder.getCallingUid();
if (!UserHandle.isSameApp(callingUid, Process.myUid())) {
throw new SecurityException("getAccountsForPackage() called from unauthorized uid "
+ callingUid + " with uid=" + uid);
}
- return getAccountsAsUser(null, UserHandle.getCallingUserId(), packageName, uid);
+ return getAccountsAsUser(null, UserHandle.getCallingUserId(), packageName, uid,
+ opPackageName);
}
@Override
- public Account[] getAccountsByTypeForPackage(String type, String packageName) {
+ public Account[] getAccountsByTypeForPackage(String type, String packageName,
+ String opPackageName) {
int packageUid = -1;
try {
packageUid = AppGlobals.getPackageManager().getPackageUid(
@@ -2765,14 +2776,16 @@ public class AccountManagerService
Slog.e(TAG, "Couldn't determine the packageUid for " + packageName + re);
return new Account[0];
}
- return getAccountsAsUser(type, UserHandle.getCallingUserId(), packageName, packageUid);
+ return getAccountsAsUser(type, UserHandle.getCallingUserId(), packageName,
+ packageUid, opPackageName);
}
@Override
public void getAccountsByFeatures(
IAccountManagerResponse response,
String type,
- String[] features) {
+ String[] features,
+ String opPackageName) {
int callingUid = Binder.getCallingUid();
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "getAccounts: accountType " + type
@@ -2785,7 +2798,8 @@ public class AccountManagerService
if (type == null) throw new IllegalArgumentException("accountType is null");
int userId = UserHandle.getCallingUserId();
- List<String> visibleAccountTypes = getTypesVisibleToCaller(callingUid, userId);
+ List<String> visibleAccountTypes = getTypesVisibleToCaller(callingUid, userId,
+ opPackageName);
if (!visibleAccountTypes.contains(type)) {
Bundle result = new Bundle();
// Need to return just the accounts that are from matching signatures.
@@ -3685,31 +3699,22 @@ public class AccountManagerService
}
}
- private boolean isPermitted(int callingUid, String... permissions) {
+ private boolean isPermitted(String opPackageName, int callingUid, String... permissions) {
for (String perm : permissions) {
if (mContext.checkCallingOrSelfPermission(perm) == PackageManager.PERMISSION_GRANTED) {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, " caller uid " + callingUid + " has " + perm);
}
- return true;
+ final int opCode = AppOpsManager.permissionToOpCode(perm);
+ if (opCode == AppOpsManager.OP_NONE || mAppOpsManager.noteOp(
+ opCode, callingUid, opPackageName) == AppOpsManager.MODE_ALLOWED) {
+ return true;
+ }
}
}
return false;
}
- /** Succeeds if any of the specified permissions are granted. */
- private void checkBinderPermission(String... permissions) {
- final int callingUid = Binder.getCallingUid();
- if (isPermitted(callingUid, permissions)) {
- String msg = String.format(
- "caller uid %s lacks any of %s",
- callingUid,
- TextUtils.join(",", permissions));
- Log.w(TAG, " " + msg);
- throw new SecurityException(msg);
- }
- }
-
private int handleIncomingUser(int userId) {
try {
return ActivityManagerNative.getDefault().handleIncomingUser(
@@ -3763,11 +3768,13 @@ public class AccountManagerService
return fromAuthenticator || hasExplicitGrants || isPrivileged;
}
- private boolean isAccountVisibleToCaller(String accountType, int callingUid, int userId) {
+ private boolean isAccountVisibleToCaller(String accountType, int callingUid, int userId,
+ String opPackageName) {
if (accountType == null) {
return false;
} else {
- return getTypesVisibleToCaller(callingUid, userId).contains(accountType);
+ return getTypesVisibleToCaller(callingUid, userId,
+ opPackageName).contains(accountType);
}
}
@@ -3779,9 +3786,10 @@ public class AccountManagerService
}
}
- private List<String> getTypesVisibleToCaller(int callingUid, int userId) {
+ private List<String> getTypesVisibleToCaller(int callingUid, int userId,
+ String opPackageName) {
boolean isPermitted =
- isPermitted(callingUid, Manifest.permission.GET_ACCOUNTS,
+ isPermitted(opPackageName, callingUid, Manifest.permission.GET_ACCOUNTS,
Manifest.permission.GET_ACCOUNTS_PRIVILEGED);
Log.i(TAG, String.format("getTypesVisibleToCaller: isPermitted? %s", isPermitted));
return getTypesForCaller(callingUid, userId, isPermitted);
@@ -3877,8 +3885,9 @@ public class AccountManagerService
private void checkReadAccountsPermitted(
int callingUid,
String accountType,
- int userId) {
- if (!isAccountVisibleToCaller(accountType, callingUid, userId)) {
+ int userId,
+ String opPackageName) {
+ if (!isAccountVisibleToCaller(accountType, callingUid, userId, opPackageName)) {
String msg = String.format(
"caller uid %s cannot access %s accounts",
callingUid,
diff --git a/services/core/java/com/android/server/connectivity/KeepalivePacketData.java b/services/core/java/com/android/server/connectivity/KeepalivePacketData.java
index 64b9399..2ccfdd1 100644
--- a/services/core/java/com/android/server/connectivity/KeepalivePacketData.java
+++ b/services/core/java/com/android/server/connectivity/KeepalivePacketData.java
@@ -71,6 +71,7 @@ public class KeepalivePacketData {
// Check we have two IP addresses of the same family.
if (srcAddress == null || dstAddress == null ||
!srcAddress.getClass().getName().equals(dstAddress.getClass().getName())) {
+ throw new InvalidPacketException(ERROR_INVALID_IP_ADDRESS);
}
// Set the protocol.
@@ -102,7 +103,7 @@ public class KeepalivePacketData {
InetAddress srcAddress, int srcPort,
InetAddress dstAddress, int dstPort) throws InvalidPacketException {
- if (!(srcAddress instanceof Inet4Address)) {
+ if (!(srcAddress instanceof Inet4Address) || !(dstAddress instanceof Inet4Address)) {
throw new InvalidPacketException(ERROR_INVALID_IP_ADDRESS);
}
diff --git a/services/core/java/com/android/server/connectivity/KeepaliveTracker.java b/services/core/java/com/android/server/connectivity/KeepaliveTracker.java
index c78f347..90c9ddf 100644
--- a/services/core/java/com/android/server/connectivity/KeepaliveTracker.java
+++ b/services/core/java/com/android/server/connectivity/KeepaliveTracker.java
@@ -62,8 +62,7 @@ public class KeepaliveTracker {
private static final String TAG = "KeepaliveTracker";
private static final boolean DBG = true;
- // TODO: Change this to a system-only permission.
- public static final String PERMISSION = android.Manifest.permission.CHANGE_NETWORK_STATE;
+ public static final String PERMISSION = android.Manifest.permission.PACKET_KEEPALIVE_OFFLOAD;
/** Keeps track of keepalive requests. */
private final HashMap <NetworkAgentInfo, HashMap<Integer, KeepaliveInfo>> mKeepalives =
@@ -208,6 +207,8 @@ public class KeepaliveTracker {
Log.d(TAG, "Stopping keepalive " + mSlot + " on " + mNai.name());
mNai.asyncChannel.sendMessage(CMD_STOP_PACKET_KEEPALIVE, mSlot);
}
+ // TODO: at the moment we unconditionally return failure here. In cases where the
+ // NetworkAgent is alive, should we ask it to reply, so it can return failure?
notifyMessenger(mSlot, reason);
unlinkDeathRecipient();
}
@@ -233,17 +234,14 @@ public class KeepaliveTracker {
mKeepalives.put(nai, networkKeepalives);
}
- // Find the lowest-numbered free slot.
+ // Find the lowest-numbered free slot. Slot numbers start from 1, because that's what two
+ // separate chipset implementations independently came up with.
int slot;
- for (slot = 0; slot < networkKeepalives.size(); slot++) {
+ for (slot = 1; slot <= networkKeepalives.size(); slot++) {
if (networkKeepalives.get(slot) == null) {
return slot;
}
}
- // No free slot, pick one at the end.
-
- // HACK for broadcom hardware that does not support slot 0!
- if (slot == 0) slot = 1;
return slot;
}
@@ -267,14 +265,15 @@ public class KeepaliveTracker {
}
public void handleStopKeepalive(NetworkAgentInfo nai, int slot, int reason) {
+ String networkName = (nai == null) ? "(null)" : nai.name();
HashMap <Integer, KeepaliveInfo> networkKeepalives = mKeepalives.get(nai);
if (networkKeepalives == null) {
- Log.e(TAG, "Attempt to stop keepalive on nonexistent network " + nai.name());
+ Log.e(TAG, "Attempt to stop keepalive on nonexistent network " + networkName);
return;
}
KeepaliveInfo ki = networkKeepalives.get(slot);
if (ki == null) {
- Log.e(TAG, "Attempt to stop nonexistent keepalive " + slot + " on " + nai.name());
+ Log.e(TAG, "Attempt to stop nonexistent keepalive " + slot + " on " + networkName);
return;
}
ki.stop(reason);
@@ -332,6 +331,11 @@ public class KeepaliveTracker {
public void startNattKeepalive(NetworkAgentInfo nai, int intervalSeconds, Messenger messenger,
IBinder binder, String srcAddrString, int srcPort, String dstAddrString, int dstPort) {
+ if (nai == null) {
+ notifyMessenger(messenger, NO_KEEPALIVE, ERROR_INVALID_NETWORK);
+ return;
+ }
+
InetAddress srcAddress, dstAddress;
try {
srcAddress = NetworkUtils.numericToInetAddress(srcAddrString);
diff --git a/services/core/java/com/android/server/content/SyncManager.java b/services/core/java/com/android/server/content/SyncManager.java
index c998c2c..334bc18 100644
--- a/services/core/java/com/android/server/content/SyncManager.java
+++ b/services/core/java/com/android/server/content/SyncManager.java
@@ -340,7 +340,8 @@ public class SyncManager {
for (UserInfo user : mUserManager.getUsers(true)) {
// Skip any partially created/removed users
if (user.partial) continue;
- Account[] accountsForUser = AccountManagerService.getSingleton().getAccounts(user.id);
+ Account[] accountsForUser = AccountManagerService.getSingleton().getAccounts(
+ user.id, mContext.getOpPackageName());
mSyncStorageEngine.doDatabaseCleanup(accountsForUser, user.id);
}
}
@@ -1232,7 +1233,8 @@ public class SyncManager {
}
// Schedule sync for any accounts under started user
- final Account[] accounts = AccountManagerService.getSingleton().getAccounts(userId);
+ final Account[] accounts = AccountManagerService.getSingleton().getAccounts(userId,
+ mContext.getOpPackageName());
for (Account account : accounts) {
scheduleSync(account, userId, SyncOperation.REASON_USER_START, null, null,
0 /* no delay */, 0 /* No flex */,
diff --git a/services/core/java/com/android/server/display/DisplayPowerState.java b/services/core/java/com/android/server/display/DisplayPowerState.java
index f53ccc9..2eabd32 100644
--- a/services/core/java/com/android/server/display/DisplayPowerState.java
+++ b/services/core/java/com/android/server/display/DisplayPowerState.java
@@ -341,7 +341,8 @@ final class DisplayPowerState {
private int mPendingBacklight = INITIAL_BACKLIGHT;
private int mActualState = INITIAL_SCREEN_STATE;
private int mActualBacklight = INITIAL_BACKLIGHT;
- private boolean mChangeInProgress;
+ private boolean mStateChangeInProgress;
+ private boolean mBacklightChangeInProgress;
public PhotonicModulator() {
super("PhotonicModulator");
@@ -349,7 +350,9 @@ final class DisplayPowerState {
public boolean setState(int state, int backlight) {
synchronized (mLock) {
- if (state != mPendingState || backlight != mPendingBacklight) {
+ boolean stateChanged = state != mPendingState;
+ boolean backlightChanged = backlight != mPendingBacklight;
+ if (stateChanged || backlightChanged) {
if (DEBUG) {
Slog.d(TAG, "Requesting new screen state: state="
+ Display.stateToString(state) + ", backlight=" + backlight);
@@ -358,12 +361,15 @@ final class DisplayPowerState {
mPendingState = state;
mPendingBacklight = backlight;
- if (!mChangeInProgress) {
- mChangeInProgress = true;
+ boolean changeInProgress = mStateChangeInProgress || mBacklightChangeInProgress;
+ mStateChangeInProgress = stateChanged;
+ mBacklightChangeInProgress = backlightChanged;
+
+ if (!changeInProgress) {
mLock.notifyAll();
}
}
- return !mChangeInProgress;
+ return !mStateChangeInProgress;
}
}
@@ -375,7 +381,8 @@ final class DisplayPowerState {
pw.println(" mPendingBacklight=" + mPendingBacklight);
pw.println(" mActualState=" + Display.stateToString(mActualState));
pw.println(" mActualBacklight=" + mActualBacklight);
- pw.println(" mChangeInProgress=" + mChangeInProgress);
+ pw.println(" mStateChangeInProgress=" + mStateChangeInProgress);
+ pw.println(" mBacklightChangeInProgress=" + mBacklightChangeInProgress);
}
}
@@ -392,10 +399,15 @@ final class DisplayPowerState {
stateChanged = (state != mActualState);
backlight = mPendingBacklight;
backlightChanged = (backlight != mActualBacklight);
- if (!stateChanged && !backlightChanged) {
- // All changed applied, notify outer class and wait for more.
- mChangeInProgress = false;
+ if (!stateChanged) {
+ // State changed applied, notify outer class.
postScreenUpdateThreadSafe();
+ mStateChangeInProgress = false;
+ }
+ if (!backlightChanged) {
+ mBacklightChangeInProgress = false;
+ }
+ if (!stateChanged && !backlightChanged) {
try {
mLock.wait();
} catch (InterruptedException ex) { }
diff --git a/services/core/java/com/android/server/fingerprint/FingerprintService.java b/services/core/java/com/android/server/fingerprint/FingerprintService.java
index 0023258..ea7d85e 100644
--- a/services/core/java/com/android/server/fingerprint/FingerprintService.java
+++ b/services/core/java/com/android/server/fingerprint/FingerprintService.java
@@ -21,10 +21,15 @@ import android.app.ActivityManager;
import android.app.ActivityManager.RunningAppProcessInfo;
import android.app.ActivityManager.RunningTaskInfo;
import android.app.ActivityManagerNative;
+import android.app.AlarmManager;
import android.app.AppOpsManager;
import android.app.IUserSwitchObserver;
+import android.app.PendingIntent;
import android.content.ComponentName;
+import android.content.BroadcastReceiver;
import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.content.pm.UserInfo;
import android.hardware.fingerprint.IFingerprintServiceLockoutResetCallback;
@@ -85,6 +90,8 @@ public class FingerprintService extends SystemService implements IBinder.DeathRe
private static final String FINGERPRINTD = "android.hardware.fingerprint.IFingerprintDaemon";
private static final int MSG_USER_SWITCHING = 10;
private static final int ENROLLMENT_TIMEOUT_MS = 60 * 1000; // 1 minute
+ private static final String ACTION_LOCKOUT_RESET =
+ "com.android.server.fingerprint.ACTION_LOCKOUT_RESET";
private ClientMonitor mAuthClient = null;
private ClientMonitor mEnrollClient = null;
@@ -118,9 +125,19 @@ public class FingerprintService extends SystemService implements IBinder.DeathRe
private long mHalDeviceId;
private int mFailedAttempts;
private IFingerprintDaemon mDaemon;
- private PowerManager mPowerManager;
+ private final PowerManager mPowerManager;
+ private final AlarmManager mAlarmManager;
- private final Runnable mLockoutReset = new Runnable() {
+ private final BroadcastReceiver mLockoutReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (ACTION_LOCKOUT_RESET.equals(intent.getAction())) {
+ resetFailedAttempts();
+ }
+ }
+ };
+
+ private final Runnable mResetFailedAttemptsRunnable = new Runnable() {
@Override
public void run() {
resetFailedAttempts();
@@ -133,7 +150,10 @@ public class FingerprintService extends SystemService implements IBinder.DeathRe
mKeyguardPackage = ComponentName.unflattenFromString(context.getResources().getString(
com.android.internal.R.string.config_keyguardComponent)).getPackageName();
mAppOps = context.getSystemService(AppOpsManager.class);
- mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
+ mPowerManager = mContext.getSystemService(PowerManager.class);
+ mAlarmManager = mContext.getSystemService(AlarmManager.class);
+ mContext.registerReceiver(mLockoutReceiver, new IntentFilter(ACTION_LOCKOUT_RESET),
+ RESET_FINGERPRINT_LOCKOUT, null /* handler */);
}
@Override
@@ -262,14 +282,28 @@ public class FingerprintService extends SystemService implements IBinder.DeathRe
return mFailedAttempts >= MAX_FAILED_ATTEMPTS;
}
+ private void scheduleLockoutReset() {
+ mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
+ SystemClock.elapsedRealtime() + FAIL_LOCKOUT_TIMEOUT_MS, getLockoutResetIntent());
+ }
+
+ private void cancelLockoutReset() {
+ mAlarmManager.cancel(getLockoutResetIntent());
+ }
+
+ private PendingIntent getLockoutResetIntent() {
+ return PendingIntent.getBroadcast(mContext, 0,
+ new Intent(ACTION_LOCKOUT_RESET), PendingIntent.FLAG_UPDATE_CURRENT);
+ }
+
private void resetFailedAttempts() {
if (DEBUG && inLockoutMode()) {
Slog.v(TAG, "Reset fingerprint lockout");
}
mFailedAttempts = 0;
- // If we're asked to reset failed attempts externally (i.e. from Keyguard), the runnable
- // may still be in the queue; remove it.
- mHandler.removeCallbacks(mLockoutReset);
+ // If we're asked to reset failed attempts externally (i.e. from Keyguard), the alarm might
+ // still be pending; remove it.
+ cancelLockoutReset();
notifyLockoutResetMonitors();
}
@@ -277,8 +311,7 @@ public class FingerprintService extends SystemService implements IBinder.DeathRe
mFailedAttempts++;
if (inLockoutMode()) {
// Failing multiple times will continue to push out the lockout time.
- mHandler.removeCallbacks(mLockoutReset);
- mHandler.postDelayed(mLockoutReset, FAIL_LOCKOUT_TIMEOUT_MS);
+ scheduleLockoutReset();
if (clientMonitor != null
&& !clientMonitor.sendError(FingerprintManager.FINGERPRINT_ERROR_LOCKOUT)) {
Slog.w(TAG, "Cannot send lockout message to client");
@@ -683,7 +716,7 @@ public class FingerprintService extends SystemService implements IBinder.DeathRe
FingerprintUtils.vibrateFingerprintSuccess(getContext());
}
result |= true; // we have a valid fingerprint
- mHandler.post(mLockoutReset);
+ resetFailedAttempts();
}
return result;
}
@@ -1016,7 +1049,7 @@ public class FingerprintService extends SystemService implements IBinder.DeathRe
public void resetTimeout(byte [] token) {
checkPermission(RESET_FINGERPRINT_LOCKOUT);
// TODO: confirm security token when we move timeout management into the HAL layer.
- mHandler.post(mLockoutReset);
+ mHandler.post(mResetFailedAttemptsRunnable);
}
@Override
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 34737c1..d7e3c54 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -117,6 +117,7 @@ import com.android.internal.R;
import com.android.internal.statusbar.IStatusBarService;
import com.android.internal.util.ScreenShapeHelper;
import com.android.internal.widget.PointerLocationView;
+import com.android.server.GestureLauncherService;
import com.android.server.LocalServices;
import com.android.server.policy.keyguard.KeyguardServiceDelegate;
import com.android.server.policy.keyguard.KeyguardServiceDelegate.DrawnListener;
@@ -125,7 +126,6 @@ import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.io.PrintWriter;
-import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
@@ -931,10 +931,17 @@ public class PhoneWindowManager implements WindowManagerPolicy {
}
}
+ GestureLauncherService gestureService = LocalServices.getService(
+ GestureLauncherService.class);
+ boolean gesturedServiceIntercepted = false;
+ if (gestureService != null) {
+ gesturedServiceIntercepted = gestureService.interceptPowerKeyDown(event, interactive);
+ }
+
// If the power key has still not yet been handled, then detect short
// press, long press, or multi press and decide what to do.
mPowerKeyHandled = hungUp || mScreenshotChordVolumeDownKeyTriggered
- || mScreenshotChordVolumeUpKeyTriggered;
+ || mScreenshotChordVolumeUpKeyTriggered || gesturedServiceIntercepted;
if (!mPowerKeyHandled) {
if (interactive) {
// When interactive, we're already awake.
diff --git a/services/tests/servicestests/AndroidManifest.xml b/services/tests/servicestests/AndroidManifest.xml
index 919293a..8bb20a6 100644
--- a/services/tests/servicestests/AndroidManifest.xml
+++ b/services/tests/servicestests/AndroidManifest.xml
@@ -39,6 +39,7 @@
<uses-permission android:name="android.permission.MODIFY_PHONE_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
+ <uses-permission android:name="android.permission.PACKET_KEEPALIVE_OFFLOAD" />
<application>
<uses-library android:name="android.test.runner" />
diff --git a/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java b/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java
index b4c76b7..97e16da 100644
--- a/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java
@@ -20,35 +20,9 @@ import static android.net.ConnectivityManager.CONNECTIVITY_ACTION;
import static android.net.ConnectivityManager.TYPE_MOBILE;
import static android.net.ConnectivityManager.TYPE_WIFI;
import static android.net.ConnectivityManager.getNetworkTypeName;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_CAPTIVE_PORTAL;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_CBS;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_DUN;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_EIMS;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_FOTA;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_IA;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_IMS;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_MMS;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VPN;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_RCS;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_SUPL;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_TRUSTED;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_WIFI_P2P;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_XCAP;
-import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
-import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
-import static org.mockito.Matchers.anyInt;
-import static org.mockito.Matchers.eq;
-import static org.mockito.Matchers.isA;
-import static org.mockito.Mockito.doNothing;
-import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.doThrow;
+import static android.net.NetworkCapabilities.*;
+
import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.reset;
-import static org.mockito.Mockito.verify;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
@@ -58,8 +32,12 @@ import android.content.Intent;
import android.content.IntentFilter;
import android.net.ConnectivityManager;
import android.net.ConnectivityManager.NetworkCallback;
+import android.net.ConnectivityManager.PacketKeepalive;
+import android.net.ConnectivityManager.PacketKeepaliveCallback;
import android.net.INetworkPolicyManager;
import android.net.INetworkStatsService;
+import android.net.IpPrefix;
+import android.net.LinkAddress;
import android.net.LinkProperties;
import android.net.Network;
import android.net.NetworkAgent;
@@ -74,8 +52,11 @@ import android.net.RouteInfo;
import android.os.ConditionVariable;
import android.os.Handler;
import android.os.HandlerThread;
-import android.os.Looper;
import android.os.INetworkManagementService;
+import android.os.Looper;
+import android.os.Message;
+import android.os.MessageQueue;
+import android.os.MessageQueue.IdleHandler;
import android.test.AndroidTestCase;
import android.test.suitebuilder.annotation.LargeTest;
import android.util.Log;
@@ -84,10 +65,10 @@ import android.util.LogPrinter;
import com.android.server.connectivity.NetworkAgentInfo;
import com.android.server.connectivity.NetworkMonitor;
-import org.mockito.ArgumentCaptor;
-
import java.net.InetAddress;
-import java.util.concurrent.Future;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
/**
@@ -99,24 +80,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
public class ConnectivityServiceTest extends AndroidTestCase {
private static final String TAG = "ConnectivityServiceTest";
- private static final String MOBILE_IFACE = "rmnet3";
- private static final String WIFI_IFACE = "wlan6";
-
- private static final RouteInfo MOBILE_ROUTE_V4 = RouteInfo.makeHostRoute(parse("10.0.0.33"),
- MOBILE_IFACE);
- private static final RouteInfo MOBILE_ROUTE_V6 = RouteInfo.makeHostRoute(parse("fd00::33"),
- MOBILE_IFACE);
-
- private static final RouteInfo WIFI_ROUTE_V4 = RouteInfo.makeHostRoute(parse("192.168.0.66"),
- parse("192.168.0.1"),
- WIFI_IFACE);
- private static final RouteInfo WIFI_ROUTE_V6 = RouteInfo.makeHostRoute(parse("fd00::66"),
- parse("fd00::"),
- WIFI_IFACE);
-
- private INetworkManagementService mNetManager;
- private INetworkStatsService mStatsService;
- private INetworkPolicyManager mPolicyService;
+ private static final int TIMEOUT_MS = 500;
private BroadcastInterceptingContext mServiceContext;
private WrappedConnectivityService mService;
@@ -148,14 +112,93 @@ public class ConnectivityServiceTest extends AndroidTestCase {
}
}
+ /**
+ * A subclass of HandlerThread that allows callers to wait for it to become idle. waitForIdle
+ * will return immediately if the handler is already idle.
+ */
+ private class IdleableHandlerThread extends HandlerThread {
+ private IdleHandler mIdleHandler;
+
+ public IdleableHandlerThread(String name) {
+ super(name);
+ }
+
+ public void waitForIdle(int timeoutMs) {
+ final ConditionVariable cv = new ConditionVariable();
+ final MessageQueue queue = getLooper().getQueue();
+
+ synchronized (queue) {
+ if (queue.isIdle()) {
+ return;
+ }
+
+ assertNull("BUG: only one idle handler allowed", mIdleHandler);
+ mIdleHandler = new IdleHandler() {
+ public boolean queueIdle() {
+ cv.open();
+ mIdleHandler = null;
+ return false; // Remove the handler.
+ }
+ };
+ queue.addIdleHandler(mIdleHandler);
+ }
+
+ if (!cv.block(timeoutMs)) {
+ fail("HandlerThread " + getName() +
+ " did not become idle after " + timeoutMs + " ms");
+ queue.removeIdleHandler(mIdleHandler);
+ }
+ }
+ }
+
+ // Tests that IdleableHandlerThread works as expected.
+ public void testIdleableHandlerThread() {
+ final int attempts = 50; // Causes the test to take about 200ms on bullhead-eng.
+
+ // Tests that waitForIdle returns immediately if the service is already idle.
+ for (int i = 0; i < attempts; i++) {
+ mService.waitForIdle();
+ }
+
+ // Bring up a network that we can use to send messages to ConnectivityService.
+ ConditionVariable cv = waitForConnectivityBroadcasts(1);
+ mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+ mWiFiNetworkAgent.connect(false);
+ waitFor(cv);
+ Network n = mWiFiNetworkAgent.getNetwork();
+ assertNotNull(n);
+
+ // Tests that calling waitForIdle waits for messages to be processed.
+ for (int i = 0; i < attempts; i++) {
+ mWiFiNetworkAgent.setSignalStrength(i);
+ mService.waitForIdle();
+ assertEquals(i, mCm.getNetworkCapabilities(n).getSignalStrength());
+ }
+
+ // Ensure that not calling waitForIdle causes a race condition.
+ for (int i = 0; i < attempts; i++) {
+ mWiFiNetworkAgent.setSignalStrength(i);
+ if (i != mCm.getNetworkCapabilities(n).getSignalStrength()) {
+ // We hit a race condition, as expected. Pass the test.
+ return;
+ }
+ }
+
+ // No race? There is a bug in this test.
+ fail("expected race condition at least once in " + attempts + " attempts");
+ }
+
private class MockNetworkAgent {
private final WrappedNetworkMonitor mWrappedNetworkMonitor;
private final NetworkInfo mNetworkInfo;
private final NetworkCapabilities mNetworkCapabilities;
- private final Thread mThread;
+ private final IdleableHandlerThread mHandlerThread;
private final ConditionVariable mDisconnected = new ConditionVariable();
private int mScore;
private NetworkAgent mNetworkAgent;
+ private int mStartKeepaliveError = PacketKeepalive.ERROR_HARDWARE_UNSUPPORTED;
+ private int mStopKeepaliveError = PacketKeepalive.NO_KEEPALIVE;
+ private Integer mExpectedKeepaliveSlot = null;
MockNetworkAgent(int transport) {
final int type = transportToLegacyType(transport);
@@ -173,26 +216,42 @@ public class ConnectivityServiceTest extends AndroidTestCase {
default:
throw new UnsupportedOperationException("unimplemented network type");
}
- final ConditionVariable initComplete = new ConditionVariable();
- final ConditionVariable networkMonitorAvailable = mService.getNetworkMonitorCreatedCV();
- mThread = new Thread() {
- public void run() {
- Looper.prepare();
- mNetworkAgent = new NetworkAgent(Looper.myLooper(), mServiceContext,
- "Mock" + typeName, mNetworkInfo, mNetworkCapabilities,
- new LinkProperties(), mScore, new NetworkMisc()) {
- public void unwanted() { mDisconnected.open(); }
- };
- initComplete.open();
- Looper.loop();
+ mHandlerThread = new IdleableHandlerThread("Mock-" + typeName);
+ mHandlerThread.start();
+ mNetworkAgent = new NetworkAgent(mHandlerThread.getLooper(), mServiceContext,
+ "Mock-" + typeName, mNetworkInfo, mNetworkCapabilities,
+ new LinkProperties(), mScore, new NetworkMisc()) {
+ @Override
+ public void unwanted() { mDisconnected.open(); }
+
+ @Override
+ public void startPacketKeepalive(Message msg) {
+ int slot = msg.arg1;
+ if (mExpectedKeepaliveSlot != null) {
+ assertEquals((int) mExpectedKeepaliveSlot, slot);
+ }
+ onPacketKeepaliveEvent(slot, mStartKeepaliveError);
+ }
+
+ @Override
+ public void stopPacketKeepalive(Message msg) {
+ onPacketKeepaliveEvent(msg.arg1, mStopKeepaliveError);
}
};
- mThread.start();
- waitFor(initComplete);
- waitFor(networkMonitorAvailable);
+ // Waits for the NetworkAgent to be registered, which includes the creation of the
+ // NetworkMonitor.
+ mService.waitForIdle();
mWrappedNetworkMonitor = mService.getLastCreatedWrappedNetworkMonitor();
}
+ public void waitForIdle(int timeoutMs) {
+ mHandlerThread.waitForIdle(timeoutMs);
+ }
+
+ public void waitForIdle() {
+ waitForIdle(TIMEOUT_MS);
+ }
+
public void adjustScore(int change) {
mScore += change;
mNetworkAgent.sendNetworkScore(mScore);
@@ -203,6 +262,11 @@ public class ConnectivityServiceTest extends AndroidTestCase {
mNetworkAgent.sendNetworkCapabilities(mNetworkCapabilities);
}
+ public void setSignalStrength(int signalStrength) {
+ mNetworkCapabilities.setSignalStrength(signalStrength);
+ mNetworkAgent.sendNetworkCapabilities(mNetworkCapabilities);
+ }
+
public void connectWithoutInternet() {
mNetworkInfo.setDetailedState(DetailedState.CONNECTED, null, null);
mNetworkAgent.sendNetworkInfo(mNetworkInfo);
@@ -272,15 +336,46 @@ public class ConnectivityServiceTest extends AndroidTestCase {
public WrappedNetworkMonitor getWrappedNetworkMonitor() {
return mWrappedNetworkMonitor;
}
+
+ public void sendLinkProperties(LinkProperties lp) {
+ mNetworkAgent.sendLinkProperties(lp);
+ }
+
+ public void setStartKeepaliveError(int error) {
+ mStartKeepaliveError = error;
+ }
+
+ public void setStopKeepaliveError(int error) {
+ mStopKeepaliveError = error;
+ }
+
+ public void setExpectedKeepaliveSlot(Integer slot) {
+ mExpectedKeepaliveSlot = slot;
+ }
}
+ /**
+ * A NetworkFactory that allows tests to wait until any in-flight NetworkRequest add or remove
+ * operations have been processed. Before ConnectivityService can add or remove any requests,
+ * the factory must be told to expect those operations by calling expectAddRequests or
+ * expectRemoveRequests.
+ */
private static class MockNetworkFactory extends NetworkFactory {
private final ConditionVariable mNetworkStartedCV = new ConditionVariable();
private final ConditionVariable mNetworkStoppedCV = new ConditionVariable();
- private final ConditionVariable mNetworkRequestedCV = new ConditionVariable();
- private final ConditionVariable mNetworkReleasedCV = new ConditionVariable();
private final AtomicBoolean mNetworkStarted = new AtomicBoolean(false);
+ // Used to expect that requests be removed or added on a separate thread, without sleeping.
+ // Callers can call either expectAddRequests() or expectRemoveRequests() exactly once, then
+ // cause some other thread to add or remove requests, then call waitForRequests(). We can
+ // either expect requests to be added or removed, but not both, because CountDownLatch can
+ // only count in one direction.
+ private CountDownLatch mExpectations;
+
+ // Whether we are currently expecting requests to be added or removed. Valid only if
+ // mExpectations is non-null.
+ private boolean mExpectingAdditions;
+
public MockNetworkFactory(Looper looper, Context context, String logTag,
NetworkCapabilities filter) {
super(looper, context, logTag, filter);
@@ -314,28 +409,75 @@ public class ConnectivityServiceTest extends AndroidTestCase {
return mNetworkStoppedCV;
}
- protected void needNetworkFor(NetworkRequest networkRequest, int score) {
- super.needNetworkFor(networkRequest, score);
- mNetworkRequestedCV.open();
+ @Override
+ protected void handleAddRequest(NetworkRequest request, int score) {
+ // If we're expecting anything, we must be expecting additions.
+ if (mExpectations != null && !mExpectingAdditions) {
+ fail("Can't add requests while expecting requests to be removed");
+ }
+
+ // Add the request.
+ super.handleAddRequest(request, score);
+
+ // Reduce the number of request additions we're waiting for.
+ if (mExpectingAdditions) {
+ assertTrue("Added more requests than expected", mExpectations.getCount() > 0);
+ mExpectations.countDown();
+ }
+ }
+
+ @Override
+ protected void handleRemoveRequest(NetworkRequest request) {
+ // If we're expecting anything, we must be expecting removals.
+ if (mExpectations != null && mExpectingAdditions) {
+ fail("Can't remove requests while expecting requests to be added");
+ }
+
+ // Remove the request.
+ super.handleRemoveRequest(request);
+
+ // Reduce the number of request removals we're waiting for.
+ if (!mExpectingAdditions) {
+ assertTrue("Removed more requests than expected", mExpectations.getCount() > 0);
+ mExpectations.countDown();
+ }
}
- protected void releaseNetworkFor(NetworkRequest networkRequest) {
- super.releaseNetworkFor(networkRequest);
- mNetworkReleasedCV.open();
+ private void assertNoExpectations() {
+ if (mExpectations != null) {
+ fail("Can't add expectation, " + mExpectations.getCount() + " already pending");
+ }
+ }
+
+ // Expects that count requests will be added.
+ public void expectAddRequests(final int count) {
+ assertNoExpectations();
+ mExpectingAdditions = true;
+ mExpectations = new CountDownLatch(count);
}
- public ConditionVariable getNetworkRequestedCV() {
- mNetworkRequestedCV.close();
- return mNetworkRequestedCV;
+ // Expects that count requests will be removed.
+ public void expectRemoveRequests(final int count) {
+ assertNoExpectations();
+ mExpectingAdditions = false;
+ mExpectations = new CountDownLatch(count);
}
- public ConditionVariable getNetworkReleasedCV() {
- mNetworkReleasedCV.close();
- return mNetworkReleasedCV;
+ // Waits for the expected request additions or removals to happen within a timeout.
+ public void waitForRequests() throws InterruptedException {
+ assertNotNull("Nothing to wait for", mExpectations);
+ mExpectations.await(TIMEOUT_MS, TimeUnit.MILLISECONDS);
+ final long count = mExpectations.getCount();
+ final String msg = count + " requests still not " +
+ (mExpectingAdditions ? "added" : "removed") +
+ " after " + TIMEOUT_MS + " ms";
+ assertEquals(msg, 0, count);
+ mExpectations = null;
}
- public void waitForNetworkRequests(final int count) {
- waitFor(new Criteria() { public boolean get() { return count == getRequestCount(); } });
+ public void waitForNetworkRequests(final int count) throws InterruptedException {
+ waitForRequests();
+ assertEquals(count, getMyRequestCount());
}
}
@@ -356,7 +498,6 @@ public class ConnectivityServiceTest extends AndroidTestCase {
}
private class WrappedConnectivityService extends ConnectivityService {
- private final ConditionVariable mNetworkMonitorCreated = new ConditionVariable();
private WrappedNetworkMonitor mLastCreatedNetworkMonitor;
public WrappedConnectivityService(Context context, INetworkManagementService netManager,
@@ -365,6 +506,11 @@ public class ConnectivityServiceTest extends AndroidTestCase {
}
@Override
+ protected HandlerThread createHandlerThread() {
+ return new IdleableHandlerThread("WrappedConnectivityService");
+ }
+
+ @Override
protected int getDefaultTcpRwnd() {
// Prevent wrapped ConnectivityService from trying to write to SystemProperties.
return 0;
@@ -397,7 +543,6 @@ public class ConnectivityServiceTest extends AndroidTestCase {
final WrappedNetworkMonitor monitor = new WrappedNetworkMonitor(context, handler, nai,
defaultRequest);
mLastCreatedNetworkMonitor = monitor;
- mNetworkMonitorCreated.open();
return monitor;
}
@@ -405,10 +550,14 @@ public class ConnectivityServiceTest extends AndroidTestCase {
return mLastCreatedNetworkMonitor;
}
- public ConditionVariable getNetworkMonitorCreatedCV() {
- mNetworkMonitorCreated.close();
- return mNetworkMonitorCreated;
+ public void waitForIdle(int timeoutMs) {
+ ((IdleableHandlerThread) mHandlerThread).waitForIdle(timeoutMs);
}
+
+ public void waitForIdle() {
+ waitForIdle(TIMEOUT_MS);
+ }
+
}
private interface Criteria {
@@ -431,23 +580,11 @@ public class ConnectivityServiceTest extends AndroidTestCase {
}
/**
- * Wait up to 500ms for {@code conditonVariable} to open.
- * Fails if 500ms goes by before {@code conditionVariable} opens.
+ * Wait up to TIMEOUT_MS for {@code conditionVariable} to open.
+ * Fails if TIMEOUT_MS goes by before {@code conditionVariable} opens.
*/
static private void waitFor(ConditionVariable conditionVariable) {
- assertTrue(conditionVariable.block(500));
- }
-
- /**
- * This should only be used to verify that nothing happens, in other words that no unexpected
- * changes occur. It should never be used to wait for a specific positive signal to occur.
- */
- private void shortSleep() {
- // TODO: Instead of sleeping, instead wait for all message loops to idle.
- try {
- Thread.sleep(500);
- } catch (InterruptedException e) {
- }
+ assertTrue(conditionVariable.block(TIMEOUT_MS));
}
@Override
@@ -455,13 +592,11 @@ public class ConnectivityServiceTest extends AndroidTestCase {
super.setUp();
mServiceContext = new MockContext(getContext());
+ mService = new WrappedConnectivityService(mServiceContext,
+ mock(INetworkManagementService.class),
+ mock(INetworkStatsService.class),
+ mock(INetworkPolicyManager.class));
- mNetManager = mock(INetworkManagementService.class);
- mStatsService = mock(INetworkStatsService.class);
- mPolicyService = mock(INetworkPolicyManager.class);
-
- mService = new WrappedConnectivityService(
- mServiceContext, mNetManager, mStatsService, mPolicyService);
mService.systemReady();
mCm = new ConnectivityManager(getContext(), mService);
}
@@ -583,11 +718,11 @@ public class ConnectivityServiceTest extends AndroidTestCase {
// Test bringing up unvalidated cellular
mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
mCellNetworkAgent.connect(false);
- shortSleep();
+ mService.waitForIdle();
verifyActiveNetwork(TRANSPORT_WIFI);
// Test cellular disconnect.
mCellNetworkAgent.disconnect();
- shortSleep();
+ mService.waitForIdle();
verifyActiveNetwork(TRANSPORT_WIFI);
// Test bringing up validated cellular
mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
@@ -797,6 +932,11 @@ public class ConnectivityServiceTest extends AndroidTestCase {
LOST
}
+ /**
+ * Utility NetworkCallback for testing. The caller must explicitly test for all the callbacks
+ * this class receives, by calling expectCallback() exactly once each time a callback is
+ * received. assertNoCallback may be called at any time.
+ */
private class TestNetworkCallback extends NetworkCallback {
private final ConditionVariable mConditionVariable = new ConditionVariable();
private CallbackState mLastCallback = CallbackState.NONE;
@@ -819,14 +959,15 @@ public class ConnectivityServiceTest extends AndroidTestCase {
mConditionVariable.open();
}
- ConditionVariable getConditionVariable() {
+ void expectCallback(CallbackState state) {
+ waitFor(mConditionVariable);
+ assertEquals(state, mLastCallback);
mLastCallback = CallbackState.NONE;
mConditionVariable.close();
- return mConditionVariable;
}
- CallbackState getLastCallback() {
- return mLastCallback;
+ void assertNoCallback() {
+ assertEquals(CallbackState.NONE, mLastCallback);
}
}
@@ -842,98 +983,68 @@ public class ConnectivityServiceTest extends AndroidTestCase {
mCm.registerNetworkCallback(cellRequest, cellNetworkCallback);
// Test unvalidated networks
- ConditionVariable cellCv = cellNetworkCallback.getConditionVariable();
- ConditionVariable wifiCv = wifiNetworkCallback.getConditionVariable();
ConditionVariable cv = waitForConnectivityBroadcasts(1);
mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
mCellNetworkAgent.connect(false);
- waitFor(cellCv);
- assertEquals(CallbackState.AVAILABLE, cellNetworkCallback.getLastCallback());
- assertEquals(CallbackState.NONE, wifiNetworkCallback.getLastCallback());
+ cellNetworkCallback.expectCallback(CallbackState.AVAILABLE);
+ wifiNetworkCallback.assertNoCallback();
assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork());
waitFor(cv);
- cellCv = cellNetworkCallback.getConditionVariable();
- wifiCv = wifiNetworkCallback.getConditionVariable();
// This should not trigger spurious onAvailable() callbacks, b/21762680.
mCellNetworkAgent.adjustScore(-1);
- shortSleep();
- assertEquals(CallbackState.NONE, wifiNetworkCallback.getLastCallback());
- assertEquals(CallbackState.NONE, cellNetworkCallback.getLastCallback());
+ mService.waitForIdle();
+ wifiNetworkCallback.assertNoCallback();
+ cellNetworkCallback.assertNoCallback();
assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork());
- cellCv = cellNetworkCallback.getConditionVariable();
- wifiCv = wifiNetworkCallback.getConditionVariable();
cv = waitForConnectivityBroadcasts(2);
mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
mWiFiNetworkAgent.connect(false);
- waitFor(wifiCv);
- assertEquals(CallbackState.AVAILABLE, wifiNetworkCallback.getLastCallback());
- assertEquals(CallbackState.NONE, cellNetworkCallback.getLastCallback());
+ wifiNetworkCallback.expectCallback(CallbackState.AVAILABLE);
+ cellNetworkCallback.assertNoCallback();
assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
waitFor(cv);
- cellCv = cellNetworkCallback.getConditionVariable();
- wifiCv = wifiNetworkCallback.getConditionVariable();
cv = waitForConnectivityBroadcasts(2);
mWiFiNetworkAgent.disconnect();
- waitFor(wifiCv);
- assertEquals(CallbackState.LOST, wifiNetworkCallback.getLastCallback());
- assertEquals(CallbackState.NONE, cellNetworkCallback.getLastCallback());
+ wifiNetworkCallback.expectCallback(CallbackState.LOST);
+ cellNetworkCallback.assertNoCallback();
waitFor(cv);
- cellCv = cellNetworkCallback.getConditionVariable();
- wifiCv = wifiNetworkCallback.getConditionVariable();
cv = waitForConnectivityBroadcasts(1);
mCellNetworkAgent.disconnect();
- waitFor(cellCv);
- assertEquals(CallbackState.LOST, cellNetworkCallback.getLastCallback());
- assertEquals(CallbackState.NONE, wifiNetworkCallback.getLastCallback());
+ cellNetworkCallback.expectCallback(CallbackState.LOST);
+ wifiNetworkCallback.assertNoCallback();
waitFor(cv);
// Test validated networks
-
- cellCv = cellNetworkCallback.getConditionVariable();
- wifiCv = wifiNetworkCallback.getConditionVariable();
mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
mCellNetworkAgent.connect(true);
- waitFor(cellCv);
- assertEquals(CallbackState.AVAILABLE, cellNetworkCallback.getLastCallback());
- assertEquals(CallbackState.NONE, wifiNetworkCallback.getLastCallback());
+ cellNetworkCallback.expectCallback(CallbackState.AVAILABLE);
+ wifiNetworkCallback.assertNoCallback();
assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork());
- cellCv = cellNetworkCallback.getConditionVariable();
- wifiCv = wifiNetworkCallback.getConditionVariable();
// This should not trigger spurious onAvailable() callbacks, b/21762680.
mCellNetworkAgent.adjustScore(-1);
- shortSleep();
- assertEquals(CallbackState.NONE, wifiNetworkCallback.getLastCallback());
- assertEquals(CallbackState.NONE, cellNetworkCallback.getLastCallback());
+ mService.waitForIdle();
+ wifiNetworkCallback.assertNoCallback();
+ cellNetworkCallback.assertNoCallback();
assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork());
- cellCv = cellNetworkCallback.getConditionVariable();
- wifiCv = wifiNetworkCallback.getConditionVariable();
mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
mWiFiNetworkAgent.connect(true);
- waitFor(wifiCv);
- assertEquals(CallbackState.AVAILABLE, wifiNetworkCallback.getLastCallback());
- waitFor(cellCv);
- assertEquals(CallbackState.LOSING, cellNetworkCallback.getLastCallback());
+ wifiNetworkCallback.expectCallback(CallbackState.AVAILABLE);
+ cellNetworkCallback.expectCallback(CallbackState.LOSING);
assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
- cellCv = cellNetworkCallback.getConditionVariable();
- wifiCv = wifiNetworkCallback.getConditionVariable();
mWiFiNetworkAgent.disconnect();
- waitFor(wifiCv);
- assertEquals(CallbackState.LOST, wifiNetworkCallback.getLastCallback());
- assertEquals(CallbackState.NONE, cellNetworkCallback.getLastCallback());
+ wifiNetworkCallback.expectCallback(CallbackState.LOST);
+ cellNetworkCallback.assertNoCallback();
- cellCv = cellNetworkCallback.getConditionVariable();
- wifiCv = wifiNetworkCallback.getConditionVariable();
mCellNetworkAgent.disconnect();
- waitFor(cellCv);
- assertEquals(CallbackState.LOST, cellNetworkCallback.getLastCallback());
- assertEquals(CallbackState.NONE, wifiNetworkCallback.getLastCallback());
+ cellNetworkCallback.expectCallback(CallbackState.LOST);
+ wifiNetworkCallback.assertNoCallback();
}
private void tryNetworkFactoryRequests(int capability) throws Exception {
@@ -957,18 +1068,21 @@ public class ConnectivityServiceTest extends AndroidTestCase {
mServiceContext, "testFactory", filter);
testFactory.setScoreFilter(40);
ConditionVariable cv = testFactory.getNetworkStartedCV();
+ testFactory.expectAddRequests(1);
testFactory.register();
+ testFactory.waitForNetworkRequests(1);
int expectedRequestCount = 1;
NetworkCallback networkCallback = null;
// For non-INTERNET capabilities we cannot rely on the default request being present, so
// add one.
if (capability != NET_CAPABILITY_INTERNET) {
- testFactory.waitForNetworkRequests(1);
assertFalse(testFactory.getMyStartRequested());
NetworkRequest request = new NetworkRequest.Builder().addCapability(capability).build();
networkCallback = new NetworkCallback();
+ testFactory.expectAddRequests(1);
mCm.requestNetwork(request, networkCallback);
expectedRequestCount++;
+ testFactory.waitForNetworkRequests(expectedRequestCount);
}
waitFor(cv);
assertEquals(expectedRequestCount, testFactory.getMyRequestCount());
@@ -981,13 +1095,20 @@ public class ConnectivityServiceTest extends AndroidTestCase {
// unvalidated penalty.
testAgent.adjustScore(40);
cv = testFactory.getNetworkStoppedCV();
+
+ // When testAgent connects, ConnectivityService will re-send us all current requests with
+ // the new score. There are expectedRequestCount such requests, and we must wait for all of
+ // them.
+ testFactory.expectAddRequests(expectedRequestCount);
testAgent.connect(false);
testAgent.addCapability(capability);
waitFor(cv);
- assertEquals(expectedRequestCount, testFactory.getMyRequestCount());
+ testFactory.waitForNetworkRequests(expectedRequestCount);
assertFalse(testFactory.getMyStartRequested());
// Bring in a bunch of requests.
+ testFactory.expectAddRequests(10);
+ assertEquals(expectedRequestCount, testFactory.getMyRequestCount());
ConnectivityManager.NetworkCallback[] networkCallbacks =
new ConnectivityManager.NetworkCallback[10];
for (int i = 0; i< networkCallbacks.length; i++) {
@@ -1000,6 +1121,7 @@ public class ConnectivityServiceTest extends AndroidTestCase {
assertFalse(testFactory.getMyStartRequested());
// Remove the requests.
+ testFactory.expectRemoveRequests(10);
for (int i = 0; i < networkCallbacks.length; i++) {
mCm.unregisterNetworkCallback(networkCallbacks[i]);
}
@@ -1088,10 +1210,8 @@ public class ConnectivityServiceTest extends AndroidTestCase {
// Test bringing up unvalidated cellular with MMS
mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
mCellNetworkAgent.addCapability(NET_CAPABILITY_MMS);
- cv = networkCallback.getConditionVariable();
mCellNetworkAgent.connectWithoutInternet();
- waitFor(cv);
- assertEquals(CallbackState.AVAILABLE, networkCallback.getLastCallback());
+ networkCallback.expectCallback(CallbackState.AVAILABLE);
verifyActiveNetwork(TRANSPORT_WIFI);
// Test releasing NetworkRequest disconnects cellular with MMS
cv = mCellNetworkAgent.getDisconnectedCV();
@@ -1114,12 +1234,10 @@ public class ConnectivityServiceTest extends AndroidTestCase {
final TestNetworkCallback networkCallback = new TestNetworkCallback();
mCm.requestNetwork(builder.build(), networkCallback);
// Test bringing up MMS cellular network
- cv = networkCallback.getConditionVariable();
MockNetworkAgent mmsNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
mmsNetworkAgent.addCapability(NET_CAPABILITY_MMS);
mmsNetworkAgent.connectWithoutInternet();
- waitFor(cv);
- assertEquals(CallbackState.AVAILABLE, networkCallback.getLastCallback());
+ networkCallback.expectCallback(CallbackState.AVAILABLE);
verifyActiveNetwork(TRANSPORT_CELLULAR);
// Test releasing MMS NetworkRequest does not disconnect main cellular NetworkAgent
cv = mmsNetworkAgent.getDisconnectedCV();
@@ -1139,133 +1257,245 @@ public class ConnectivityServiceTest extends AndroidTestCase {
final NetworkRequest validatedRequest = new NetworkRequest.Builder()
.addCapability(NET_CAPABILITY_VALIDATED).build();
mCm.registerNetworkCallback(validatedRequest, validatedCallback);
- ConditionVariable validatedCv = validatedCallback.getConditionVariable();
// Bring up a network with a captive portal.
// Expect onAvailable callback of listen for NET_CAPABILITY_CAPTIVE_PORTAL.
- ConditionVariable cv = captivePortalCallback.getConditionVariable();
mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
mWiFiNetworkAgent.connectWithCaptivePortal();
- waitFor(cv);
- assertEquals(CallbackState.AVAILABLE, captivePortalCallback.getLastCallback());
+ captivePortalCallback.expectCallback(CallbackState.AVAILABLE);
// Take down network.
// Expect onLost callback.
- cv = captivePortalCallback.getConditionVariable();
mWiFiNetworkAgent.disconnect();
- waitFor(cv);
- assertEquals(CallbackState.LOST, captivePortalCallback.getLastCallback());
+ captivePortalCallback.expectCallback(CallbackState.LOST);
// Bring up a network with a captive portal.
// Expect onAvailable callback of listen for NET_CAPABILITY_CAPTIVE_PORTAL.
- cv = captivePortalCallback.getConditionVariable();
mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
mWiFiNetworkAgent.connectWithCaptivePortal();
- waitFor(cv);
- assertEquals(CallbackState.AVAILABLE, captivePortalCallback.getLastCallback());
+ captivePortalCallback.expectCallback(CallbackState.AVAILABLE);
// Make captive portal disappear then revalidate.
// Expect onLost callback because network no longer provides NET_CAPABILITY_CAPTIVE_PORTAL.
- cv = captivePortalCallback.getConditionVariable();
mWiFiNetworkAgent.getWrappedNetworkMonitor().gen204ProbeResult = 204;
mCm.reportNetworkConnectivity(mWiFiNetworkAgent.getNetwork(), true);
- waitFor(cv);
- assertEquals(CallbackState.LOST, captivePortalCallback.getLastCallback());
+ captivePortalCallback.expectCallback(CallbackState.LOST);
// Expect NET_CAPABILITY_VALIDATED onAvailable callback.
- waitFor(validatedCv);
- assertEquals(CallbackState.AVAILABLE, validatedCallback.getLastCallback());
+ validatedCallback.expectCallback(CallbackState.AVAILABLE);
// Break network connectivity.
// Expect NET_CAPABILITY_VALIDATED onLost callback.
- validatedCv = validatedCallback.getConditionVariable();
mWiFiNetworkAgent.getWrappedNetworkMonitor().gen204ProbeResult = 500;
mCm.reportNetworkConnectivity(mWiFiNetworkAgent.getNetwork(), false);
- waitFor(validatedCv);
- assertEquals(CallbackState.LOST, validatedCallback.getLastCallback());
+ validatedCallback.expectCallback(CallbackState.LOST);
+ }
+
+ private static class TestKeepaliveCallback extends PacketKeepaliveCallback {
+
+ public static enum CallbackType { ON_STARTED, ON_STOPPED, ON_ERROR };
+
+ private class CallbackValue {
+ public CallbackType callbackType;
+ public int error;
+
+ public CallbackValue(CallbackType type) {
+ this.callbackType = type;
+ this.error = PacketKeepalive.SUCCESS;
+ assertTrue("onError callback must have error", type != CallbackType.ON_ERROR);
+ }
+
+ public CallbackValue(CallbackType type, int error) {
+ this.callbackType = type;
+ this.error = error;
+ assertEquals("error can only be set for onError", type, CallbackType.ON_ERROR);
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ return o instanceof CallbackValue &&
+ this.callbackType == ((CallbackValue) o).callbackType &&
+ this.error == ((CallbackValue) o).error;
+ }
+
+ @Override
+ public String toString() {
+ return String.format("%s(%s, %d)", getClass().getSimpleName(), callbackType, error);
+ }
+ }
+
+ private LinkedBlockingQueue<CallbackValue> mCallbacks = new LinkedBlockingQueue<>();
+
+ @Override
+ public void onStarted() {
+ mCallbacks.add(new CallbackValue(CallbackType.ON_STARTED));
+ }
+
+ @Override
+ public void onStopped() {
+ mCallbacks.add(new CallbackValue(CallbackType.ON_STOPPED));
+ }
+
+ @Override
+ public void onError(int error) {
+ mCallbacks.add(new CallbackValue(CallbackType.ON_ERROR, error));
+ }
+
+ private void expectCallback(CallbackValue callbackValue) {
+ try {
+ assertEquals(
+ callbackValue,
+ mCallbacks.poll(TIMEOUT_MS, TimeUnit.MILLISECONDS));
+ } catch (InterruptedException e) {
+ fail(callbackValue.callbackType + " callback not seen after " + TIMEOUT_MS + " ms");
+ }
+ }
+
+ public void expectStarted() {
+ expectCallback(new CallbackValue(CallbackType.ON_STARTED));
+ }
+
+ public void expectStopped() {
+ expectCallback(new CallbackValue(CallbackType.ON_STOPPED));
+ }
+
+ public void expectError(int error) {
+ expectCallback(new CallbackValue(CallbackType.ON_ERROR, error));
+ }
}
-// @Override
-// public void tearDown() throws Exception {
-// super.tearDown();
-// }
-//
-// public void testMobileConnectedAddedRoutes() throws Exception {
-// Future<?> nextConnBroadcast;
-//
-// // bring up mobile network
-// mMobile.info.setDetailedState(DetailedState.CONNECTED, null, null);
-// mMobile.link.setInterfaceName(MOBILE_IFACE);
-// mMobile.link.addRoute(MOBILE_ROUTE_V4);
-// mMobile.link.addRoute(MOBILE_ROUTE_V6);
-// mMobile.doReturnDefaults();
-//
-// cv = waitForConnectivityBroadcasts(1);
-// mTrackerHandler.obtainMessage(EVENT_STATE_CHANGED, mMobile.info).sendToTarget();
-// waitFor(cv);
-//
-// // verify that both routes were added
-// int mobileNetId = mMobile.tracker.getNetwork().netId;
-// verify(mNetManager).addRoute(eq(mobileNetId), eq(MOBILE_ROUTE_V4));
-// verify(mNetManager).addRoute(eq(mobileNetId), eq(MOBILE_ROUTE_V6));
-// }
-//
-// public void testMobileWifiHandoff() throws Exception {
-// Future<?> nextConnBroadcast;
-//
-// // bring up mobile network
-// mMobile.info.setDetailedState(DetailedState.CONNECTED, null, null);
-// mMobile.link.setInterfaceName(MOBILE_IFACE);
-// mMobile.link.addRoute(MOBILE_ROUTE_V4);
-// mMobile.link.addRoute(MOBILE_ROUTE_V6);
-// mMobile.doReturnDefaults();
-//
-// cv = waitForConnectivityBroadcasts(1);
-// mTrackerHandler.obtainMessage(EVENT_STATE_CHANGED, mMobile.info).sendToTarget();
-// waitFor(cv);
-//
-// reset(mNetManager);
-//
-// // now bring up wifi network
-// mWifi.info.setDetailedState(DetailedState.CONNECTED, null, null);
-// mWifi.link.setInterfaceName(WIFI_IFACE);
-// mWifi.link.addRoute(WIFI_ROUTE_V4);
-// mWifi.link.addRoute(WIFI_ROUTE_V6);
-// mWifi.doReturnDefaults();
-//
-// // expect that mobile will be torn down
-// doReturn(true).when(mMobile.tracker).teardown();
-//
-// cv = waitForConnectivityBroadcasts(1);
-// mTrackerHandler.obtainMessage(EVENT_STATE_CHANGED, mWifi.info).sendToTarget();
-// waitFor(cv);
-//
-// // verify that wifi routes added, and teardown requested
-// int wifiNetId = mWifi.tracker.getNetwork().netId;
-// verify(mNetManager).addRoute(eq(wifiNetId), eq(WIFI_ROUTE_V4));
-// verify(mNetManager).addRoute(eq(wifiNetId), eq(WIFI_ROUTE_V6));
-// verify(mMobile.tracker).teardown();
-//
-// int mobileNetId = mMobile.tracker.getNetwork().netId;
-//
-// reset(mNetManager, mMobile.tracker);
-//
-// // tear down mobile network, as requested
-// mMobile.info.setDetailedState(DetailedState.DISCONNECTED, null, null);
-// mMobile.link.clear();
-// mMobile.doReturnDefaults();
-//
-// cv = waitForConnectivityBroadcasts(1);
-// mTrackerHandler.obtainMessage(EVENT_STATE_CHANGED, mMobile.info).sendToTarget();
-// waitFor(cv);
-//
-// verify(mNetManager).removeRoute(eq(mobileNetId), eq(MOBILE_ROUTE_V4));
-// verify(mNetManager).removeRoute(eq(mobileNetId), eq(MOBILE_ROUTE_V6));
-//
-// }
-
- private static InetAddress parse(String addr) {
- return InetAddress.parseNumericAddress(addr);
+ private Network connectKeepaliveNetwork(LinkProperties lp) {
+ // Ensure the network is disconnected before we do anything.
+ if (mWiFiNetworkAgent != null) {
+ assertNull(mCm.getNetworkCapabilities(mWiFiNetworkAgent.getNetwork()));
+ }
+
+ mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+ ConditionVariable cv = waitForConnectivityBroadcasts(1);
+ mWiFiNetworkAgent.connect(true);
+ waitFor(cv);
+ verifyActiveNetwork(TRANSPORT_WIFI);
+ mWiFiNetworkAgent.sendLinkProperties(lp);
+ mService.waitForIdle();
+ return mWiFiNetworkAgent.getNetwork();
}
+ public void testPacketKeepalives() throws Exception {
+ InetAddress myIPv4 = InetAddress.getByName("192.0.2.129");
+ InetAddress notMyIPv4 = InetAddress.getByName("192.0.2.35");
+ InetAddress myIPv6 = InetAddress.getByName("2001:db8::1");
+ InetAddress dstIPv4 = InetAddress.getByName("8.8.8.8");
+ InetAddress dstIPv6 = InetAddress.getByName("2001:4860:4860::8888");
+
+ LinkProperties lp = new LinkProperties();
+ lp.setInterfaceName("wlan12");
+ lp.addLinkAddress(new LinkAddress(myIPv6, 64));
+ lp.addLinkAddress(new LinkAddress(myIPv4, 25));
+ lp.addRoute(new RouteInfo(InetAddress.getByName("fe80::1234")));
+ lp.addRoute(new RouteInfo(InetAddress.getByName("192.0.2.254")));
+
+ Network notMyNet = new Network(61234);
+ Network myNet = connectKeepaliveNetwork(lp);
+
+ TestKeepaliveCallback callback = new TestKeepaliveCallback();
+ PacketKeepalive ka;
+
+ // Attempt to start keepalives with invalid parameters and check for errors.
+ ka = mCm.startNattKeepalive(notMyNet, 25, callback, myIPv4, 1234, dstIPv4);
+ callback.expectError(PacketKeepalive.ERROR_INVALID_NETWORK);
+
+ ka = mCm.startNattKeepalive(myNet, 19, callback, notMyIPv4, 1234, dstIPv4);
+ callback.expectError(PacketKeepalive.ERROR_INVALID_INTERVAL);
+
+ ka = mCm.startNattKeepalive(myNet, 25, callback, myIPv4, 1234, dstIPv6);
+ callback.expectError(PacketKeepalive.ERROR_INVALID_IP_ADDRESS);
+
+ ka = mCm.startNattKeepalive(myNet, 25, callback, myIPv6, 1234, dstIPv4);
+ callback.expectError(PacketKeepalive.ERROR_INVALID_IP_ADDRESS);
+
+ ka = mCm.startNattKeepalive(myNet, 25, callback, myIPv6, 1234, dstIPv6);
+ callback.expectError(PacketKeepalive.ERROR_INVALID_IP_ADDRESS); // NAT-T is IPv4-only.
+
+ ka = mCm.startNattKeepalive(myNet, 25, callback, myIPv4, 123456, dstIPv4);
+ callback.expectError(PacketKeepalive.ERROR_INVALID_PORT);
+
+ ka = mCm.startNattKeepalive(myNet, 25, callback, myIPv4, 123456, dstIPv4);
+ callback.expectError(PacketKeepalive.ERROR_INVALID_PORT);
+
+ ka = mCm.startNattKeepalive(myNet, 25, callback, myIPv4, 12345, dstIPv4);
+ callback.expectError(PacketKeepalive.ERROR_HARDWARE_UNSUPPORTED);
+
+ ka = mCm.startNattKeepalive(myNet, 25, callback, myIPv4, 12345, dstIPv4);
+ callback.expectError(PacketKeepalive.ERROR_HARDWARE_UNSUPPORTED);
+
+ // Check that a started keepalive can be stopped.
+ mWiFiNetworkAgent.setStartKeepaliveError(PacketKeepalive.SUCCESS);
+ ka = mCm.startNattKeepalive(myNet, 25, callback, myIPv4, 12345, dstIPv4);
+ callback.expectStarted();
+ mWiFiNetworkAgent.setStopKeepaliveError(PacketKeepalive.SUCCESS);
+ ka.stop();
+ callback.expectStopped();
+
+ // Check that deleting the IP address stops the keepalive.
+ LinkProperties bogusLp = new LinkProperties(lp);
+ ka = mCm.startNattKeepalive(myNet, 25, callback, myIPv4, 12345, dstIPv4);
+ callback.expectStarted();
+ bogusLp.removeLinkAddress(new LinkAddress(myIPv4, 25));
+ bogusLp.addLinkAddress(new LinkAddress(notMyIPv4, 25));
+ mWiFiNetworkAgent.sendLinkProperties(bogusLp);
+ callback.expectError(PacketKeepalive.ERROR_INVALID_IP_ADDRESS);
+ mWiFiNetworkAgent.sendLinkProperties(lp);
+
+ // Check that a started keepalive is stopped correctly when the network disconnects.
+ ka = mCm.startNattKeepalive(myNet, 25, callback, myIPv4, 12345, dstIPv4);
+ callback.expectStarted();
+ mWiFiNetworkAgent.disconnect();
+ callback.expectError(PacketKeepalive.ERROR_INVALID_NETWORK);
+
+ // ... and that stopping it after that has no adverse effects.
+ assertNull(mCm.getNetworkCapabilities(myNet));
+ ka.stop();
+
+ // Reconnect.
+ myNet = connectKeepaliveNetwork(lp);
+ mWiFiNetworkAgent.setStartKeepaliveError(PacketKeepalive.SUCCESS);
+
+ // Check things work as expected when the keepalive is stopped and the network disconnects.
+ ka = mCm.startNattKeepalive(myNet, 25, callback, myIPv4, 12345, dstIPv4);
+ callback.expectStarted();
+ ka.stop();
+ mWiFiNetworkAgent.disconnect();
+ mService.waitForIdle();
+ callback.expectStopped();
+
+ // Reconnect.
+ myNet = connectKeepaliveNetwork(lp);
+ mWiFiNetworkAgent.setStartKeepaliveError(PacketKeepalive.SUCCESS);
+
+ // Check that keepalive slots start from 1 and increment. The first one gets slot 1.
+ mWiFiNetworkAgent.setExpectedKeepaliveSlot(1);
+ ka = mCm.startNattKeepalive(myNet, 25, callback, myIPv4, 12345, dstIPv4);
+ callback.expectStarted();
+
+ // The second one gets slot 2.
+ mWiFiNetworkAgent.setExpectedKeepaliveSlot(2);
+ TestKeepaliveCallback callback2 = new TestKeepaliveCallback();
+ PacketKeepalive ka2 = mCm.startNattKeepalive(myNet, 25, callback2, myIPv4, 6789, dstIPv4);
+ callback2.expectStarted();
+
+ // Now stop the first one and create a third. This also gets slot 1.
+ ka.stop();
+ callback.expectStopped();
+
+ mWiFiNetworkAgent.setExpectedKeepaliveSlot(1);
+ TestKeepaliveCallback callback3 = new TestKeepaliveCallback();
+ PacketKeepalive ka3 = mCm.startNattKeepalive(myNet, 25, callback3, myIPv4, 9876, dstIPv4);
+ callback3.expectStarted();
+
+ ka2.stop();
+ callback2.expectStopped();
+
+ ka3.stop();
+ callback3.expectStopped();
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/accounts/AccountManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/accounts/AccountManagerServiceTest.java
index 0f20dde..f9aa124 100644
--- a/services/tests/servicestests/src/com/android/server/accounts/AccountManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/accounts/AccountManagerServiceTest.java
@@ -82,7 +82,7 @@ public class AccountManagerServiceTest extends AndroidTestCase {
mAms.addAccountExplicitly(a31, "p31", null);
mAms.addAccountExplicitly(a32, "p32", null);
- Account[] accounts = mAms.getAccounts(null);
+ Account[] accounts = mAms.getAccounts(null, mContext.getOpPackageName());
Arrays.sort(accounts, new AccountSorter());
assertEquals(6, accounts.length);
assertEquals(a11, accounts[0]);
@@ -92,7 +92,7 @@ public class AccountManagerServiceTest extends AndroidTestCase {
assertEquals(a22, accounts[4]);
assertEquals(a32, accounts[5]);
- accounts = mAms.getAccounts("type1" );
+ accounts = mAms.getAccounts("type1", mContext.getOpPackageName());
Arrays.sort(accounts, new AccountSorter());
assertEquals(3, accounts.length);
assertEquals(a11, accounts[0]);
@@ -101,7 +101,7 @@ public class AccountManagerServiceTest extends AndroidTestCase {
mAms.removeAccountInternal(a21);
- accounts = mAms.getAccounts("type1" );
+ accounts = mAms.getAccounts("type1", mContext.getOpPackageName());
Arrays.sort(accounts, new AccountSorter());
assertEquals(2, accounts.length);
assertEquals(a11, accounts[0]);
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index bd89792..e675c6d 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -267,6 +267,16 @@ public class CarrierConfigManager {
"carrier_instant_lettering_available_bool";
/**
+ * When IMS instant lettering is available for a carrier (see
+ * {@link #KEY_CARRIER_INSTANT_LETTERING_AVAILABLE_BOOL}), determines the list of characters
+ * which may not be contained in messages. Should be specified as a regular expression suitable
+ * for use with {@link String#matches(String)}.
+ * @hide
+ */
+ public static final String KEY_CARRIER_INSTANT_LETTERING_INVALID_CHARS_STRING =
+ "carrier_instant_lettering_invalid_chars_string";
+
+ /**
* If Voice Radio Technology is RIL_RADIO_TECHNOLOGY_LTE:14 or RIL_RADIO_TECHNOLOGY_UNKNOWN:0
* this is the value that should be used instead. A configuration value of
* RIL_RADIO_TECHNOLOGY_UNKNOWN:0 means there is no replacement value and that the default
@@ -371,6 +381,18 @@ public class CarrierConfigManager {
public static final String KEY_EDITABLE_ENHANCED_4G_LTE_BOOL = "editable_enhanced_4g_lte_bool";
/**
+ * Determine whether IMS apn can be shown.
+ * @hide
+ */
+ public static final String KEY_HIDE_IMS_APN_BOOL = "hide_ims_apn_bool";
+
+ /**
+ * Determine whether preferred network type can be shown.
+ * @hide
+ */
+ public static final String KEY_HIDE_PREFERRED_NETWORK_TYPE_BOOL = "hide_preferred_network_type_bool";
+
+ /**
* If this is true, the SIM card (through Customer Service Profile EF file) will be able to
* prevent manual operator selection. If false, this SIM setting will be ignored and manual
* operator selection will always be available. See CPHS4_2.WW6, CPHS B.4.7.1 for more
@@ -440,6 +462,7 @@ public class CarrierConfigManager {
sDefaults.putBoolean(KEY_CARRIER_VOLTE_TTY_SUPPORTED_BOOL, true);
sDefaults.putBoolean(KEY_CARRIER_ALLOW_TURNOFF_IMS_BOOL, true);
sDefaults.putBoolean(KEY_CARRIER_INSTANT_LETTERING_AVAILABLE_BOOL, false);
+ sDefaults.putString(KEY_CARRIER_INSTANT_LETTERING_INVALID_CHARS_STRING, "");
sDefaults.putBoolean(KEY_DISABLE_CDMA_ACTIVATION_CODE_BOOL, false);
sDefaults.putBoolean(KEY_DTMF_TYPE_ENABLED_BOOL, false);
sDefaults.putBoolean(KEY_ENABLE_DIALER_KEY_VIBRATION_BOOL, true);
@@ -481,6 +504,8 @@ public class CarrierConfigManager {
sDefaults.putInt(KEY_IMS_DTMF_TONE_DELAY_INT, 0);
sDefaults.putBoolean(KEY_SUPPORT_CONFERENCE_CALL_BOOL, true);
sDefaults.putBoolean(KEY_EDITABLE_ENHANCED_4G_LTE_BOOL, true);
+ sDefaults.putBoolean(KEY_HIDE_IMS_APN_BOOL, false);
+ sDefaults.putBoolean(KEY_HIDE_PREFERRED_NETWORK_TYPE_BOOL, false);
// MMS defaults
sDefaults.putBoolean(KEY_MMS_ALIAS_ENABLED_BOOL, false);