Merge "DO NOT MERGE Add 'bluetooth' user to the 'system' group." into cw-e-dev
diff --git a/Android.mk b/Android.mk
index 6f5f8f9..41190be 100644
--- a/Android.mk
+++ b/Android.mk
@@ -160,6 +160,7 @@
core/java/android/hardware/fingerprint/IFingerprintDaemon.aidl \
core/java/android/hardware/fingerprint/IFingerprintDaemonCallback.aidl \
core/java/android/hardware/fingerprint/IFingerprintService.aidl \
+ core/java/android/hardware/fingerprint/IFingerprintServiceLockoutResetCallback.aidl \
core/java/android/hardware/fingerprint/IFingerprintServiceReceiver.aidl \
core/java/android/hardware/hdmi/IHdmiControlCallback.aidl \
core/java/android/hardware/hdmi/IHdmiControlService.aidl \
@@ -172,6 +173,7 @@
core/java/android/hardware/hdmi/IHdmiVendorCommandListener.aidl \
core/java/android/hardware/input/IInputManager.aidl \
core/java/android/hardware/input/IInputDevicesChangedListener.aidl \
+ core/java/android/hardware/input/ITabletModeChangedListener.aidl \
core/java/android/hardware/location/IActivityRecognitionHardware.aidl \
core/java/android/hardware/location/IActivityRecognitionHardwareClient.aidl \
core/java/android/hardware/location/IActivityRecognitionHardwareSink.aidl \
diff --git a/core/java/android/app/FragmentManager.java b/core/java/android/app/FragmentManager.java
index 3b026d2..132ffef 100644
--- a/core/java/android/app/FragmentManager.java
+++ b/core/java/android/app/FragmentManager.java
@@ -2196,6 +2196,7 @@
fragment.mTag = tag;
fragment.mInLayout = true;
fragment.mFragmentManager = this;
+ fragment.mHost = mHost;
fragment.onInflate(mHost.getContext(), attrs, fragment.mSavedFragmentState);
addFragment(fragment, true);
} else if (fragment.mInLayout) {
diff --git a/core/java/android/hardware/fingerprint/FingerprintManager.java b/core/java/android/hardware/fingerprint/FingerprintManager.java
index 7cff11b..1f23c0a 100644
--- a/core/java/android/hardware/fingerprint/FingerprintManager.java
+++ b/core/java/android/hardware/fingerprint/FingerprintManager.java
@@ -392,6 +392,18 @@
};
/**
+ * @hide
+ */
+ public static abstract class LockoutResetCallback {
+
+ /**
+ * Called when lockout period expired and clients are allowed to listen for fingerprint
+ * again.
+ */
+ public void onLockoutReset() { }
+ };
+
+ /**
* Request authentication of a crypto object. This call warms up the fingerprint hardware
* and starts scanning for a fingerprint. It terminates when
* {@link AuthenticationCallback#onAuthenticationError(int, CharSequence)} or
@@ -680,10 +692,37 @@
try {
mService.resetTimeout(token);
} catch (RemoteException e) {
- Log.v(TAG, "Remote exception in getAuthenticatorId(): ", e);
+ Log.v(TAG, "Remote exception in resetTimeout(): ", e);
}
} else {
- Log.w(TAG, "getAuthenticatorId(): Service not connected!");
+ Log.w(TAG, "resetTimeout(): Service not connected!");
+ }
+ }
+
+ /**
+ * @hide
+ */
+ public void addLockoutResetCallback(final LockoutResetCallback callback) {
+ if (mService != null) {
+ try {
+ mService.addLockoutResetCallback(
+ new IFingerprintServiceLockoutResetCallback.Stub() {
+
+ @Override
+ public void onLockoutReset(long deviceId) throws RemoteException {
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ callback.onLockoutReset();
+ }
+ });
+ }
+ });
+ } catch (RemoteException e) {
+ Log.v(TAG, "Remote exception in addLockoutResetCallback(): ", e);
+ }
+ } else {
+ Log.w(TAG, "addLockoutResetCallback(): Service not connected!");
}
}
diff --git a/core/java/android/hardware/fingerprint/IFingerprintService.aidl b/core/java/android/hardware/fingerprint/IFingerprintService.aidl
index 3356354..690a751 100644
--- a/core/java/android/hardware/fingerprint/IFingerprintService.aidl
+++ b/core/java/android/hardware/fingerprint/IFingerprintService.aidl
@@ -17,6 +17,7 @@
import android.os.Bundle;
import android.hardware.fingerprint.IFingerprintServiceReceiver;
+import android.hardware.fingerprint.IFingerprintServiceLockoutResetCallback;
import android.hardware.fingerprint.Fingerprint;
import java.util.List;
@@ -71,4 +72,7 @@
// Reset the timeout when user authenticates with strong auth (e.g. PIN, pattern or password)
void resetTimeout(in byte [] cryptoToken);
+
+ // Add a callback which gets notified when the fingerprint lockout period expired.
+ void addLockoutResetCallback(IFingerprintServiceLockoutResetCallback callback);
}
diff --git a/core/java/android/hardware/fingerprint/IFingerprintServiceLockoutResetCallback.aidl b/core/java/android/hardware/fingerprint/IFingerprintServiceLockoutResetCallback.aidl
new file mode 100644
index 0000000..c9a5d59
--- /dev/null
+++ b/core/java/android/hardware/fingerprint/IFingerprintServiceLockoutResetCallback.aidl
@@ -0,0 +1,28 @@
+/*
+ * 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.hardware.fingerprint;
+
+import android.hardware.fingerprint.Fingerprint;
+import android.os.Bundle;
+import android.os.UserHandle;
+
+/**
+ * Callback when lockout period expired and clients are allowed to authenticate again.
+ * @hide
+ */
+oneway interface IFingerprintServiceLockoutResetCallback {
+ void onLockoutReset(long deviceId);
+}
diff --git a/core/java/android/hardware/input/IInputManager.aidl b/core/java/android/hardware/input/IInputManager.aidl
index 465d142..c8b45c7 100644
--- a/core/java/android/hardware/input/IInputManager.aidl
+++ b/core/java/android/hardware/input/IInputManager.aidl
@@ -19,6 +19,7 @@
import android.hardware.input.InputDeviceIdentifier;
import android.hardware.input.KeyboardLayout;
import android.hardware.input.IInputDevicesChangedListener;
+import android.hardware.input.ITabletModeChangedListener;
import android.hardware.input.TouchCalibration;
import android.os.IBinder;
import android.view.InputDevice;
@@ -60,6 +61,9 @@
// Registers an input devices changed listener.
void registerInputDevicesChangedListener(IInputDevicesChangedListener listener);
+ // Registers a tablet mode change listener
+ void registerTabletModeChangedListener(ITabletModeChangedListener listener);
+
// Input device vibrator control.
void vibrate(int deviceId, in long[] pattern, int repeat, IBinder token);
void cancelVibrate(int deviceId, IBinder token);
diff --git a/core/java/android/hardware/input/ITabletModeChangedListener.aidl b/core/java/android/hardware/input/ITabletModeChangedListener.aidl
new file mode 100644
index 0000000..a8559a7
--- /dev/null
+++ b/core/java/android/hardware/input/ITabletModeChangedListener.aidl
@@ -0,0 +1,23 @@
+/*
+ * 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.hardware.input;
+
+/** @hide */
+interface ITabletModeChangedListener {
+ /* Called when the device enters or exits tablet mode. */
+ oneway void onTabletModeChanged(long whenNanos, boolean inTabletMode);
+}
diff --git a/core/java/android/hardware/input/InputManager.java b/core/java/android/hardware/input/InputManager.java
index 444f020..a754d6b 100644
--- a/core/java/android/hardware/input/InputManager.java
+++ b/core/java/android/hardware/input/InputManager.java
@@ -16,6 +16,7 @@
package android.hardware.input;
+import com.android.internal.os.SomeArgs;
import com.android.internal.util.ArrayUtils;
import android.annotation.SdkConstant;
@@ -29,6 +30,7 @@
import android.os.Message;
import android.os.RemoteException;
import android.os.ServiceManager;
+import android.os.SystemClock;
import android.os.Vibrator;
import android.provider.Settings;
import android.provider.Settings.SettingNotFoundException;
@@ -38,6 +40,7 @@
import android.view.InputEvent;
import java.util.ArrayList;
+import java.util.List;
/**
* Provides information about input devices and available key layouts.
@@ -67,6 +70,11 @@
private final ArrayList<InputDeviceListenerDelegate> mInputDeviceListeners =
new ArrayList<InputDeviceListenerDelegate>();
+ // Guarded by mTabletModeLock
+ private final Object mTabletModeLock = new Object();
+ private TabletModeChangedListener mTabletModeChangedListener;
+ private List<OnTabletModeChangedListenerDelegate> mOnTabletModeChangedListeners;
+
/**
* Broadcast Action: Query available keyboard layouts.
* <p>
@@ -331,6 +339,72 @@
}
/**
+ * Register a tablet mode changed listener.
+ *
+ * @param listener The listener to register.
+ * @param handler The handler on which the listener should be invoked, or null
+ * if the listener should be invoked on the calling thread's looper.
+ * @hide
+ */
+ public void registerOnTabletModeChangedListener(
+ OnTabletModeChangedListener listener, Handler handler) {
+ if (listener == null) {
+ throw new IllegalArgumentException("listener must not be null");
+ }
+ synchronized (mTabletModeLock) {
+ if (mOnTabletModeChangedListeners == null) {
+ initializeTabletModeListenerLocked();
+ }
+ int idx = findOnTabletModeChangedListenerLocked(listener);
+ if (idx < 0) {
+ OnTabletModeChangedListenerDelegate d =
+ new OnTabletModeChangedListenerDelegate(listener, handler);
+ mOnTabletModeChangedListeners.add(d);
+ }
+ }
+ }
+
+ /**
+ * Unregister a tablet mode changed listener.
+ *
+ * @param listener The listener to unregister.
+ * @hide
+ */
+ public void unregisterOnTabletModeChangedListener(OnTabletModeChangedListener listener) {
+ if (listener == null) {
+ throw new IllegalArgumentException("listener must not be null");
+ }
+ synchronized (mTabletModeLock) {
+ int idx = findOnTabletModeChangedListenerLocked(listener);
+ if (idx >= 0) {
+ OnTabletModeChangedListenerDelegate d = mOnTabletModeChangedListeners.remove(idx);
+ d.removeCallbacksAndMessages(null);
+ }
+ }
+ }
+
+ private void initializeTabletModeListenerLocked() {
+ final TabletModeChangedListener listener = new TabletModeChangedListener();
+ try {
+ mIm.registerTabletModeChangedListener(listener);
+ } catch (RemoteException ex) {
+ throw new RuntimeException("Could not register tablet mode changed listener", ex);
+ }
+ mTabletModeChangedListener = listener;
+ mOnTabletModeChangedListeners = new ArrayList<>();
+ }
+
+ private int findOnTabletModeChangedListenerLocked(OnTabletModeChangedListener listener) {
+ final int N = mOnTabletModeChangedListeners.size();
+ for (int i = 0; i < N; i++) {
+ if (mOnTabletModeChangedListeners.get(i).mListener == listener) {
+ return i;
+ }
+ }
+ return -1;
+ }
+
+ /**
* Gets information about all supported keyboard layouts.
* <p>
* The input manager consults the built-in keyboard layouts as well
@@ -769,6 +843,22 @@
return false;
}
+
+ private void onTabletModeChanged(long whenNanos, boolean inTabletMode) {
+ if (DEBUG) {
+ Log.d(TAG, "Received tablet mode changed: "
+ + "whenNanos=" + whenNanos + ", inTabletMode=" + inTabletMode);
+ }
+ synchronized (mTabletModeLock) {
+ final int N = mOnTabletModeChangedListeners.size();
+ for (int i = 0; i < N; i++) {
+ OnTabletModeChangedListenerDelegate listener =
+ mOnTabletModeChangedListeners.get(i);
+ listener.sendTabletModeChanged(whenNanos, inTabletMode);
+ }
+ }
+ }
+
/**
* Gets a vibrator service associated with an input device, assuming it has one.
* @return The vibrator, never null.
@@ -838,6 +928,57 @@
}
}
+ /** @hide */
+ public interface OnTabletModeChangedListener {
+ /**
+ * Called whenever the device goes into or comes out of tablet mode.
+ *
+ * @param whenNanos The time at which the device transitioned into or
+ * out of tablet mode. This is given in nanoseconds in the
+ * {@link SystemClock#uptimeMillis} time base.
+ */
+ void onTabletModeChanged(long whenNanos, boolean inTabletMode);
+ }
+
+ private final class TabletModeChangedListener extends ITabletModeChangedListener.Stub {
+ @Override
+ public void onTabletModeChanged(long whenNanos, boolean inTabletMode) {
+ InputManager.this.onTabletModeChanged(whenNanos, inTabletMode);
+ }
+ }
+
+ private static final class OnTabletModeChangedListenerDelegate extends Handler {
+ private static final int MSG_TABLET_MODE_CHANGED = 0;
+
+ public final OnTabletModeChangedListener mListener;
+
+ public OnTabletModeChangedListenerDelegate(
+ OnTabletModeChangedListener listener, Handler handler) {
+ super(handler != null ? handler.getLooper() : Looper.myLooper());
+ mListener = listener;
+ }
+
+ public void sendTabletModeChanged(long whenNanos, boolean inTabletMode) {
+ SomeArgs args = SomeArgs.obtain();
+ args.argi1 = (int) (whenNanos & 0xFFFFFFFF);
+ args.argi2 = (int) (whenNanos >> 32);
+ args.arg1 = (Boolean) inTabletMode;
+ obtainMessage(MSG_TABLET_MODE_CHANGED, args).sendToTarget();
+ }
+
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case MSG_TABLET_MODE_CHANGED:
+ SomeArgs args = (SomeArgs) msg.obj;
+ long whenNanos = (args.argi1 & 0xFFFFFFFFl) | ((long) args.argi2 << 32);
+ boolean inTabletMode = (boolean) args.arg1;
+ mListener.onTabletModeChanged(whenNanos, inTabletMode);
+ break;
+ }
+ }
+ }
+
private final class InputDeviceVibrator extends Vibrator {
private final int mDeviceId;
private final Binder mToken;
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index ec0cc6d..d4e6c82 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -100,6 +100,16 @@
public static final String CONNECTIVITY_ACTION = "android.net.conn.CONNECTIVITY_CHANGE";
/**
+ * A temporary hack until SUPL system can get off the legacy APIS.
+ * They do too many network requests and the long list of apps listening
+ * and waking due to the CONNECTIVITY_ACTION bcast makes it expensive.
+ * Use this bcast intent instead for SUPL requests.
+ * @hide
+ */
+ public static final String CONNECTIVITY_ACTION_SUPL =
+ "android.net.conn.CONNECTIVITY_CHANGE_SUPL";
+
+ /**
* The device has connected to a network that has presented a captive
* portal, which is blocking Internet connectivity. The user was presented
* with a notification that network sign in is required,
diff --git a/core/java/com/android/internal/view/FloatingActionMode.java b/core/java/com/android/internal/view/FloatingActionMode.java
index 9761661..44df0ce 100644
--- a/core/java/com/android/internal/view/FloatingActionMode.java
+++ b/core/java/com/android/internal/view/FloatingActionMode.java
@@ -76,6 +76,15 @@
mMenu = new MenuBuilder(context).setDefaultShowAsAction(
MenuItem.SHOW_AS_ACTION_IF_ROOM);
setType(ActionMode.TYPE_FLOATING);
+ mMenu.setCallback(new MenuBuilder.Callback() {
+ @Override
+ public void onMenuModeChange(MenuBuilder menu) {}
+
+ @Override
+ public boolean onMenuItemSelected(MenuBuilder menu, MenuItem item) {
+ return mCallback.onActionItemClicked(FloatingActionMode.this, item);
+ }
+ });
mContentRect = new Rect();
mContentRectOnScreen = new Rect();
mPreviousContentRectOnScreen = new Rect();
@@ -99,7 +108,7 @@
.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
@Override
public boolean onMenuItemClick(MenuItem item) {
- return mCallback.onActionItemClicked(FloatingActionMode.this, item);
+ return mMenu.performItemAction(item, 0);
}
});
mFloatingToolbarVisibilityHelper = new FloatingToolbarVisibilityHelper(mFloatingToolbar);
diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java
index d24b10b..4ac2958 100644
--- a/core/java/com/android/internal/widget/LockPatternUtils.java
+++ b/core/java/com/android/internal/widget/LockPatternUtils.java
@@ -232,7 +232,7 @@
public void reportFailedPasswordAttempt(int userId) {
getDevicePolicyManager().reportFailedPasswordAttempt(userId);
getTrustManager().reportUnlockAttempt(false /* authenticated */, userId);
- requireCredentialEntry(userId);
+ requireStrongAuth(StrongAuthTracker.SOME_AUTH_REQUIRED_AFTER_WRONG_CREDENTIAL, userId);
}
public void reportSuccessfulPasswordAttempt(int userId) {
@@ -1174,7 +1174,7 @@
* @param userId either an explicit user id or {@link android.os.UserHandle#USER_ALL}
*/
public void requireCredentialEntry(int userId) {
- requireStrongAuth(StrongAuthTracker.SOME_AUTH_REQUIRED_AFTER_USER_REQUEST, userId);
+ requireStrongAuth(StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_USER_REQUEST, userId);
}
/**
@@ -1251,7 +1251,7 @@
value = { STRONG_AUTH_NOT_REQUIRED,
STRONG_AUTH_REQUIRED_AFTER_BOOT,
STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW,
- SOME_AUTH_REQUIRED_AFTER_USER_REQUEST})
+ STRONG_AUTH_REQUIRED_AFTER_USER_REQUEST})
@Retention(RetentionPolicy.SOURCE)
public @interface StrongAuthFlags {}
@@ -1266,14 +1266,14 @@
public static final int STRONG_AUTH_REQUIRED_AFTER_BOOT = 0x1;
/**
- * Strong authentication is required because a device admin has requested it.
+ * Strong authentication is required because a device admin has temporarily requested it.
*/
public static final int STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW = 0x2;
/**
- * Some authentication is required because the user has temporarily disabled trust.
+ * Strong authentication is required because the user has temporarily requested it.
*/
- public static final int SOME_AUTH_REQUIRED_AFTER_USER_REQUEST = 0x4;
+ public static final int STRONG_AUTH_REQUIRED_AFTER_USER_REQUEST = 0x4;
/**
* Strong authentication is required because the user has been locked out after too many
@@ -1281,11 +1281,17 @@
*/
public static final int STRONG_AUTH_REQUIRED_AFTER_LOCKOUT = 0x8;
+ /**
+ * Some authentication is required because the user has entered a wrong credential.
+ */
+ public static final int SOME_AUTH_REQUIRED_AFTER_WRONG_CREDENTIAL = 0x10;
+
public static final int DEFAULT = STRONG_AUTH_REQUIRED_AFTER_BOOT;
- private static final int ALLOWING_FINGERPRINT = SOME_AUTH_REQUIRED_AFTER_USER_REQUEST;
- final SparseIntArray mStrongAuthRequiredForUser = new SparseIntArray();
+ private static final int ALLOWING_FINGERPRINT = STRONG_AUTH_NOT_REQUIRED
+ | SOME_AUTH_REQUIRED_AFTER_WRONG_CREDENTIAL;
+ private final SparseIntArray mStrongAuthRequiredForUser = new SparseIntArray();
private final H mHandler;
public StrongAuthTracker() {
diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp
index dce2ecb..1d1685a 100644
--- a/core/jni/com_android_internal_os_Zygote.cpp
+++ b/core/jni/com_android_internal_os_Zygote.cpp
@@ -83,6 +83,14 @@
pid_t pid;
int status;
+ // It's necessary to save and restore the errno during this function.
+ // Since errno is stored per thread, changing it here modifies the errno
+ // on the thread on which this signal handler executes. If a signal occurs
+ // between a call and an errno check, it's possible to get the errno set
+ // here.
+ // See b/23572286 for extra information.
+ int saved_errno = errno;
+
while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
// Log process-death status that we care about. In general it is
// not safe to call LOG(...) from a signal handler because of
@@ -118,6 +126,8 @@
if (pid < 0 && errno != ECHILD) {
ALOGW("Zygote SIGCHLD error in waitpid: %s", strerror(errno));
}
+
+ errno = saved_errno;
}
// Configures the SIGCHLD handler for the zygote process. This is configured
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 86659ae..02fb8f4 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -2061,6 +2061,12 @@
<permission android:name="android.permission.SET_KEYBOARD_LAYOUT"
android:protectionLevel="signature" />
+ <!-- Allows an application to monitor changes in tablet mode.
+ <p>Not for use by third-party applications.
+ @hide -->
+ <permission android:name="android.permission.TABLET_MODE_LISTENER"
+ android:protectionLevel="signature" />
+
<!-- Allows an application to request installing packages. Apps
targeting APIs greater than 22 must hold this permission in
order to use {@link android.content.Intent#ACTION_INSTALL_PACKAGE}.
diff --git a/core/res/res/values-mcc204-mnc12/config.xml b/core/res/res/values-mcc204-mnc12/config.xml
new file mode 100644
index 0000000..80432d7
--- /dev/null
+++ b/core/res/res/values-mcc204-mnc12/config.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 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 my 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.
+*/
+-->
+
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- Don't use roaming icon for considered operators -->
+ <string-array translatable="false" name="config_operatorConsideredNonRoaming">
+ <item>20408</item>
+ </string-array>
+</resources>
diff --git a/core/res/res/values-mcc450-mnc06/config.xml b/core/res/res/values-mcc450-mnc06/config.xml
index 63f9823..819c2a5 100644
--- a/core/res/res/values-mcc450-mnc06/config.xml
+++ b/core/res/res/values-mcc450-mnc06/config.xml
@@ -25,4 +25,7 @@
-->
<integer name="config_mobile_mtu">1428</integer>
+ <!-- Do not set the system language as value of EF LI/EF PL -->
+ <bool name="config_use_sim_language_file">false</bool>
+
</resources>
diff --git a/core/res/res/values-mcc450-mnc08/config.xml b/core/res/res/values-mcc450-mnc08/config.xml
index 950c62b..ca26ec1 100644
--- a/core/res/res/values-mcc450-mnc08/config.xml
+++ b/core/res/res/values-mcc450-mnc08/config.xml
@@ -25,4 +25,7 @@
-->
<integer name="config_mobile_mtu">1450</integer>
+ <!-- Do not set the system language as value of EF LI/EF PL -->
+ <bool name="config_use_sim_language_file">false</bool>
+
</resources>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 694d263..77d79ad 100755
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -166,6 +166,21 @@
so that applications can still use their own mechanisms. -->
<bool name="config_enableAutoPowerModes">false</bool>
+ <!-- The threshold angle for any motion detection in auto-power save modes.
+ In hundreths of a degree. -->
+ <integer name="config_autoPowerModeThresholdAngle">200</integer>
+
+ <!-- The sensor id of an "any motion" sensor used in auto-power save modes.
+ 0 indicates this sensor is not available. -->
+ <integer name="config_autoPowerModeAnyMotionSensor">0</integer>
+
+ <!-- If an any motion sensor is not available, prefer the wrist tilt detector over the
+ SMD. -->
+ <bool name="config_autoPowerModePreferWristTilt">false</bool>
+
+ <!-- If a location should be pre-fetched when going into device idle. -->
+ <bool name="config_autoPowerModePrefetchLocation">true</bool>
+
<!-- The duration (in milliseconds) that the radio will scan for a signal
when there's no network connection. If the scan doesn't timeout, use zero -->
<integer name="config_radioScanningTimeout">0</integer>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 4e94a64..35443fe 100755
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -253,6 +253,10 @@
<java-symbol type="bool" name="config_cellBroadcastAppLinks" />
<java-symbol type="bool" name="config_duplicate_port_omadm_wappush" />
<java-symbol type="bool" name="config_enableAutoPowerModes" />
+ <java-symbol type="integer" name="config_autoPowerModeThresholdAngle" />
+ <java-symbol type="integer" name="config_autoPowerModeAnyMotionSensor" />
+ <java-symbol type="bool" name="config_autoPowerModePreferWristTilt" />
+ <java-symbol type="bool" name="config_autoPowerModePrefetchLocation" />
<java-symbol type="bool" name="config_enable_emergency_call_while_sim_locked" />
<java-symbol type="bool" name="config_enable_puk_unlock_screen" />
<java-symbol type="bool" name="config_enableBurnInProtection" />
diff --git a/core/tests/bluetoothtests/AndroidManifest.xml b/core/tests/bluetoothtests/AndroidManifest.xml
index e43ba12..7f9d874 100644
--- a/core/tests/bluetoothtests/AndroidManifest.xml
+++ b/core/tests/bluetoothtests/AndroidManifest.xml
@@ -21,6 +21,7 @@
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<uses-permission android:name="android.permission.BROADCAST_STICKY" />
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
+ <uses-permission android:name="android.permission.LOCAL_MAC_ADDRESS" />
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_SETTINGS" />
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardPinBasedInputView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardPinBasedInputView.java
index ce2d11a..f51e10f 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardPinBasedInputView.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardPinBasedInputView.java
@@ -64,7 +64,7 @@
@Override
protected void resetState() {
- mPasswordEntry.setEnabled(true);
+ setPasswordEntryEnabled(true);
}
@Override
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
index fc6117f..b752c9b 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -29,6 +29,7 @@
import android.content.IntentFilter;
import android.database.ContentObserver;
import android.graphics.Bitmap;
+import android.hardware.fingerprint.Fingerprint;
import android.hardware.fingerprint.FingerprintManager;
import android.hardware.fingerprint.FingerprintManager.AuthenticationCallback;
import android.hardware.fingerprint.FingerprintManager.AuthenticationResult;
@@ -472,6 +473,10 @@
}
}
+ private void handleFingerprintLockoutReset() {
+ updateFingerprintListeningState();
+ }
+
private void setFingerprintRunningState(int fingerprintRunningState) {
boolean wasRunning = mFingerprintRunningState == FINGERPRINT_STATE_RUNNING;
boolean isRunning = fingerprintRunningState == FINGERPRINT_STATE_RUNNING;
@@ -681,6 +686,14 @@
}
};
+ private final FingerprintManager.LockoutResetCallback mLockoutResetCallback
+ = new FingerprintManager.LockoutResetCallback() {
+ @Override
+ public void onLockoutReset() {
+ handleFingerprintLockoutReset();
+ }
+ };
+
private FingerprintManager.AuthenticationCallback mAuthenticationCallback
= new AuthenticationCallback() {
@@ -1003,6 +1016,9 @@
mFpm = (FingerprintManager) context.getSystemService(Context.FINGERPRINT_SERVICE);
updateFingerprintListeningState();
+ if (mFpm != null) {
+ mFpm.addLockoutResetCallback(mLockoutResetCallback);
+ }
}
private void updateFingerprintListeningState() {
@@ -1332,9 +1348,7 @@
*/
private void handleKeyguardReset() {
if (DEBUG) Log.d(TAG, "handleKeyguardReset");
- if (!isUnlockingWithFingerprintAllowed()) {
- updateFingerprintListeningState();
- }
+ updateFingerprintListeningState();
}
/**
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index d785cca..b9daf59 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -39,6 +39,7 @@
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.EXPAND_STATUS_BAR" />
+ <uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
<!-- System tool permissions granted to the shell. -->
<uses-permission android:name="android.permission.REAL_GET_TASKS" />
<uses-permission android:name="android.permission.CHANGE_CONFIGURATION" />
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index d520072..da4ffa4 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -1046,6 +1046,7 @@
// Without this, settings is not enabled until the lock screen first appears
setShowingLocked(false);
hideLocked();
+ mUpdateMonitor.reportSuccessfulStrongAuthUnlockAttempt();
return;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
index c14f2159..eecac63 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
@@ -1636,11 +1636,13 @@
protected void handleVisibleToUserChanged(boolean visibleToUser) {
try {
if (visibleToUser) {
- boolean clearNotificationEffects = !isPanelFullyCollapsed() &&
- (mShowLockscreenNotifications ||
- (mState == StatusBarState.SHADE || mState == StatusBarState.SHADE_LOCKED));
+ boolean pinnedHeadsUp = mHeadsUpManager.hasPinnedHeadsUp();
+ boolean clearNotificationEffects =
+ ((mShowLockscreenNotifications && mState == StatusBarState.KEYGUARD) ||
+ (!pinnedHeadsUp && (mState == StatusBarState.SHADE
+ || mState == StatusBarState.SHADE_LOCKED)));
int notificationLoad = mNotificationData.getActiveNotifications().size();
- if (mHeadsUpManager.hasPinnedHeadsUp() && isPanelFullyCollapsed()) {
+ if (pinnedHeadsUp && isPanelFullyCollapsed()) {
notificationLoad = 1;
} else {
MetricsLogger.histogram(mContext, "note_load", notificationLoad);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/FingerprintUnlockController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/FingerprintUnlockController.java
index 4e69999..84082db 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/FingerprintUnlockController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/FingerprintUnlockController.java
@@ -227,7 +227,7 @@
return MODE_DISMISS_BOUNCER;
} else if (unlockingAllowed) {
return MODE_UNLOCK;
- } else {
+ } else if (!mStatusBarKeyguardViewManager.isBouncerShowing()) {
return MODE_SHOW_BOUNCER;
}
}
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 d30411a..f4439bf 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
@@ -262,14 +262,21 @@
return (secure && !canSkipBouncer) ? SECURE_CAMERA_INTENT : INSECURE_CAMERA_INTENT;
}
+ /**
+ * Resolves the intent to launch the camera application.
+ */
+ public ResolveInfo resolveCameraIntent() {
+ return mContext.getPackageManager().resolveActivityAsUser(getCameraIntent(),
+ PackageManager.MATCH_DEFAULT_ONLY,
+ KeyguardUpdateMonitor.getCurrentUser());
+ }
+
private void updateCameraVisibility() {
if (mCameraImageView == null) {
// Things are not set up yet; reply hazy, ask again later
return;
}
- ResolveInfo resolved = mContext.getPackageManager().resolveActivityAsUser(getCameraIntent(),
- PackageManager.MATCH_DEFAULT_ONLY,
- KeyguardUpdateMonitor.getCurrentUser());
+ ResolveInfo resolved = resolveCameraIntent();
boolean visible = !isCameraDisabledByDpm() && resolved != null
&& getResources().getBoolean(R.bool.config_keyguardShowCameraAffordance)
&& mUserSetupComplete;
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 93ecb06..030501b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java
@@ -166,10 +166,13 @@
if (mAccessibilityController == null) {
return;
}
+ boolean trustManagedOrFingerprintAllowed = mUnlockMethodCache.isTrustManaged()
+ || KeyguardUpdateMonitor.getInstance(mContext).isUnlockingWithFingerprintAllowed();
+
boolean clickToUnlock = mAccessibilityController.isTouchExplorationEnabled();
- boolean clickToForceLock = mUnlockMethodCache.isTrustManaged()
+ boolean clickToForceLock = trustManagedOrFingerprintAllowed
&& !mAccessibilityController.isAccessibilityEnabled();
- boolean longClickToForceLock = mUnlockMethodCache.isTrustManaged()
+ boolean longClickToForceLock = trustManagedOrFingerprintAllowed
&& !clickToForceLock;
setClickable(clickToForceLock || clickToUnlock);
setLongClickable(longClickToForceLock);
@@ -245,10 +248,10 @@
return STATE_FINGERPRINT_ERROR;
} else if (mUnlockMethodCache.canSkipBouncer()) {
return STATE_LOCK_OPEN;
- } else if (fingerprintRunning && unlockingAllowed) {
- return STATE_FINGERPRINT;
} else if (mUnlockMethodCache.isFaceUnlockRunning()) {
return STATE_FACE_UNLOCK;
+ } else if (fingerprintRunning && unlockingAllowed) {
+ return STATE_FINGERPRINT;
} else {
return STATE_LOCKED;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupManager.java
index 950b162..310625e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupManager.java
@@ -78,6 +78,13 @@
Notification notif = sbn.getNotification();
String groupKey = sbn.getGroupKey();
final NotificationGroup group = mGroupMap.get(groupKey);
+ if (group == null) {
+ // When an app posts 2 different notifications as summary of the same group, then a
+ // cancellation of the first notification removes this group.
+ // This situation is not supported and we will not allow such notifications anymore in
+ // the close future. See b/23676310 for reference.
+ return;
+ }
if (notif.isGroupSummary()) {
group.summary = null;
} else {
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 5557f9c..b93586e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -21,7 +21,10 @@
import android.animation.ObjectAnimator;
import android.animation.PropertyValuesHolder;
import android.animation.ValueAnimator;
+import android.app.ActivityManager;
+import android.app.ActivityManager.RunningTaskInfo;
import android.content.Context;
+import android.content.pm.ResolveInfo;
import android.content.res.Configuration;
import android.graphics.Canvas;
import android.graphics.Color;
@@ -61,6 +64,8 @@
import com.android.systemui.statusbar.stack.NotificationStackScrollLayout;
import com.android.systemui.statusbar.stack.StackStateAnimator;
+import java.util.List;
+
public class NotificationPanelView extends PanelView implements
ExpandableView.OnHeightChangedListener, ObservableScrollView.Listener,
View.OnClickListener, NotificationStackScrollLayout.OnOverscrollTopChangedListener,
@@ -2425,7 +2430,28 @@
getCenterIcon().setLaunchingAffordance(launchingAffordance);
}
- public boolean canCameraGestureBeLaunched() {
- return !mAfforanceHelper.isSwipingInProgress();
+ /**
+ * Whether the camera application can be launched for the camera launch gesture.
+ *
+ * @param keyguardIsShowing whether keyguard is being shown
+ */
+ public boolean canCameraGestureBeLaunched(boolean keyguardIsShowing) {
+ ResolveInfo resolveInfo = mKeyguardBottomArea.resolveCameraIntent();
+ String packageToLaunch = (resolveInfo == null || resolveInfo.activityInfo == null)
+ ? null : resolveInfo.activityInfo.packageName;
+ return packageToLaunch != null &&
+ (keyguardIsShowing || !isForegroundApp(packageToLaunch)) &&
+ !mAfforanceHelper.isSwipingInProgress();
+ }
+
+ /**
+ * Return true if the applications with the package name is running in foreground.
+ *
+ * @param pkgName application package name.
+ */
+ private boolean isForegroundApp(String pkgName) {
+ ActivityManager am = getContext().getSystemService(ActivityManager.class);
+ List<ActivityManager.RunningTaskInfo> tasks = am.getRunningTasks(1);
+ return !tasks.isEmpty() && pkgName.equals(tasks.get(0).topActivity.getPackageName());
}
}
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 8063bbe..55b1127 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -3742,12 +3742,9 @@
// down on the lockscreen), clear notification LED, vibration,
// ringing.
// Other transitions are covered in handleVisibleToUserChanged().
- if (state != mState && mVisible && state == StatusBarState.SHADE_LOCKED) {
- try {
- mBarService.clearNotificationEffects();
- } catch (RemoteException e) {
- // Ignore.
- }
+ if (state != mState && mVisible && (state == StatusBarState.SHADE_LOCKED
+ || (state == StatusBarState.SHADE && isGoingToNotificationShade()))) {
+ clearNotificationEffects();
}
mState = state;
mGroupManager.setStatusBarState(state);
@@ -4090,7 +4087,8 @@
@Override
public void onCameraLaunchGestureDetected() {
- if (!mNotificationPanel.canCameraGestureBeLaunched()) {
+ if (!mNotificationPanel.canCameraGestureBeLaunched(
+ mStatusBarKeyguardViewManager.isShowing() && mExpandedVisible)) {
return;
}
if (!mDeviceInteractive) {
diff --git a/services/core/java/com/android/server/AlarmManagerService.java b/services/core/java/com/android/server/AlarmManagerService.java
index d58d3721..e3d5d38 100644
--- a/services/core/java/com/android/server/AlarmManagerService.java
+++ b/services/core/java/com/android/server/AlarmManagerService.java
@@ -177,7 +177,7 @@
private static final long DEFAULT_MIN_FUTURITY = 5 * 1000;
private static final long DEFAULT_MIN_INTERVAL = 60 * 1000;
- private static final long DEFAULT_ALLOW_WHILE_IDLE_SHORT_TIME = 60*1000;
+ private static final long DEFAULT_ALLOW_WHILE_IDLE_SHORT_TIME = DEFAULT_MIN_FUTURITY;
private static final long DEFAULT_ALLOW_WHILE_IDLE_LONG_TIME = 15*60*1000;
private static final long DEFAULT_ALLOW_WHILE_IDLE_WHITELIST_DURATION = 10*1000;
diff --git a/services/core/java/com/android/server/AnyMotionDetector.java b/services/core/java/com/android/server/AnyMotionDetector.java
index 6a67316..a0b5c15 100644
--- a/services/core/java/com/android/server/AnyMotionDetector.java
+++ b/services/core/java/com/android/server/AnyMotionDetector.java
@@ -58,9 +58,6 @@
/** Current measurement state. */
private int mState;
- /** Threshold angle in degrees beyond which the device is considered moving. */
- private final float THRESHOLD_ANGLE = 2f;
-
/** Threshold energy above which the device is considered moving. */
private final float THRESHOLD_ENERGY = 5f;
@@ -88,6 +85,9 @@
private SensorManager mSensorManager;
private PowerManager.WakeLock mWakeLock;
+ /** Threshold angle in degrees beyond which the device is considered moving. */
+ private final float mThresholdAngle;
+
/** The minimum number of samples required to detect AnyMotion. */
private int mNumSufficientSamples;
@@ -106,7 +106,7 @@
private DeviceIdleCallback mCallback = null;
public AnyMotionDetector(PowerManager pm, Handler handler, SensorManager sm,
- DeviceIdleCallback callback) {
+ DeviceIdleCallback callback, float thresholdAngle) {
if (DEBUG) Slog.d(TAG, "AnyMotionDetector instantiated.");
mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
mWakeLock.setReferenceCounted(false);
@@ -116,6 +116,7 @@
mMeasurementInProgress = false;
mState = STATE_INACTIVE;
mCallback = callback;
+ mThresholdAngle = thresholdAngle;
mRunningStats = new RunningSignalStats();
mNumSufficientSamples = (int) Math.ceil(
((double)ORIENTATION_MEASUREMENT_DURATION_MILLIS / SAMPLING_INTERVAL_MILLIS));
@@ -224,8 +225,9 @@
Vector3 previousGravityVectorNormalized = mPreviousGravityVector.normalized();
Vector3 currentGravityVectorNormalized = mCurrentGravityVector.normalized();
float angle = previousGravityVectorNormalized.angleBetween(currentGravityVectorNormalized);
- if (DEBUG) Slog.d(TAG, "getStationaryStatus: angle = " + angle);
- if ((angle < THRESHOLD_ANGLE) && (mRunningStats.getEnergy() < THRESHOLD_ENERGY)) {
+ if (DEBUG) Slog.d(TAG, "getStationaryStatus: angle = " + angle
+ + " energy = " + mRunningStats.getEnergy());
+ if ((angle < mThresholdAngle) && (mRunningStats.getEnergy() < THRESHOLD_ENERGY)) {
return RESULT_STATIONARY;
} else if (Float.isNaN(angle)) {
/**
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index e19447d..2bcee91 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -1524,10 +1524,14 @@
final long ident = Binder.clearCallingIdentity();
if (ConnectivityManager.CONNECTIVITY_ACTION.equals(intent.getAction())) {
+ final NetworkInfo ni = intent.getParcelableExtra(
+ ConnectivityManager.EXTRA_NETWORK_INFO);
+ if (ni.getType() == ConnectivityManager.TYPE_MOBILE_SUPL) {
+ intent.setAction(ConnectivityManager.CONNECTIVITY_ACTION_SUPL);
+ intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
+ }
final IBatteryStats bs = BatteryStatsService.getService();
try {
- NetworkInfo ni = intent.getParcelableExtra(
- ConnectivityManager.EXTRA_NETWORK_INFO);
bs.noteConnectivityChanged(intent.getIntExtra(
ConnectivityManager.EXTRA_NETWORK_TYPE, ConnectivityManager.TYPE_NONE),
ni != null ? ni.getState().toString() : "?");
diff --git a/services/core/java/com/android/server/DeviceIdleController.java b/services/core/java/com/android/server/DeviceIdleController.java
index 80fd441..80e8d1c 100644
--- a/services/core/java/com/android/server/DeviceIdleController.java
+++ b/services/core/java/com/android/server/DeviceIdleController.java
@@ -98,7 +98,7 @@
implements AnyMotionDetector.DeviceIdleCallback {
private static final String TAG = "DeviceIdleController";
- private static final boolean DEBUG = false;
+ private static final boolean DEBUG = true; // STOPSHIP
private static final boolean COMPRESS_TIME = false;
@@ -128,7 +128,8 @@
private boolean mNotMoving;
private boolean mLocating;
private boolean mLocated;
- private boolean mHaveGps;
+ private boolean mHasGps;
+ private boolean mHasNetworkLocation;
private Location mLastGenericLocation;
private Location mLastGpsLocation;
@@ -882,17 +883,37 @@
mDisplayManager = (DisplayManager) getContext().getSystemService(
Context.DISPLAY_SERVICE);
mSensorManager = (SensorManager) getContext().getSystemService(Context.SENSOR_SERVICE);
- mSigMotionSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_SIGNIFICANT_MOTION);
- mLocationManager = (LocationManager) getContext().getSystemService(
- Context.LOCATION_SERVICE);
- mLocationRequest = new LocationRequest()
- .setQuality(LocationRequest.ACCURACY_FINE)
- .setInterval(0)
- .setFastestInterval(0)
- .setNumUpdates(1);
+ int sigMotionSensorId = getContext().getResources().getInteger(
+ com.android.internal.R.integer.config_autoPowerModeAnyMotionSensor);
+ if (sigMotionSensorId > 0) {
+ mSigMotionSensor = mSensorManager.getDefaultSensor(sigMotionSensorId, true);
+ }
+ if (mSigMotionSensor == null && getContext().getResources().getBoolean(
+ com.android.internal.R.bool.config_autoPowerModePreferWristTilt)) {
+ mSigMotionSensor = mSensorManager.getDefaultSensor(
+ Sensor.TYPE_WRIST_TILT_GESTURE);
+ }
+ if (mSigMotionSensor == null) {
+ // As a last ditch, fall back to SMD.
+ mSigMotionSensor = mSensorManager.getDefaultSensor(
+ Sensor.TYPE_SIGNIFICANT_MOTION);
+ }
+ if (getContext().getResources().getBoolean(
+ com.android.internal.R.bool.config_autoPowerModePrefetchLocation)) {
+ mLocationManager = (LocationManager) getContext().getSystemService(
+ Context.LOCATION_SERVICE);
+ mLocationRequest = new LocationRequest()
+ .setQuality(LocationRequest.ACCURACY_FINE)
+ .setInterval(0)
+ .setFastestInterval(0)
+ .setNumUpdates(1);
+ }
+
+ float angleThreshold = getContext().getResources().getInteger(
+ com.android.internal.R.integer.config_autoPowerModeThresholdAngle) / 100f;
mAnyMotionDetector = new AnyMotionDetector(
(PowerManager) getContext().getSystemService(Context.POWER_SERVICE),
- mHandler, mSensorManager, this);
+ mHandler, mSensorManager, this, angleThreshold);
Intent intent = new Intent(ACTION_STEP_IDLE_STATE)
.setPackage("android")
@@ -1279,17 +1300,30 @@
EventLogTags.writeDeviceIdle(mState, "step");
cancelSensingAlarmLocked();
scheduleSensingAlarmLocked(mConstants.LOCATING_TIMEOUT);
- mLocating = true;
- mLocationManager.requestLocationUpdates(mLocationRequest, mGenericLocationListener,
- mHandler.getLooper());
- if (mLocationManager.getProvider(LocationManager.GPS_PROVIDER) != null) {
- mHaveGps = true;
+ if (mLocationManager != null
+ && mLocationManager.getProvider(LocationManager.NETWORK_PROVIDER) != null) {
+ mLocationManager.requestLocationUpdates(mLocationRequest,
+ mGenericLocationListener, mHandler.getLooper());
+ mLocating = true;
+ } else {
+ mHasNetworkLocation = false;
+ }
+ if (mLocationManager != null
+ && mLocationManager.getProvider(LocationManager.GPS_PROVIDER) != null) {
+ mHasGps = true;
mLocationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 1000, 5,
mGpsLocationListener, mHandler.getLooper());
+ mLocating = true;
} else {
- mHaveGps = false;
+ mHasGps = false;
}
- break;
+ // If we have a location provider, we're all set, the listeners will move state
+ // forward.
+ if (mLocating) {
+ break;
+ }
+
+ // Otherwise, we have to move from locating into idle maintenance.
case STATE_LOCATING:
cancelSensingAlarmLocked();
cancelLocatingLocked();
@@ -1346,7 +1380,7 @@
}
if (DEBUG) Slog.d(TAG, "Generic location: " + location);
mLastGenericLocation = new Location(location);
- if (location.getAccuracy() > mConstants.LOCATION_ACCURACY && mHaveGps) {
+ if (location.getAccuracy() > mConstants.LOCATION_ACCURACY && mHasGps) {
return;
}
mLocated = true;
@@ -1413,9 +1447,9 @@
void scheduleAlarmLocked(long delay, boolean idleUntil) {
if (DEBUG) Slog.d(TAG, "scheduleAlarmLocked(" + delay + ", " + idleUntil + ")");
if (mSigMotionSensor == null) {
- // If there is no significant motion sensor on this device, then we won't schedule
+ // If there is no motion sensor on this device, then we won't schedule
// alarms, because we can't determine if the device is not moving. This effectively
- // turns off normal exeuction of device idling, although it is still possible to
+ // turns off normal execution of device idling, although it is still possible to
// manually poke it by pretending like the alarm is going off.
return;
}
@@ -1902,8 +1936,9 @@
pw.print(" mSigMotionActive="); pw.println(mSigMotionActive);
pw.print(" mSensing="); pw.print(mSensing); pw.print(" mNotMoving=");
pw.println(mNotMoving);
- pw.print(" mLocating="); pw.print(mLocating); pw.print(" mHaveGps=");
- pw.print(mHaveGps); pw.print(" mLocated="); pw.println(mLocated);
+ pw.print(" mLocating="); pw.print(mLocating); pw.print(" mHasGps=");
+ pw.print(mHasGps); pw.print(" mHasNetwork=");
+ pw.print(mHasNetworkLocation); pw.print(" mLocated="); pw.println(mLocated);
if (mLastGenericLocation != null) {
pw.print(" mLastGenericLocation="); pw.println(mLastGenericLocation);
}
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index 899139f..b87e109 100755
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -2085,7 +2085,8 @@
}
private boolean collectPackageServicesLocked(String packageName, Set<String> filterByClasses,
- boolean evenPersistent, boolean doit, ArrayMap<ComponentName, ServiceRecord> services) {
+ boolean evenPersistent, boolean doit, boolean killProcess,
+ ArrayMap<ComponentName, ServiceRecord> services) {
boolean didSomething = false;
for (int i = services.size() - 1; i >= 0; i--) {
ServiceRecord service = services.valueAt(i);
@@ -2101,7 +2102,7 @@
didSomething = true;
Slog.i(TAG, " Force stopping service " + service);
if (service.app != null) {
- service.app.removed = true;
+ service.app.removed = killProcess;
if (!service.app.persistent) {
service.app.services.remove(service);
}
@@ -2118,7 +2119,7 @@
}
boolean bringDownDisabledPackageServicesLocked(String packageName, Set<String> filterByClasses,
- int userId, boolean evenPersistent, boolean doit) {
+ int userId, boolean evenPersistent, boolean killProcess, boolean doit) {
boolean didSomething = false;
if (mTmpCollectionResults != null) {
@@ -2128,7 +2129,7 @@
if (userId == UserHandle.USER_ALL) {
for (int i = mServiceMap.size() - 1; i >= 0; i--) {
didSomething |= collectPackageServicesLocked(packageName, filterByClasses,
- evenPersistent, doit, mServiceMap.valueAt(i).mServicesByName);
+ evenPersistent, doit, killProcess, mServiceMap.valueAt(i).mServicesByName);
if (!doit && didSomething) {
return true;
}
@@ -2138,7 +2139,7 @@
if (smap != null) {
ArrayMap<ComponentName, ServiceRecord> items = smap.mServicesByName;
didSomething = collectPackageServicesLocked(packageName, filterByClasses,
- evenPersistent, doit, items);
+ evenPersistent, doit, killProcess, items);
}
}
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 191bf99..525aac7 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -400,6 +400,17 @@
private static final int PERSISTENT_MASK =
ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PERSISTENT;
+
+ // Delay to disable app launch boost
+ static final int APP_BOOST_MESSAGE_DELAY = 3000;
+ // Lower delay than APP_BOOST_MESSAGE_DELAY to disable the boost
+ static final int APP_BOOST_TIMEOUT = 2500;
+
+ private static native int nativeMigrateToBoost();
+ private static native int nativeMigrateFromBoost();
+ private boolean mIsBoosted = false;
+ private long mBoostStartTime = 0;
+
/** All system services */
SystemServiceManager mSystemServiceManager;
@@ -1356,6 +1367,7 @@
static final int REPORT_TIME_TRACKER_MSG = 55;
static final int REPORT_USER_SWITCH_COMPLETE_MSG = 56;
static final int SHUTDOWN_UI_AUTOMATION_CONNECTION_MSG = 57;
+ static final int APP_BOOST_DEACTIVATE_MSG = 58;
static final int FIRST_ACTIVITY_STACK_MSG = 100;
static final int FIRST_BROADCAST_QUEUE_MSG = 200;
@@ -2031,6 +2043,20 @@
// it is finished we make sure it is reset to its default.
mUserIsMonkey = false;
} break;
+ case APP_BOOST_DEACTIVATE_MSG : {
+ synchronized(ActivityManagerService.this) {
+ if (mIsBoosted) {
+ if (mBoostStartTime < (SystemClock.uptimeMillis() - APP_BOOST_TIMEOUT)) {
+ nativeMigrateFromBoost();
+ mIsBoosted = false;
+ mBoostStartTime = 0;
+ } else {
+ Message newmsg = mHandler.obtainMessage(APP_BOOST_DEACTIVATE_MSG);
+ mHandler.sendMessageDelayed(newmsg, APP_BOOST_TIMEOUT);
+ }
+ }
+ }
+ } break;
}
}
};
@@ -3114,6 +3140,16 @@
app = null;
}
+ // app launch boost for big.little configurations
+ // use cpusets to migrate freshly launched tasks to big cores
+ synchronized(ActivityManagerService.this) {
+ nativeMigrateToBoost();
+ mIsBoosted = true;
+ mBoostStartTime = SystemClock.uptimeMillis();
+ Message msg = mHandler.obtainMessage(APP_BOOST_DEACTIVATE_MSG);
+ mHandler.sendMessageDelayed(msg, APP_BOOST_MESSAGE_DELAY);
+ }
+
// We don't have to do anything more if:
// (1) There is an existing application record; and
// (2) The caller doesn't think it is dead, OR there is no thread
@@ -5562,7 +5598,7 @@
}
private void cleanupDisabledPackageComponentsLocked(
- String packageName, int userId, String[] changedClasses) {
+ String packageName, int userId, boolean killProcess, String[] changedClasses) {
Set<String> disabledClasses = null;
boolean packageDisabled = false;
@@ -5632,7 +5668,7 @@
// Clean-up disabled services.
mServices.bringDownDisabledPackageServicesLocked(
- packageName, disabledClasses, userId, false, true);
+ packageName, disabledClasses, userId, false, killProcess, true);
// Clean-up disabled providers.
ArrayList<ContentProviderRecord> providers = new ArrayList<>();
@@ -5717,7 +5753,7 @@
}
if (mServices.bringDownDisabledPackageServicesLocked(
- packageName, null, userId, evenPersistent, doit)) {
+ packageName, null, userId, evenPersistent, true, doit)) {
if (!doit) {
return true;
}
@@ -16590,7 +16626,9 @@
boolean removed = Intent.ACTION_PACKAGE_REMOVED.equals(action);
boolean fullUninstall = removed &&
!intent.getBooleanExtra(Intent.EXTRA_REPLACING, false);
- if (!intent.getBooleanExtra(Intent.EXTRA_DONT_KILL_APP, false)) {
+ final boolean killProcess =
+ !intent.getBooleanExtra(Intent.EXTRA_DONT_KILL_APP, false);
+ if (killProcess) {
forceStopPackageLocked(ssp, UserHandle.getAppId(
intent.getIntExtra(Intent.EXTRA_UID, -1)),
false, true, true, false, fullUninstall, userId,
@@ -16610,7 +16648,7 @@
mBatteryStatsService.notePackageUninstalled(ssp);
}
} else {
- cleanupDisabledPackageComponentsLocked(ssp, userId,
+ cleanupDisabledPackageComponentsLocked(ssp, userId, killProcess,
intent.getStringArrayExtra(
Intent.EXTRA_CHANGED_COMPONENT_NAME_LIST));
}
diff --git a/services/core/java/com/android/server/am/BroadcastQueue.java b/services/core/java/com/android/server/am/BroadcastQueue.java
index a956c56..960cbf1 100644
--- a/services/core/java/com/android/server/am/BroadcastQueue.java
+++ b/services/core/java/com/android/server/am/BroadcastQueue.java
@@ -509,7 +509,7 @@
break;
}
int appOp = AppOpsManager.permissionToOpCode(requiredPermission);
- if (appOp != r.appOp
+ if (appOp != AppOpsManager.OP_NONE && appOp != r.appOp
&& mService.mAppOpsService.noteOperation(appOp,
filter.receiverList.uid, filter.packageName)
!= AppOpsManager.MODE_ALLOWED) {
diff --git a/services/core/java/com/android/server/fingerprint/FingerprintService.java b/services/core/java/com/android/server/fingerprint/FingerprintService.java
index 7e46db8..0023258 100644
--- a/services/core/java/com/android/server/fingerprint/FingerprintService.java
+++ b/services/core/java/com/android/server/fingerprint/FingerprintService.java
@@ -18,13 +18,18 @@
import android.Manifest;
import android.app.ActivityManager;
+import android.app.ActivityManager.RunningAppProcessInfo;
+import android.app.ActivityManager.RunningTaskInfo;
import android.app.ActivityManagerNative;
import android.app.AppOpsManager;
import android.app.IUserSwitchObserver;
+import android.content.ComponentName;
import android.content.Context;
import android.content.pm.PackageManager;
import android.content.pm.UserInfo;
+import android.hardware.fingerprint.IFingerprintServiceLockoutResetCallback;
import android.os.Binder;
+import android.os.DeadObjectException;
import android.os.Environment;
import android.os.Handler;
import android.os.IBinder;
@@ -51,8 +56,8 @@
import android.hardware.fingerprint.IFingerprintDaemon;
import android.hardware.fingerprint.IFingerprintDaemonCallback;
import android.hardware.fingerprint.IFingerprintServiceReceiver;
-import android.view.Display;
+import static android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND;
import static android.Manifest.permission.MANAGE_FINGERPRINT;
import static android.Manifest.permission.RESET_FINGERPRINT_LOCKOUT;
import static android.Manifest.permission.USE_FINGERPRINT;
@@ -60,6 +65,7 @@
import java.io.File;
import java.io.FileDescriptor;
import java.io.PrintWriter;
+import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
@@ -83,12 +89,15 @@
private ClientMonitor mAuthClient = null;
private ClientMonitor mEnrollClient = null;
private ClientMonitor mRemoveClient = null;
+ private final ArrayList<FingerprintServiceLockoutResetMonitor> mLockoutMonitors =
+ new ArrayList<>();
private final AppOpsManager mAppOps;
private static final long MS_PER_SEC = 1000;
private static final long FAIL_LOCKOUT_TIMEOUT_MS = 30*1000;
private static final int MAX_FAILED_ATTEMPTS = 5;
private static final int FINGERPRINT_ACQUIRED_GOOD = 0;
+ private final String mKeyguardPackage;
Handler mHandler = new Handler() {
@Override
@@ -121,6 +130,8 @@
public FingerprintService(Context context) {
super(context);
mContext = context;
+ 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);
}
@@ -248,7 +259,7 @@
}
private boolean inLockoutMode() {
- return mFailedAttempts > MAX_FAILED_ATTEMPTS;
+ return mFailedAttempts >= MAX_FAILED_ATTEMPTS;
}
private void resetFailedAttempts() {
@@ -259,11 +270,12 @@
// 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);
+ notifyLockoutResetMonitors();
}
private boolean handleFailedAttempt(ClientMonitor clientMonitor) {
mFailedAttempts++;
- if (mFailedAttempts > MAX_FAILED_ATTEMPTS) {
+ if (inLockoutMode()) {
// Failing multiple times will continue to push out the lockout time.
mHandler.removeCallbacks(mLockoutReset);
mHandler.postDelayed(mLockoutReset, FAIL_LOCKOUT_TIMEOUT_MS);
@@ -493,10 +505,67 @@
return false;
}
- private boolean canUseFingerprint(String opPackageName) {
+ private boolean isForegroundActivity(int uid, int pid) {
+ try {
+ List<RunningAppProcessInfo> procs =
+ ActivityManagerNative.getDefault().getRunningAppProcesses();
+ int N = procs.size();
+ for (int i = 0; i < N; i++) {
+ RunningAppProcessInfo proc = procs.get(i);
+ if (proc.pid == pid && proc.uid == uid
+ && proc.importance == IMPORTANCE_FOREGROUND) {
+ return true;
+ }
+ }
+ } catch (RemoteException e) {
+ Slog.w(TAG, "am.getRunningAppProcesses() failed");
+ }
+ return false;
+ }
+
+ /**
+ * @param opPackageName name of package for caller
+ * @param foregroundOnly only allow this call while app is in the foreground
+ * @return true if caller can use fingerprint API
+ */
+ private boolean canUseFingerprint(String opPackageName, boolean foregroundOnly) {
checkPermission(USE_FINGERPRINT);
- return mAppOps.noteOp(AppOpsManager.OP_USE_FINGERPRINT, Binder.getCallingUid(),
- opPackageName) == AppOpsManager.MODE_ALLOWED;
+ final int uid = Binder.getCallingUid();
+ final int pid = Binder.getCallingPid();
+ if (opPackageName.equals(mKeyguardPackage)) {
+ return true; // Keyguard is always allowed
+ }
+ if (!isCurrentUserOrProfile(UserHandle.getCallingUserId())) {
+ Slog.w(TAG,"Rejecting " + opPackageName + " ; not a current user or profile");
+ return false;
+ }
+ if (mAppOps.noteOp(AppOpsManager.OP_USE_FINGERPRINT, uid, opPackageName)
+ != AppOpsManager.MODE_ALLOWED) {
+ Slog.v(TAG, "Rejecting " + opPackageName + " ; permission denied");
+ return false;
+ }
+ if (foregroundOnly && !isForegroundActivity(uid, pid)) {
+ Slog.v(TAG, "Rejecting " + opPackageName + " ; not in foreground");
+ return false;
+ }
+ return true;
+ }
+
+ private void addLockoutResetMonitor(FingerprintServiceLockoutResetMonitor monitor) {
+ if (!mLockoutMonitors.contains(monitor)) {
+ mLockoutMonitors.add(monitor);
+ }
+ }
+
+ private void removeLockoutResetCallback(
+ FingerprintServiceLockoutResetMonitor monitor) {
+ mLockoutMonitors.remove(monitor);
+ }
+
+ private void notifyLockoutResetMonitors() {
+ for (int i = 0; i < mLockoutMonitors.size(); i++) {
+ mLockoutMonitors.get(i).sendLockoutReset();
+ }
}
private class ClientMonitor implements IBinder.DeathRecipient {
@@ -614,7 +683,7 @@
FingerprintUtils.vibrateFingerprintSuccess(getContext());
}
result |= true; // we have a valid fingerprint
- mLockoutReset.run();
+ mHandler.post(mLockoutReset);
}
return result;
}
@@ -654,6 +723,36 @@
}
}
+ private class FingerprintServiceLockoutResetMonitor {
+
+ private final IFingerprintServiceLockoutResetCallback mCallback;
+
+ public FingerprintServiceLockoutResetMonitor(
+ IFingerprintServiceLockoutResetCallback callback) {
+ mCallback = callback;
+ }
+
+ public void sendLockoutReset() {
+ if (mCallback != null) {
+ try {
+ mCallback.onLockoutReset(mHalDeviceId);
+ } catch (DeadObjectException e) {
+ Slog.w(TAG, "Death object while invoking onLockoutReset: ", e);
+ mHandler.post(mRemoveCallbackRunnable);
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Failed to invoke onLockoutReset: ", e);
+ }
+ }
+ }
+
+ private final Runnable mRemoveCallbackRunnable = new Runnable() {
+ @Override
+ public void run() {
+ removeLockoutResetCallback(FingerprintServiceLockoutResetMonitor.this);
+ }
+ };
+ }
+
private IFingerprintDaemonCallback mDaemonCallback = new IFingerprintDaemonCallback.Stub() {
@Override
@@ -782,12 +881,7 @@
public void authenticate(final IBinder token, final long opId, final int groupId,
final IFingerprintServiceReceiver receiver, final int flags,
final String opPackageName) {
- if (!isCurrentUserOrProfile(UserHandle.getCallingUserId())) {
- Slog.w(TAG, "Can't authenticate non-current user");
- return;
- }
- if (!canUseFingerprint(opPackageName)) {
- Slog.w(TAG, "Calling not granted permission to use fingerprint");
+ if (!canUseFingerprint(opPackageName, true /* foregroundOnly */)) {
return;
}
@@ -807,7 +901,7 @@
@Override // Binder call
public void cancelAuthentication(final IBinder token, String opPackageName) {
- if (!canUseFingerprint(opPackageName)) {
+ if (!canUseFingerprint(opPackageName, false /* foregroundOnly */)) {
return;
}
mHandler.post(new Runnable() {
@@ -838,7 +932,7 @@
@Override // Binder call
public boolean isHardwareDetected(long deviceId, String opPackageName) {
- if (!canUseFingerprint(opPackageName)) {
+ if (!canUseFingerprint(opPackageName, false /* foregroundOnly */)) {
return false;
}
return mHalDeviceId != 0;
@@ -862,7 +956,7 @@
@Override // Binder call
public List<Fingerprint> getEnrolledFingerprints(int userId, String opPackageName) {
- if (!canUseFingerprint(opPackageName)) {
+ if (!canUseFingerprint(opPackageName, false /* foregroundOnly */)) {
return Collections.emptyList();
}
int effectiveUserId = getEffectiveUserId(userId);
@@ -872,7 +966,7 @@
@Override // Binder call
public boolean hasEnrolledFingerprints(int userId, String opPackageName) {
- if (!canUseFingerprint(opPackageName)) {
+ if (!canUseFingerprint(opPackageName, false /* foregroundOnly */)) {
return false;
}
@@ -922,7 +1016,19 @@
public void resetTimeout(byte [] token) {
checkPermission(RESET_FINGERPRINT_LOCKOUT);
// TODO: confirm security token when we move timeout management into the HAL layer.
- mLockoutReset.run();
+ mHandler.post(mLockoutReset);
+ }
+
+ @Override
+ public void addLockoutResetCallback(final IFingerprintServiceLockoutResetCallback callback)
+ throws RemoteException {
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ addLockoutResetMonitor(
+ new FingerprintServiceLockoutResetMonitor(callback));
+ }
+ });
}
}
diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java
index 17b4f9c..5a13672 100644
--- a/services/core/java/com/android/server/input/InputManagerService.java
+++ b/services/core/java/com/android/server/input/InputManagerService.java
@@ -17,6 +17,7 @@
package com.android.server.input;
import android.view.Display;
+import com.android.internal.os.SomeArgs;
import com.android.internal.R;
import com.android.internal.util.XmlUtils;
import com.android.server.DisplayThread;
@@ -52,6 +53,7 @@
import android.hardware.input.InputDeviceIdentifier;
import android.hardware.input.InputManager;
import android.hardware.input.InputManagerInternal;
+import android.hardware.input.ITabletModeChangedListener;
import android.hardware.input.KeyboardLayout;
import android.hardware.input.TouchCalibration;
import android.os.Binder;
@@ -93,6 +95,7 @@
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
+import java.util.List;
import libcore.io.Streams;
import libcore.util.Objects;
@@ -112,6 +115,7 @@
private static final int MSG_RELOAD_KEYBOARD_LAYOUTS = 3;
private static final int MSG_UPDATE_KEYBOARD_LAYOUTS = 4;
private static final int MSG_RELOAD_DEVICE_ALIASES = 5;
+ private static final int MSG_DELIVER_TABLET_MODE_CHANGED = 6;
// Pointer to native input manager service object.
private final long mPtr;
@@ -124,6 +128,13 @@
private boolean mSystemReady;
private NotificationManager mNotificationManager;
+ private final Object mTabletModeLock = new Object();
+ // List of currently registered tablet mode changed listeners by process id
+ private final SparseArray<TabletModeChangedListenerRecord> mTabletModeChangedListeners =
+ new SparseArray<>(); // guarded by mTabletModeLock
+ private final List<TabletModeChangedListenerRecord> mTempTabletModeChangedListenersToNotify =
+ new ArrayList<>();
+
// Persistent data store. Must be locked each time during use.
private final PersistentDataStore mDataStore = new PersistentDataStore();
@@ -227,6 +238,11 @@
/** Switch code: Lid switch. When set, lid is shut. */
public static final int SW_LID = 0x00;
+ /** Switch code: Tablet mode switch.
+ * When set, the device is in tablet mode (i.e. no keyboard is connected).
+ */
+ public static final int SW_TABLET_MODE = 0x01;
+
/** Switch code: Keypad slide. When set, keyboard is exposed. */
public static final int SW_KEYPAD_SLIDE = 0x0a;
@@ -246,6 +262,7 @@
public static final int SW_CAMERA_LENS_COVER = 0x09;
public static final int SW_LID_BIT = 1 << SW_LID;
+ public static final int SW_TABLET_MODE_BIT = 1 << SW_TABLET_MODE;
public static final int SW_KEYPAD_SLIDE_BIT = 1 << SW_KEYPAD_SLIDE;
public static final int SW_HEADPHONE_INSERT_BIT = 1 << SW_HEADPHONE_INSERT;
public static final int SW_MICROPHONE_INSERT_BIT = 1 << SW_MICROPHONE_INSERT;
@@ -774,6 +791,57 @@
}
}
+ @Override // Binder call
+ public void registerTabletModeChangedListener(ITabletModeChangedListener listener) {
+ if (!checkCallingPermission(android.Manifest.permission.TABLET_MODE_LISTENER,
+ "registerTabletModeChangedListener()")) {
+ throw new SecurityException("Requires TABLET_MODE_LISTENER permission");
+ }
+ if (listener == null) {
+ throw new IllegalArgumentException("listener must not be null");
+ }
+
+ synchronized (mTabletModeLock) {
+ final int callingPid = Binder.getCallingPid();
+ if (mTabletModeChangedListeners.get(callingPid) != null) {
+ throw new IllegalStateException("The calling process has already registered "
+ + "a TabletModeChangedListener.");
+ }
+ TabletModeChangedListenerRecord record =
+ new TabletModeChangedListenerRecord(callingPid, listener);
+ try {
+ IBinder binder = listener.asBinder();
+ binder.linkToDeath(record, 0);
+ } catch (RemoteException ex) {
+ throw new RuntimeException(ex);
+ }
+ mTabletModeChangedListeners.put(callingPid, record);
+ }
+ }
+
+ private void onTabletModeChangedListenerDied(int pid) {
+ synchronized (mTabletModeLock) {
+ mTabletModeChangedListeners.remove(pid);
+ }
+ }
+
+ // Must be called on handler
+ private void deliverTabletModeChanged(long whenNanos, boolean inTabletMode) {
+ mTempTabletModeChangedListenersToNotify.clear();
+ final int numListeners;
+ synchronized (mTabletModeLock) {
+ numListeners = mTabletModeChangedListeners.size();
+ for (int i = 0; i < numListeners; i++) {
+ mTempTabletModeChangedListenersToNotify.add(
+ mTabletModeChangedListeners.valueAt(i));
+ }
+ }
+ for (int i = 0; i < numListeners; i++) {
+ mTempTabletModeChangedListenersToNotify.get(i).notifyTabletModeChanged(
+ whenNanos, inTabletMode);
+ }
+ }
+
// Must be called on handler.
private void showMissingKeyboardLayoutNotification(InputDevice device) {
if (!mKeyboardLayoutNotificationShown) {
@@ -1419,6 +1487,15 @@
mWiredAccessoryCallbacks.notifyWiredAccessoryChanged(whenNanos, switchValues,
switchMask);
}
+
+ if ((switchMask & SW_TABLET_MODE) != 0) {
+ SomeArgs args = SomeArgs.obtain();
+ args.argi1 = (int) (whenNanos & 0xFFFFFFFF);
+ args.argi2 = (int) (whenNanos >> 32);
+ args.arg1 = Boolean.valueOf((switchValues & SW_TABLET_MODE_BIT) != 0);
+ mHandler.obtainMessage(MSG_DELIVER_TABLET_MODE_CHANGED,
+ args).sendToTarget();
+ }
}
// Native callback.
@@ -1664,6 +1741,12 @@
case MSG_RELOAD_DEVICE_ALIASES:
reloadDeviceAliases();
break;
+ case MSG_DELIVER_TABLET_MODE_CHANGED:
+ SomeArgs args = (SomeArgs) msg.obj;
+ long whenNanos = (args.argi1 & 0xFFFFFFFFl) | ((long) args.argi2 << 32);
+ boolean inTabletMode = (boolean) args.arg1;
+ deliverTabletModeChanged(whenNanos, inTabletMode);
+ break;
}
}
}
@@ -1755,6 +1838,34 @@
}
}
+ private final class TabletModeChangedListenerRecord implements DeathRecipient {
+ private final int mPid;
+ private final ITabletModeChangedListener mListener;
+
+ public TabletModeChangedListenerRecord(int pid, ITabletModeChangedListener listener) {
+ mPid = pid;
+ mListener = listener;
+ }
+
+ @Override
+ public void binderDied() {
+ if (DEBUG) {
+ Slog.d(TAG, "Tablet mode changed listener for pid " + mPid + " died.");
+ }
+ onTabletModeChangedListenerDied(mPid);
+ }
+
+ public void notifyTabletModeChanged(long whenNanos, boolean inTabletMode) {
+ try {
+ mListener.onTabletModeChanged(whenNanos, inTabletMode);
+ } catch (RemoteException ex) {
+ Slog.w(TAG, "Failed to notify process " + mPid +
+ " that tablet mode changed, assuming it died.", ex);
+ binderDied();
+ }
+ }
+ }
+
private final class VibratorToken implements DeathRecipient {
public final int mDeviceId;
public final IBinder mToken;
diff --git a/services/core/java/com/android/server/location/GpsLocationProvider.java b/services/core/java/com/android/server/location/GpsLocationProvider.java
index 02f2c73..4f42f83 100644
--- a/services/core/java/com/android/server/location/GpsLocationProvider.java
+++ b/services/core/java/com/android/server/location/GpsLocationProvider.java
@@ -444,7 +444,8 @@
checkSmsSuplInit(intent);
} else if (action.equals(Intents.WAP_PUSH_RECEIVED_ACTION)) {
checkWapSuplInit(intent);
- } else if (action.equals(ConnectivityManager.CONNECTIVITY_ACTION)) {
+ } else if (action.equals(ConnectivityManager.CONNECTIVITY_ACTION)
+ || action.equals(ConnectivityManager.CONNECTIVITY_ACTION_SUPL)) {
// retrieve NetworkInfo result for this UID
NetworkInfo info =
intent.getParcelableExtra(ConnectivityManager.EXTRA_NETWORK_INFO);
@@ -2049,6 +2050,7 @@
intentFilter.addAction(ALARM_WAKEUP);
intentFilter.addAction(ALARM_TIMEOUT);
intentFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
+ intentFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION_SUPL);
intentFilter.addAction(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED);
intentFilter.addAction(PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED);
intentFilter.addAction(Intent.ACTION_SCREEN_OFF);
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 7112fc8..96c54605 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -2283,16 +2283,16 @@
}
updatePermissionsLPw(null, null, updateFlags);
ver.sdkVersion = mSdkVersion;
- // clear only after permissions have been updated
- mExistingSystemPackages.clear();
- mPromoteSystemApps = false;
- // If this is the first boot, and it is a normal boot, then
- // we need to initialize the default preferred apps.
- if (!mRestoredSettings && !onlyCore) {
- mSettings.applyDefaultPreferredAppsLPw(this, UserHandle.USER_OWNER);
- applyFactoryDefaultBrowserLPw(UserHandle.USER_OWNER);
- primeDomainVerificationsLPw(UserHandle.USER_OWNER);
+ // If this is the first boot or an update from pre-M, and it is a normal
+ // boot, then we need to initialize the default preferred apps across
+ // all defined users.
+ if (!onlyCore && (mPromoteSystemApps || !mRestoredSettings)) {
+ for (UserInfo user : sUserManager.getUsers(true)) {
+ mSettings.applyDefaultPreferredAppsLPw(this, user.id);
+ applyFactoryDefaultBrowserLPw(user.id);
+ primeDomainVerificationsLPw(user.id);
+ }
}
// If this is first boot after an OTA, and a normal boot, then
@@ -2310,6 +2310,10 @@
checkDefaultBrowser();
+ // clear only after permissions and other defaults have been updated
+ mExistingSystemPackages.clear();
+ mPromoteSystemApps = false;
+
// All the changes are done during package scanning.
ver.databaseVersion = Settings.CURRENT_DATABASE_VERSION;
@@ -5929,12 +5933,6 @@
*/
if (shouldHideSystemApp) {
synchronized (mPackages) {
- /*
- * We have to grant systems permissions before we hide, because
- * grantPermissions will assume the package update is trying to
- * expand its permissions.
- */
- grantPermissionsLPw(pkg, true, pkg.packageName);
mSettings.disableSystemPackageLPw(pkg.packageName);
}
}
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index d7c9c02..34737c1 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -4417,7 +4417,7 @@
if (mAppsToBeHidden.isEmpty()) {
if (dismissKeyguard && !mKeyguardSecure) {
mAppsThatDismissKeyguard.add(appToken);
- } else if (win.isDrawnLw()) {
+ } else if (win.isDrawnLw() || win.hasAppShownWindows()) {
mWinShowWhenLocked = win;
mHideLockScreen = true;
mForceStatusBarFromKeyguard = false;
@@ -4451,7 +4451,8 @@
mWinDismissingKeyguard = win;
mSecureDismissingKeyguard = mKeyguardSecure;
mForceStatusBarFromKeyguard = mShowingLockscreen && mKeyguardSecure;
- } else if (mAppsToBeHidden.isEmpty() && showWhenLocked && win.isDrawnLw()) {
+ } else if (mAppsToBeHidden.isEmpty() && showWhenLocked
+ && (win.isDrawnLw() || win.hasAppShownWindows())) {
if (DEBUG_LAYOUT) Slog.v(TAG,
"Setting mHideLockScreen to true by win " + win);
mHideLockScreen = true;
diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java
index 3da9b44..ba608bd 100644
--- a/services/core/java/com/android/server/wm/TaskStack.java
+++ b/services/core/java/com/android/server/wm/TaskStack.java
@@ -375,7 +375,10 @@
for (int appNdx = appWindowTokens.size() - 1; appNdx >= 0; --appNdx) {
final WindowList appWindows = appWindowTokens.get(appNdx).allAppWindows;
for (int winNdx = appWindows.size() - 1; winNdx >= 0; --winNdx) {
- mService.removeWindowInnerLocked(appWindows.get(winNdx));
+ // We are in the middle of changing the state of displays/stacks/tasks. We need
+ // to finish that, before we let layout interfere with it.
+ mService.removeWindowInnerLocked(appWindows.get(winNdx),
+ false /* performLayout */);
doAnotherLayoutPass = true;
}
}
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 33d4331..a0499b7 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -2793,6 +2793,10 @@
}
void removeWindowInnerLocked(WindowState win) {
+ removeWindowInnerLocked(win, true);
+ }
+
+ void removeWindowInnerLocked(WindowState win, boolean performLayout) {
if (win.mRemoved) {
// Nothing to do.
return;
@@ -2890,7 +2894,9 @@
if (displayContent != null) {
displayContent.layoutNeeded = true;
}
- performLayoutAndPlaceSurfacesLocked();
+ if (performLayout) {
+ performLayoutAndPlaceSurfacesLocked();
+ }
if (win.mAppToken != null) {
win.mAppToken.updateReportedVisibilityLocked();
}
@@ -5193,7 +5199,9 @@
}
public void removeStack(int stackId) {
- mStackIdToStack.remove(stackId);
+ synchronized (mWindowMap) {
+ mStackIdToStack.remove(stackId);
+ }
}
public void removeTask(int taskId) {
@@ -5267,10 +5275,12 @@
}
public void getStackBounds(int stackId, Rect bounds) {
- final TaskStack stack = mStackIdToStack.get(stackId);
- if (stack != null) {
- stack.getBounds(bounds);
- return;
+ synchronized (mWindowMap) {
+ final TaskStack stack = mStackIdToStack.get(stackId);
+ if (stack != null) {
+ stack.getBounds(bounds);
+ return;
+ }
}
bounds.setEmpty();
}
diff --git a/services/core/jni/Android.mk b/services/core/jni/Android.mk
index 9556b08..98d8d08 100644
--- a/services/core/jni/Android.mk
+++ b/services/core/jni/Android.mk
@@ -4,9 +4,16 @@
LOCAL_CFLAGS += -Wall -Werror -Wno-unused-parameter
+ifneq ($(ENABLE_CPUSETS),)
+ifneq ($(ENABLE_SCHED_BOOST),)
+LOCAL_CFLAGS += -DUSE_SCHED_BOOST
+endif
+endif
+
LOCAL_SRC_FILES += \
$(LOCAL_REL_DIR)/com_android_server_AlarmManagerService.cpp \
$(LOCAL_REL_DIR)/com_android_server_am_BatteryStatsService.cpp \
+ $(LOCAL_REL_DIR)/com_android_server_am_ActivityManagerService.cpp \
$(LOCAL_REL_DIR)/com_android_server_AssetAtlasService.cpp \
$(LOCAL_REL_DIR)/com_android_server_connectivity_Vpn.cpp \
$(LOCAL_REL_DIR)/com_android_server_ConsumerIrService.cpp \
diff --git a/services/core/jni/com_android_server_am_ActivityManagerService.cpp b/services/core/jni/com_android_server_am_ActivityManagerService.cpp
new file mode 100644
index 0000000..52217b9
--- /dev/null
+++ b/services/core/jni/com_android_server_am_ActivityManagerService.cpp
@@ -0,0 +1,151 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "ActivityManagerService"
+//#define LOG_NDEBUG 0
+
+#include <android_runtime/AndroidRuntime.h>
+#include <jni.h>
+
+#include <ScopedLocalRef.h>
+#include <ScopedPrimitiveArray.h>
+
+#include <cutils/log.h>
+#include <utils/misc.h>
+#include <utils/Log.h>
+
+#include <stdio.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <semaphore.h>
+#include <stddef.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+namespace android
+{
+
+ // migrate from foreground to foreground_boost
+ static jint migrateToBoost(JNIEnv *env, jobject _this)
+ {
+#ifdef USE_SCHED_BOOST
+ // File descriptors open to /dev/cpuset/../tasks, setup by initialize, or -1 on error
+ FILE* fg_cpuset_file = NULL;
+ int boost_cpuset_fd = 0;
+ if (!access("/dev/cpuset/tasks", F_OK)) {
+ fg_cpuset_file = fopen("/dev/cpuset/foreground/tasks", "r+");
+ if (ferror(fg_cpuset_file)) {
+ return 0;
+ }
+ boost_cpuset_fd = open("/dev/cpuset/foreground/boost/tasks", O_WRONLY);
+ if (boost_cpuset_fd < 0) {
+ fclose(fg_cpuset_file);
+ return 0;
+ }
+
+ }
+ if (!fg_cpuset_file || !boost_cpuset_fd) {
+ fclose(fg_cpuset_file);
+ close(boost_cpuset_fd);
+ return 0;
+ }
+ char buf[17];
+ while (fgets(buf, 16, fg_cpuset_file)) {
+ int i = 0;
+ for (; i < 16; i++) {
+ if (buf[i] == '\n') {
+ buf[i] = 0;
+ break;
+ }
+ }
+ if (write(boost_cpuset_fd, buf, i) < 0) {
+ // ignore error
+ }
+ if (feof(fg_cpuset_file))
+ break;
+ }
+ fclose(fg_cpuset_file);
+ close(boost_cpuset_fd);
+#endif
+ return 0;
+ }
+
+ // migrate from foreground_boost to foreground
+ static jint migrateFromBoost(JNIEnv *env, jobject _this)
+ {
+#ifdef USE_SCHED_BOOST
+ // File descriptors open to /dev/cpuset/../tasks, setup by initialize, or -1 on error
+ int fg_cpuset_fd = 0;
+ FILE* boost_cpuset_file = NULL;
+ if (!access("/dev/cpuset/tasks", F_OK)) {
+ boost_cpuset_file = fopen("/dev/cpuset/foreground/boost/tasks", "r+");
+ if (ferror(boost_cpuset_file)) {
+ return 0;
+ }
+ fg_cpuset_fd = open("/dev/cpuset/foreground/tasks", O_WRONLY);
+ if (fg_cpuset_fd < 0) {
+ fclose(boost_cpuset_file);
+ return 0;
+ }
+
+ }
+ if (!boost_cpuset_file || !fg_cpuset_fd) {
+ fclose(boost_cpuset_file);
+ close(fg_cpuset_fd);
+ return 0;
+ }
+ char buf[17];
+ char *curBuf = buf;
+ while (fgets(buf, 16, boost_cpuset_file)) {
+ //ALOGE("Appending FD %s to fg", buf);
+ int i = 0;
+ for (; i < 16; i++) {
+ if (buf[i] == '\n') {
+ buf[i] = 0;
+ break;
+ }
+ }
+ if (write(fg_cpuset_fd, buf, i) < 0) {
+ //ALOGE("Appending FD %s to fg ERROR", buf);
+ // handle error?
+ }
+ if (feof(boost_cpuset_file))
+ break;
+ }
+
+ close(fg_cpuset_fd);
+ fclose(boost_cpuset_file);
+
+#endif
+ return 0;
+
+ }
+
+
+ static JNINativeMethod method_table[] = {
+ { "nativeMigrateToBoost", "()I", (void*)migrateToBoost },
+ { "nativeMigrateFromBoost", "()I", (void*)migrateFromBoost },
+ };
+
+ int register_android_server_ActivityManagerService(JNIEnv *env)
+ {
+ return jniRegisterNativeMethods(env, "com/android/server/am/ActivityManagerService",
+ method_table, NELEM(method_table));
+ }
+
+}
diff --git a/services/core/jni/onload.cpp b/services/core/jni/onload.cpp
index 67872da..1f3fde6 100644
--- a/services/core/jni/onload.cpp
+++ b/services/core/jni/onload.cpp
@@ -20,6 +20,7 @@
#include "utils/misc.h"
namespace android {
+int register_android_server_ActivityManagerService(JNIEnv* env);
int register_android_server_AlarmManagerService(JNIEnv* env);
int register_android_server_AssetAtlasService(JNIEnv* env);
int register_android_server_BatteryStatsService(JNIEnv* env);
@@ -57,6 +58,7 @@
}
ALOG_ASSERT(env, "Could not retrieve the env!");
+ register_android_server_ActivityManagerService(env);
register_android_server_PowerManagerService(env);
register_android_server_SerialService(env);
register_android_server_InputApplicationHandle(env);
@@ -80,5 +82,6 @@
register_android_server_PersistentDataBlockService(env);
register_android_server_Watchdog(env);
+
return JNI_VERSION_1_4;
}
diff --git a/services/net/java/android/net/dhcp/DhcpPacket.java b/services/net/java/android/net/dhcp/DhcpPacket.java
index a91ddb8..cbf8fc2 100644
--- a/services/net/java/android/net/dhcp/DhcpPacket.java
+++ b/services/net/java/android/net/dhcp/DhcpPacket.java
@@ -55,6 +55,7 @@
public static final int MIN_PACKET_LENGTH_L3 = MIN_PACKET_LENGTH_BOOTP + 20 + 8;
public static final int MIN_PACKET_LENGTH_L2 = MIN_PACKET_LENGTH_L3 + 14;
+ public static final int HWADDR_LEN = 16;
public static final int MAX_OPTION_LEN = 255;
/**
* IP layer definitions.
@@ -399,7 +400,7 @@
buf.put(mRelayIp.getAddress());
buf.put(mClientMac);
buf.position(buf.position() +
- (16 - mClientMac.length) // pad addr to 16 bytes
+ (HWADDR_LEN - mClientMac.length) // pad addr to 16 bytes
+ 64 // empty server host name (64 bytes)
+ 128); // empty boot file name (128 bytes)
buf.putInt(0x63825363); // magic number
@@ -786,7 +787,7 @@
byte type = packet.get();
byte hwType = packet.get();
- byte addrLen = packet.get();
+ int addrLen = packet.get() & 0xff;
byte hops = packet.get();
transactionId = packet.getInt();
secs = packet.getShort();
@@ -807,6 +808,16 @@
return null;
}
+ // Some DHCP servers have been known to announce invalid client hardware address values such
+ // as 0xff. The legacy DHCP client accepted these becuause it does not check the length at
+ // all but only checks that the interface MAC address matches the first bytes of the address
+ // in the packets. We're a bit stricter: if the length is obviously invalid (i.e., bigger
+ // than the size of the field), we fudge it to 6 (Ethernet). http://b/23725795
+ // TODO: evaluate whether to make this test more liberal.
+ if (addrLen > HWADDR_LEN) {
+ addrLen = ETHER_BROADCAST.length;
+ }
+
clientMac = new byte[addrLen];
packet.get(clientMac);
diff --git a/services/tests/servicestests/src/android/net/dhcp/DhcpPacketTest.java b/services/tests/servicestests/src/android/net/dhcp/DhcpPacketTest.java
index da1df1a..cd3b8bb 100644
--- a/services/tests/servicestests/src/android/net/dhcp/DhcpPacketTest.java
+++ b/services/tests/servicestests/src/android/net/dhcp/DhcpPacketTest.java
@@ -333,6 +333,76 @@
}
@SmallTest
+ public void testBadHwaddrLength() throws Exception {
+ final ByteBuffer packet = ByteBuffer.wrap(HexEncoding.decode((
+ // IP header.
+ "450001518d0600004011144dc0a82b01c0a82bf7" +
+ // UDP header.
+ "00430044013d9ac7" +
+ // BOOTP header.
+ "02010600dfc23d1f0002000000000000c0a82bf7c0a82b0100000000" +
+ // MAC address.
+ "30766ff2a90c00000000000000000000" +
+ // Server name.
+ "0000000000000000000000000000000000000000000000000000000000000000" +
+ "0000000000000000000000000000000000000000000000000000000000000000" +
+ // File.
+ "0000000000000000000000000000000000000000000000000000000000000000" +
+ "0000000000000000000000000000000000000000000000000000000000000000" +
+ "0000000000000000000000000000000000000000000000000000000000000000" +
+ "0000000000000000000000000000000000000000000000000000000000000000" +
+ // Options
+ "638253633501023604c0a82b01330400000e103a04000007083b0400000c4e0104ffffff00" +
+ "1c04c0a82bff0304c0a82b010604c0a82b012b0f414e44524f49445f4d455445524544ff"
+ ).toCharArray(), false));
+ String expectedClientMac = "30766FF2A90C";
+
+ final int hwAddrLenOffset = 20 + 8 + 2;
+ assertEquals(6, packet.get(hwAddrLenOffset));
+
+ // Expect the expected.
+ DhcpPacket offerPacket = DhcpPacket.decodeFullPacket(packet, ENCAP_L3);
+ assertNotNull(offerPacket);
+ assertEquals(6, offerPacket.getClientMac().length);
+ assertEquals(expectedClientMac, HexDump.toHexString(offerPacket.getClientMac()));
+
+ // Reduce the hardware address length and verify that it shortens the client MAC.
+ packet.flip();
+ packet.put(hwAddrLenOffset, (byte) 5);
+ offerPacket = DhcpPacket.decodeFullPacket(packet, ENCAP_L3);
+ assertNotNull(offerPacket);
+ assertEquals(5, offerPacket.getClientMac().length);
+ assertEquals(expectedClientMac.substring(0, 10),
+ HexDump.toHexString(offerPacket.getClientMac()));
+
+ packet.flip();
+ packet.put(hwAddrLenOffset, (byte) 3);
+ offerPacket = DhcpPacket.decodeFullPacket(packet, ENCAP_L3);
+ assertNotNull(offerPacket);
+ assertEquals(3, offerPacket.getClientMac().length);
+ assertEquals(expectedClientMac.substring(0, 6),
+ HexDump.toHexString(offerPacket.getClientMac()));
+
+ // Set the the hardware address length to 0xff and verify that we a) don't treat it as -1
+ // and crash, and b) hardcode it to 6.
+ packet.flip();
+ packet.put(hwAddrLenOffset, (byte) -1);
+ offerPacket = DhcpPacket.decodeFullPacket(packet, ENCAP_L3);
+ assertNotNull(offerPacket);
+ assertEquals(6, offerPacket.getClientMac().length);
+ assertEquals(expectedClientMac, HexDump.toHexString(offerPacket.getClientMac()));
+
+ // Set the the hardware address length to a positive invalid value (> 16) and verify that we
+ // hardcode it to 6.
+ packet.flip();
+ packet.put(hwAddrLenOffset, (byte) 17);
+ offerPacket = DhcpPacket.decodeFullPacket(packet, ENCAP_L3);
+ assertNotNull(offerPacket);
+ assertEquals(6, offerPacket.getClientMac().length);
+ assertEquals(expectedClientMac, HexDump.toHexString(offerPacket.getClientMac()));
+ }
+
+ @SmallTest
public void testPadAndOverloadedOptionsOffer() throws Exception {
// A packet observed in the real world that is interesting for two reasons:
//
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 62e532e..df8affe 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -411,7 +411,7 @@
* @hide
*/
public static final String KEY_ALLOW_NON_EMERGENCY_CALLS_IN_ECM_BOOL =
- "allowNonEmergencyCallsInEcm";
+ "allow_non_emergency_calls_in_ecm_bool";
/** The default value for every variable. */
private final static PersistableBundle sDefaults;
diff --git a/telephony/java/android/telephony/PhoneNumberUtils.java b/telephony/java/android/telephony/PhoneNumberUtils.java
index 273cc93..b430340 100644
--- a/telephony/java/android/telephony/PhoneNumberUtils.java
+++ b/telephony/java/android/telephony/PhoneNumberUtils.java
@@ -1457,10 +1457,15 @@
String result = null;
try {
PhoneNumber pn = util.parseAndKeepRawInput(phoneNumber, defaultCountryIso);
+ /**
+ * Need to reformat any local Korean phone numbers (when the user is in Korea) with
+ * country code to corresponding national format which would replace the leading
+ * +82 with 0.
+ */
if (KOREA_ISO_COUNTRY_CODE.equals(defaultCountryIso) &&
- (pn.getCountryCode() == util.getCountryCodeForRegion(KOREA_ISO_COUNTRY_CODE))) {
- // Format local Korean phone numbers with country code to corresponding national
- // format which would replace the leading +82 with 0.
+ (pn.getCountryCode() == util.getCountryCodeForRegion(KOREA_ISO_COUNTRY_CODE)) &&
+ (pn.getCountryCodeSource() ==
+ PhoneNumber.CountryCodeSource.FROM_NUMBER_WITH_PLUS_SIGN)) {
result = util.format(pn, PhoneNumberUtil.PhoneNumberFormat.NATIONAL);
} else {
result = util.formatInOriginalFormat(pn, defaultCountryIso);
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
index 1f3802e..689e359 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
@@ -36,8 +36,8 @@
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
-import android.annotation.Nullable;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.ContentResolver;
@@ -139,8 +139,9 @@
private Map<StyleResourceValue, Integer> mStyleToDynamicIdMap;
private int mDynamicIdGenerator = 0x02030000; // Base id for R.style in custom namespace
- // cache for TypedArray generated from IStyleResourceValue object
- private Map<int[], Map<Integer, BridgeTypedArray>> mTypedArrayCache;
+ // cache for TypedArray generated from StyleResourceValue object
+ private Map<int[], Map<List<StyleResourceValue>, Map<Integer, BridgeTypedArray>>>
+ mTypedArrayCache;
private BridgeInflater mBridgeInflater;
private BridgeContentResolver mContentResolver;
@@ -621,31 +622,38 @@
}
}
+ // The map is from
+ // attrs (int[]) -> context's current themes (List<StyleRV>) -> resid (int) -> typed array.
if (mTypedArrayCache == null) {
- mTypedArrayCache = new HashMap<int[], Map<Integer,BridgeTypedArray>>();
-
- Map<Integer, BridgeTypedArray> map = new HashMap<Integer, BridgeTypedArray>();
- mTypedArrayCache.put(attrs, map);
-
- BridgeTypedArray ta = createStyleBasedTypedArray(style, attrs);
- map.put(resid, ta);
-
- return ta;
+ mTypedArrayCache = new IdentityHashMap<int[],
+ Map<List<StyleResourceValue>, Map<Integer, BridgeTypedArray>>>();
}
// get the 2nd map
- Map<Integer, BridgeTypedArray> map = mTypedArrayCache.get(attrs);
- if (map == null) {
- map = new HashMap<Integer, BridgeTypedArray>();
- mTypedArrayCache.put(attrs, map);
+ Map<List<StyleResourceValue>, Map<Integer, BridgeTypedArray>> map2 =
+ mTypedArrayCache.get(attrs);
+ if (map2 == null) {
+ map2 = new HashMap<List<StyleResourceValue>, Map<Integer, BridgeTypedArray>>();
+ mTypedArrayCache.put(attrs, map2);
}
- // get the array from the 2nd map
- BridgeTypedArray ta = map.get(resid);
+ // get the 3rd map
+ List<StyleResourceValue> currentThemes = mRenderResources.getAllThemes();
+ Map<Integer, BridgeTypedArray> map3 = map2.get(currentThemes);
+ if (map3 == null) {
+ map3 = new HashMap<Integer, BridgeTypedArray>();
+ // Create a copy of the list before adding it to the map. This allows reusing the
+ // existing list.
+ currentThemes = new ArrayList<StyleResourceValue>(currentThemes);
+ map2.put(currentThemes, map3);
+ }
+
+ // get the array from the 3rd map
+ BridgeTypedArray ta = map3.get(resid);
if (ta == null) {
ta = createStyleBasedTypedArray(style, attrs);
- map.put(resid, ta);
+ map3.put(resid, ta);
}
return ta;