Merge "Tune delivery and batching of alarms" into lmp-mr1-dev
diff --git a/Android.mk b/Android.mk
index ba45e6f..1416472 100644
--- a/Android.mk
+++ b/Android.mk
@@ -100,6 +100,7 @@
core/java/android/bluetooth/IBluetoothA2dpSink.aidl \
core/java/android/bluetooth/IBluetoothAvrcpController.aidl \
core/java/android/bluetooth/IBluetoothCallback.aidl \
+ core/java/android/bluetooth/IBluetoothProfileServiceConnection.aidl \
core/java/android/bluetooth/IBluetoothHeadset.aidl \
core/java/android/bluetooth/IBluetoothHeadsetPhone.aidl \
core/java/android/bluetooth/IBluetoothHealth.aidl \
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 4753099..ead89b3 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -504,6 +504,22 @@
}
return false;
}
+ /**
+ * Return true if the given administrator component is currently being removed
+ * for the user.
+ * @hide
+ */
+ public boolean isRemovingAdmin(ComponentName who, int userId) {
+ if (mService != null) {
+ try {
+ return mService.isRemovingAdmin(who, userId);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Failed talking with device policy service", e);
+ }
+ }
+ return false;
+ }
+
/**
* Return a list of all currently active device administrator's component
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index d144ae8..0ca60c0 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -196,4 +196,6 @@
void setAutoTimeRequired(in ComponentName who, int userHandle, boolean required);
boolean getAutoTimeRequired();
+
+ boolean isRemovingAdmin(in ComponentName adminReceiver, int userHandle);
}
diff --git a/core/java/android/bluetooth/BluetoothHeadset.java b/core/java/android/bluetooth/BluetoothHeadset.java
index 353f0fb..546a50e 100644
--- a/core/java/android/bluetooth/BluetoothHeadset.java
+++ b/core/java/android/bluetooth/BluetoothHeadset.java
@@ -20,9 +20,10 @@
import android.annotation.SdkConstant.SdkConstantType;
import android.content.ComponentName;
import android.content.Context;
-import android.content.Intent;
-import android.content.ServiceConnection;
+import android.os.Handler;
import android.os.IBinder;
+import android.os.Looper;
+import android.os.Message;
import android.os.RemoteException;
import android.util.Log;
@@ -221,11 +222,14 @@
*/
public static final int STATE_AUDIO_CONNECTED = 12;
+ private static final int MESSAGE_HEADSET_SERVICE_CONNECTED = 100;
+ private static final int MESSAGE_HEADSET_SERVICE_DISCONNECTED = 101;
private Context mContext;
private ServiceListener mServiceListener;
private IBluetoothHeadset mService;
private BluetoothAdapter mAdapter;
+ private boolean mIsClosed;
final private IBluetoothStateChangeCallback mBluetoothStateChangeCallback =
new IBluetoothStateChangeCallback.Stub() {
@@ -233,14 +237,7 @@
if (DBG) Log.d(TAG, "onBluetoothStateChange: up=" + up);
if (!up) {
if (VDBG) Log.d(TAG,"Unbinding service...");
- synchronized (mConnection) {
- try {
- mService = null;
- mContext.unbindService(mConnection);
- } catch (Exception re) {
- Log.e(TAG,"",re);
- }
- }
+ doUnbind();
} else {
synchronized (mConnection) {
try {
@@ -263,6 +260,7 @@
mContext = context;
mServiceListener = l;
mAdapter = BluetoothAdapter.getDefaultAdapter();
+ mIsClosed = false;
IBluetoothManager mgr = mAdapter.getBluetoothManager();
if (mgr != null) {
@@ -277,15 +275,26 @@
}
boolean doBind() {
- Intent intent = new Intent(IBluetoothHeadset.class.getName());
- ComponentName comp = intent.resolveSystemService(mContext.getPackageManager(), 0);
- intent.setComponent(comp);
- if (comp == null || !mContext.bindServiceAsUser(intent, mConnection, 0,
- android.os.Process.myUserHandle())) {
- Log.e(TAG, "Could not bind to Bluetooth Headset Service with " + intent);
- return false;
+ try {
+ return mAdapter.getBluetoothManager().bindBluetoothProfileService(
+ BluetoothProfile.HEADSET, mConnection);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Unable to bind HeadsetService", e);
}
- return true;
+ return false;
+ }
+
+ void doUnbind() {
+ synchronized (mConnection) {
+ if (mService != null) {
+ try {
+ mAdapter.getBluetoothManager().unbindBluetoothProfileService(
+ BluetoothProfile.HEADSET, mConnection);
+ } catch (RemoteException e) {
+ Log.e(TAG,"Unable to unbind HeadsetService", e);
+ }
+ }
+ }
}
/**
@@ -305,18 +314,8 @@
Log.e(TAG,"",e);
}
}
-
- synchronized (mConnection) {
- if (mService != null) {
- try {
- mService = null;
- mContext.unbindService(mConnection);
- } catch (Exception re) {
- Log.e(TAG,"",re);
- }
- }
- }
- mServiceListener = null;
+ mIsClosed = true;
+ doUnbind();
}
/**
@@ -930,21 +929,21 @@
return false;
}
- private final ServiceConnection mConnection = new ServiceConnection() {
+ private final IBluetoothProfileServiceConnection mConnection
+ = new IBluetoothProfileServiceConnection.Stub() {
+ @Override
public void onServiceConnected(ComponentName className, IBinder service) {
if (DBG) Log.d(TAG, "Proxy object connected");
mService = IBluetoothHeadset.Stub.asInterface(service);
-
- if (mServiceListener != null) {
- mServiceListener.onServiceConnected(BluetoothProfile.HEADSET, BluetoothHeadset.this);
- }
+ mHandler.sendMessage(mHandler.obtainMessage(
+ MESSAGE_HEADSET_SERVICE_CONNECTED));
}
+ @Override
public void onServiceDisconnected(ComponentName className) {
if (DBG) Log.d(TAG, "Proxy object disconnected");
mService = null;
- if (mServiceListener != null) {
- mServiceListener.onServiceDisconnected(BluetoothProfile.HEADSET);
- }
+ mHandler.sendMessage(mHandler.obtainMessage(
+ MESSAGE_HEADSET_SERVICE_DISCONNECTED));
}
};
@@ -968,4 +967,28 @@
private static void log(String msg) {
Log.d(TAG, msg);
}
+
+ private final Handler mHandler = new Handler(Looper.getMainLooper()) {
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case MESSAGE_HEADSET_SERVICE_CONNECTED: {
+ if (mServiceListener != null) {
+ mServiceListener.onServiceConnected(BluetoothProfile.HEADSET,
+ BluetoothHeadset.this);
+ }
+ break;
+ }
+ case MESSAGE_HEADSET_SERVICE_DISCONNECTED: {
+ if (mServiceListener != null) {
+ mServiceListener.onServiceDisconnected(BluetoothProfile.HEADSET);
+ }
+ if (mIsClosed){
+ mServiceListener = null;
+ }
+ break;
+ }
+ }
+ }
+ };
}
diff --git a/core/java/android/bluetooth/BluetoothUuid.java b/core/java/android/bluetooth/BluetoothUuid.java
index 1e22eb3..194a53e 100644
--- a/core/java/android/bluetooth/BluetoothUuid.java
+++ b/core/java/android/bluetooth/BluetoothUuid.java
@@ -66,6 +66,8 @@
ParcelUuid.fromString("00001116-0000-1000-8000-00805F9B34FB");
public static final ParcelUuid BNEP =
ParcelUuid.fromString("0000000f-0000-1000-8000-00805F9B34FB");
+ public static final ParcelUuid PBAP_PCE =
+ ParcelUuid.fromString("0000112e-0000-1000-8000-00805F9B34FB");
public static final ParcelUuid PBAP_PSE =
ParcelUuid.fromString("0000112f-0000-1000-8000-00805F9B34FB");
public static final ParcelUuid MAP =
diff --git a/core/java/android/bluetooth/IBluetoothManager.aidl b/core/java/android/bluetooth/IBluetoothManager.aidl
index 493d2f8..7411d3f 100644
--- a/core/java/android/bluetooth/IBluetoothManager.aidl
+++ b/core/java/android/bluetooth/IBluetoothManager.aidl
@@ -19,6 +19,7 @@
import android.bluetooth.IBluetooth;
import android.bluetooth.IBluetoothGatt;
import android.bluetooth.IBluetoothManagerCallback;
+import android.bluetooth.IBluetoothProfileServiceConnection;
import android.bluetooth.IBluetoothStateChangeCallback;
/**
@@ -38,6 +39,9 @@
boolean disable(boolean persist);
IBluetoothGatt getBluetoothGatt();
+ boolean bindBluetoothProfileService(int profile, IBluetoothProfileServiceConnection proxy);
+ void unbindBluetoothProfileService(int profile, IBluetoothProfileServiceConnection proxy);
+
String getAddress();
String getName();
}
diff --git a/core/java/android/bluetooth/IBluetoothProfileServiceConnection.aidl b/core/java/android/bluetooth/IBluetoothProfileServiceConnection.aidl
new file mode 100755
index 0000000..96c59e2
--- /dev/null
+++ b/core/java/android/bluetooth/IBluetoothProfileServiceConnection.aidl
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.bluetooth;
+
+import android.content.ComponentName;
+import android.os.IBinder;
+
+/**
+ * Callback for bluetooth profile connections.
+ *
+ * {@hide}
+ */
+interface IBluetoothProfileServiceConnection {
+ void onServiceConnected(in ComponentName comp, in IBinder service);
+ void onServiceDisconnected(in ComponentName comp);
+}
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index 4fe418a..4215f20 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -100,7 +100,7 @@
/**
* Identical to {@link #CONNECTIVITY_ACTION} broadcast, but sent without any
- * historic {@link Settings.Global#CONNECTIVITY_CHANGE_DELAY}.
+ * applicable {@link Settings.Global#CONNECTIVITY_CHANGE_DELAY}.
*
* @hide
*/
@@ -428,6 +428,18 @@
public static final int DEFAULT_NETWORK_PREFERENCE = TYPE_WIFI;
/**
+ * Default value for {@link Settings.Global#CONNECTIVITY_CHANGE_DELAY} in
+ * milliseconds. This was introduced because IPv6 routes seem to take a
+ * moment to settle - trying network activity before the routes are adjusted
+ * can lead to packets using the wrong interface or having the wrong IP address.
+ * This delay is a bit crude, but in the future hopefully we will have kernel
+ * notifications letting us know when it's safe to use the new network.
+ *
+ * @hide
+ */
+ public static final int CONNECTIVITY_CHANGE_DELAY_DEFAULT = 3000;
+
+ /**
* @hide
*/
public final static int REQUEST_ID_UNSET = 0;
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 3bc74ae..0c036d51 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -6118,7 +6118,7 @@
/**
* The number of milliseconds to delay before sending out
- * {@link ConnectivityManager#CONNECTIVITY_ACTION} broadcasts. Ignored.
+ * {@link ConnectivityManager#CONNECTIVITY_ACTION} broadcasts.
*
* @hide
*/
diff --git a/core/java/android/text/util/Linkify.java b/core/java/android/text/util/Linkify.java
index c1341e1..14be269 100644
--- a/core/java/android/text/util/Linkify.java
+++ b/core/java/android/text/util/Linkify.java
@@ -402,7 +402,7 @@
}
boolean hasPrefix = false;
-
+
for (int i = 0; i < prefixes.length; i++) {
if (url.regionMatches(true, 0, prefixes[i], 0,
prefixes[i].length())) {
@@ -450,7 +450,7 @@
private static final void gatherTelLinks(ArrayList<LinkSpec> links, Spannable s) {
PhoneNumberUtil phoneUtil = PhoneNumberUtil.getInstance();
Iterable<PhoneNumberMatch> matches = phoneUtil.findNumbers(s.toString(),
- Locale.getDefault().getCountry(), Leniency.POSSIBLE, Long.MAX_VALUE);
+ Locale.getDefault().getCountry(), Leniency.VALID, Long.MAX_VALUE);
for (PhoneNumberMatch match : matches) {
LinkSpec spec = new LinkSpec();
spec.url = "tel:" + PhoneNumberUtils.normalizeNumber(match.rawString());
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index f4f047e..094a8a1 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -1102,6 +1102,13 @@
public static final int PRIVATE_FLAG_KEYGUARD = 0x00000400;
/**
+ * Flag that prevents the wallpaper behind the current window from receiving touch events.
+ *
+ * {@hide}
+ */
+ public static final int PRIVATE_FLAG_DISABLE_WALLPAPER_TOUCH_EVENTS = 0x00000800;
+
+ /**
* Control flags that are private to the platform.
* @hide
*/
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 3dd9770..3fdaaa6 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -2914,7 +2914,8 @@
Any service that filters for this intent must be a carrier privileged app. -->
<permission android:name="android.permission.BIND_CARRIER_MESSAGING_SERVICE"
android:label="@string/permlab_bindCarrierMessagingService"
- android:description="@string/permdesc_bindCarrierMessagingService" />
+ android:description="@string/permdesc_bindCarrierMessagingService"
+ android:protectionLevel="signature|system" />
<!-- The system process is explicitly the only one allowed to launch the
confirmation UI for full backup/restore -->
diff --git a/data/fonts/fallback_fonts.xml b/data/fonts/fallback_fonts.xml
index 0244891..f94fe66 100644
--- a/data/fonts/fallback_fonts.xml
+++ b/data/fonts/fallback_fonts.xml
@@ -229,6 +229,12 @@
</family>
<family>
<fileset>
+ <file>NotoSansCham-Regular.ttf</file>
+ <file>NotoSansCham-Bold.ttf</file>
+ </fileset>
+ </family>
+ <family>
+ <fileset>
<file>NotoSansBalinese-Regular.ttf</file>
</fileset>
</family>
@@ -259,6 +265,16 @@
</family>
<family>
<fileset>
+ <file>NotoSansCoptic-Regular.ttf</file>
+ </fileset>
+ </family>
+ <family>
+ <fileset>
+ <file>NotoSansGlagolitic-Regular.ttf</file>
+ </fileset>
+ </family>
+ <family>
+ <fileset>
<file>NotoSansHanunoo-Regular.ttf</file>
</fileset>
</family>
@@ -269,6 +285,11 @@
</family>
<family>
<fileset>
+ <file>NotoSansKayahLi-Regular.ttf</file>
+ </fileset>
+ </family>
+ <family>
+ <fileset>
<file>NotoSansLepcha-Regular.ttf</file>
</fileset>
</family>
@@ -314,6 +335,26 @@
</family>
<family>
<fileset>
+ <file>NotoSansTaiLe-Regular.ttf</file>
+ </fileset>
+ </family>
+ <family>
+ <fileset>
+ <file>NotoSansTaiTham-Regular.ttf</file>
+ </fileset>
+ </family>
+ <family>
+ <fileset>
+ <file>NotoSansTaiViet-Regular.ttf</file>
+ </fileset>
+ </family>
+ <family>
+ <fileset>
+ <file>NotoSansTifinagh-Regular.ttf</file>
+ </fileset>
+ </family>
+ <family>
+ <fileset>
<file>NotoSansYi-Regular.ttf</file>
</fileset>
</family>
diff --git a/data/fonts/fonts.xml b/data/fonts/fonts.xml
index a62e972..02bf877 100644
--- a/data/fonts/fonts.xml
+++ b/data/fonts/fonts.xml
@@ -224,6 +224,10 @@
<font weight="700" style="normal">NotoSansThaana-Bold.ttf</font>
</family>
<family>
+ <font weight="400" style="normal">NotoSansCham-Regular.ttf</font>
+ <font weight="700" style="normal">NotoSansCham-Bold.ttf</font>
+ </family>
+ <family>
<font weight="400" style="normal">NotoSansBalinese-Regular.ttf</font>
</family>
<family>
@@ -242,12 +246,21 @@
<font weight="400" style="normal">NotoSansCherokee-Regular.ttf</font>
</family>
<family>
+ <font weight="400" style="normal">NotoSansCoptic-Regular.ttf</font>
+ </family>
+ <family>
+ <font weight="400" style="normal">NotoSansGlagolitic-Regular.ttf</font>
+ </family>
+ <family>
<font weight="400" style="normal">NotoSansHanunoo-Regular.ttf</font>
</family>
<family>
<font weight="400" style="normal">NotoSansJavanese-Regular.ttf</font>
</family>
<family>
+ <font weight="400" style="normal">NotoSansKayahLi-Regular.ttf</font>
+ </family>
+ <family>
<font weight="400" style="normal">NotoSansLepcha-Regular.ttf</font>
</family>
<family>
@@ -275,6 +288,18 @@
<font weight="400" style="normal">NotoSansTagbanwa-Regular.ttf</font>
</family>
<family>
+ <font weight="400" style="normal">NotoSansTaiLe-Regular.ttf</font>
+ </family>
+ <family>
+ <font weight="400" style="normal">NotoSansTaiTham-Regular.ttf</font>
+ </family>
+ <family>
+ <font weight="400" style="normal">NotoSansTaiViet-Regular.ttf</font>
+ </family>
+ <family>
+ <font weight="400" style="normal">NotoSansTifinagh-Regular.ttf</font>
+ </family>
+ <family>
<font weight="400" style="normal">NotoSansYi-Regular.ttf</font>
</family>
<family>
diff --git a/docs/html/samples/images/ActivitySceneTransitionBasic.png b/docs/html/samples/images/ActivitySceneTransitionBasic.png
index ea58641..a126cf8 100644
--- a/docs/html/samples/images/ActivitySceneTransitionBasic.png
+++ b/docs/html/samples/images/ActivitySceneTransitionBasic.png
Binary files differ
diff --git a/docs/html/samples/images/ActivitySceneTransitionBasic@2x.png b/docs/html/samples/images/ActivitySceneTransitionBasic@2x.png
index cd28ade..44378bb 100644
--- a/docs/html/samples/images/ActivitySceneTransitionBasic@2x.png
+++ b/docs/html/samples/images/ActivitySceneTransitionBasic@2x.png
Binary files differ
diff --git a/docs/html/samples/images/BasicManagedProfile.png b/docs/html/samples/images/BasicManagedProfile.png
index 7354842..5749db3 100644
--- a/docs/html/samples/images/BasicManagedProfile.png
+++ b/docs/html/samples/images/BasicManagedProfile.png
Binary files differ
diff --git a/docs/html/samples/images/BasicManagedProfile@2x.png b/docs/html/samples/images/BasicManagedProfile@2x.png
index c232809..860c954 100644
--- a/docs/html/samples/images/BasicManagedProfile@2x.png
+++ b/docs/html/samples/images/BasicManagedProfile@2x.png
Binary files differ
diff --git a/docs/html/samples/images/JobSchedulerSample.png b/docs/html/samples/images/JobSchedulerSample.png
index ee57bdb..a043f3e 100644
--- a/docs/html/samples/images/JobSchedulerSample.png
+++ b/docs/html/samples/images/JobSchedulerSample.png
Binary files differ
diff --git a/docs/html/samples/images/JobSchedulerSample@2x.png b/docs/html/samples/images/JobSchedulerSample@2x.png
index 3d543db..1ed2cf9 100644
--- a/docs/html/samples/images/JobSchedulerSample@2x.png
+++ b/docs/html/samples/images/JobSchedulerSample@2x.png
Binary files differ
diff --git a/docs/html/training/wearables/ui/exit.jd b/docs/html/training/wearables/ui/exit.jd
index 6b205a57..84e1e45 100644
--- a/docs/html/training/wearables/ui/exit.jd
+++ b/docs/html/training/wearables/ui/exit.jd
@@ -67,7 +67,7 @@
android:id="@+id/dismiss_overlay"
android:layout_height="match_parent"
android:layout_width="match_parent"/>
-</FrameLayout>
+<FrameLayout>
</pre>
<p>In your activity, obtain the <code>DismissOverlayView</code> element and set some introductory
@@ -100,8 +100,8 @@
// Capture long presses
@Override
- public boolean dispatchTouchEvent(MotionEvent e) {
- return mDetector.onTouchEvent(e) || super.dispatchTouchEvent(e);
+ public boolean onTouchEvent(MotionEvent ev) {
+ return mDetector.onTouchEvent(ev) || super.onTouchEvent(ev);
}
}
</pre>
diff --git a/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java b/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java
index e9c8c2a..2a17a60 100644
--- a/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java
+++ b/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java
@@ -146,7 +146,8 @@
@Override
public Drawable mutate() {
if (!mMutated && super.mutate() == this) {
- mAnimatedVectorState.mVectorDrawable.mutate();
+ mAnimatedVectorState = new AnimatedVectorDrawableState(
+ mAnimatedVectorState, mCallback, null);
mMutated = true;
}
return this;
diff --git a/media/java/android/media/tv/ITvInputSessionWrapper.java b/media/java/android/media/tv/ITvInputSessionWrapper.java
index da6f3fc..94c9690 100644
--- a/media/java/android/media/tv/ITvInputSessionWrapper.java
+++ b/media/java/android/media/tv/ITvInputSessionWrapper.java
@@ -42,7 +42,7 @@
private static final String TAG = "TvInputSessionWrapper";
private static final int MESSAGE_HANDLING_DURATION_THRESHOLD_MILLIS = 50;
- private static final int MESSAGE_TUNE_DURATION_THRESHOLD_MILLIS = 1000;
+ private static final int MESSAGE_TUNE_DURATION_THRESHOLD_MILLIS = 2000;
private static final int DO_RELEASE = 1;
private static final int DO_SET_MAIN = 2;
diff --git a/media/java/android/service/media/MediaBrowserService.java b/media/java/android/service/media/MediaBrowserService.java
index 779d486..26aedbd 100644
--- a/media/java/android/service/media/MediaBrowserService.java
+++ b/media/java/android/service/media/MediaBrowserService.java
@@ -323,24 +323,22 @@
* <p>
* This should be called as soon as possible during the service's startup.
* It may only be called once.
- *
- * @return The media session token, must not be null.
*/
public void setSessionToken(final MediaSession.Token token) {
if (token == null) {
throw new IllegalArgumentException("Session token may not be null.");
}
+ if (mSession != null) {
+ throw new IllegalStateException("The session token has already been set.");
+ }
+ mSession = token;
mHandler.post(new Runnable() {
@Override
public void run() {
- if (mSession != null) {
- throw new IllegalStateException("The session token has already been set.");
- }
- mSession = token;
for (IBinder key : mConnections.keySet()) {
ConnectionRecord connection = mConnections.get(key);
try {
- connection.callbacks.onConnect(connection.root.getRootId(), mSession,
+ connection.callbacks.onConnect(connection.root.getRootId(), token,
connection.root.getExtras());
} catch (RemoteException e) {
Log.w(TAG, "Connection for " + connection.pkg + " is no longer valid.");
diff --git a/packages/SystemUI/res/layout/lland.xml b/packages/SystemUI/res/layout/lland.xml
index 053225d..71a16c9 100644
--- a/packages/SystemUI/res/layout/lland.xml
+++ b/packages/SystemUI/res/layout/lland.xml
@@ -31,10 +31,10 @@
android:textSize="32sp"
android:textColor="#FFAAAAAA"
android:layout_marginTop="32dp"
- android:layout_marginLeft="16dp"
- android:layout_gravity="top|left"
- android:paddingLeft="16dp"
- android:paddingRight="16dp"
+ android:layout_marginStart="16dp"
+ android:layout_gravity="top|start"
+ android:paddingStart="16dp"
+ android:paddingEnd="16dp"
android:paddingTop="8dp"
android:paddingBottom="8dp"
android:background="@drawable/scorecard"
diff --git a/packages/SystemUI/src/com/android/systemui/egg/LLand.java b/packages/SystemUI/src/com/android/systemui/egg/LLand.java
index 5de09a3..fa257b1 100644
--- a/packages/SystemUI/src/com/android/systemui/egg/LLand.java
+++ b/packages/SystemUI/src/com/android/systemui/egg/LLand.java
@@ -178,6 +178,9 @@
setFocusable(true);
PARAMS = new Params(getResources());
mTimeOfDay = irand(0, SKIES.length);
+
+ // we assume everything will be laid out left|top
+ setLayoutDirection(LAYOUT_DIRECTION_LTR);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index 206fc43..7ac0daf 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -72,6 +72,7 @@
import com.android.systemui.statusbar.phone.StatusBarWindowManager;
import java.util.ArrayList;
+import java.util.List;
import static android.provider.Settings.System.SCREEN_OFF_TIMEOUT;
@@ -1217,7 +1218,12 @@
synchronized (this) {
if (mBootCompleted) {
final UserHandle currentUser = new UserHandle(mLockPatternUtils.getCurrentUser());
- mContext.sendBroadcastAsUser(USER_PRESENT_INTENT, currentUser);
+ final UserManager um = (UserManager) mContext.getSystemService(
+ Context.USER_SERVICE);
+ List <UserInfo> userHandles = um.getProfiles(currentUser.getIdentifier());
+ for (UserInfo ui : userHandles) {
+ mContext.sendBroadcastAsUser(USER_PRESENT_INTENT, ui.getUserHandle());
+ }
} else {
mBootSendUserPresent = true;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
index 57ac4b0..2b6ac26 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
@@ -683,15 +683,12 @@
Log.v(TAG, String.format("%s: current userid: %d, notification userid: %d",
n, thisUserId, notificationUserId));
}
- synchronized (mCurrentProfiles) {
- return notificationUserId == UserHandle.USER_ALL
- || mCurrentProfiles.get(notificationUserId) != null;
- }
+ return isCurrentProfile(notificationUserId);
}
protected boolean isCurrentProfile(int userId) {
synchronized (mCurrentProfiles) {
- return mCurrentProfiles.get(userId) != null;
+ return userId == UserHandle.USER_ALL || mCurrentProfiles.get(userId) != null;
}
}
diff --git a/services/core/java/com/android/server/BluetoothManagerService.java b/services/core/java/com/android/server/BluetoothManagerService.java
index ebdd386..3117a17 100644
--- a/services/core/java/com/android/server/BluetoothManagerService.java
+++ b/services/core/java/com/android/server/BluetoothManagerService.java
@@ -18,11 +18,14 @@
import android.app.ActivityManager;
import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothProfile;
import android.bluetooth.IBluetooth;
import android.bluetooth.IBluetoothGatt;
import android.bluetooth.IBluetoothCallback;
+import android.bluetooth.IBluetoothHeadset;
import android.bluetooth.IBluetoothManager;
import android.bluetooth.IBluetoothManagerCallback;
+import android.bluetooth.IBluetoothProfileServiceConnection;
import android.bluetooth.IBluetoothStateChangeCallback;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
@@ -32,6 +35,7 @@
import android.content.IntentFilter;
import android.content.ServiceConnection;
import android.content.pm.PackageManager;
+import android.content.pm.UserInfo;
import android.os.Binder;
import android.os.Handler;
import android.os.IBinder;
@@ -42,12 +46,18 @@
import android.os.RemoteException;
import android.os.SystemClock;
import android.os.UserHandle;
+import android.os.UserManager;
import android.provider.Settings;
import android.util.Log;
import java.io.FileDescriptor;
import java.io.PrintWriter;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.List;
+import java.util.Vector;
+
class BluetoothManagerService extends IBluetoothManager.Stub {
private static final String TAG = "BluetoothManagerService";
private static final boolean DBG = true;
@@ -67,6 +77,8 @@
private static final int ERROR_RESTART_TIME_MS = 3000;
//Maximum msec to delay MESSAGE_USER_SWITCHED
private static final int USER_SWITCHED_TIME_MS = 200;
+ // Delay for the addProxy function in msec
+ private static final int ADD_PROXY_DELAY_MS = 100;
private static final int MESSAGE_ENABLE = 1;
private static final int MESSAGE_DISABLE = 2;
@@ -83,6 +95,8 @@
private static final int MESSAGE_GET_NAME_AND_ADDRESS=200;
private static final int MESSAGE_SAVE_NAME_AND_ADDRESS=201;
private static final int MESSAGE_USER_SWITCHED = 300;
+ private static final int MESSAGE_ADD_PROXY_DELAYED = 400;
+ private static final int MESSAGE_BIND_PROFILE_SERVICE = 401;
private static final int MAX_SAVE_RETRIES=3;
private static final int MAX_ERROR_RESTART_RETRIES=6;
@@ -127,6 +141,11 @@
private int mErrorRecoveryRetryCounter;
private final int mSystemUiUid;
+ // Save a ProfileServiceConnections object for each of the bound
+ // bluetooth profile services
+ private final Map <Integer, ProfileServiceConnections> mProfileServices =
+ new HashMap <Integer, ProfileServiceConnections>();
+
private void registerForAirplaneMode(IntentFilter filter) {
final ContentResolver resolver = mContext.getContentResolver();
final String airplaneModeRadios = Settings.Global.getString(resolver,
@@ -499,6 +518,187 @@
return mBluetoothGatt;
}
+ @Override
+ public boolean bindBluetoothProfileService(int bluetoothProfile,
+ IBluetoothProfileServiceConnection proxy) {
+ if (!mEnable) {
+ if (DBG) {
+ Log.d(TAG, "Trying to bind to profile: " + bluetoothProfile +
+ ", while Bluetooth was disabled");
+ }
+ return false;
+ }
+ synchronized (mProfileServices) {
+ ProfileServiceConnections psc = mProfileServices.get(new Integer(bluetoothProfile));
+ if (psc == null) {
+ if (DBG) {
+ Log.d(TAG, "Creating new ProfileServiceConnections object for"
+ + " profile: " + bluetoothProfile);
+ }
+ Intent intent = null;
+ if (bluetoothProfile == BluetoothProfile.HEADSET) {
+ intent = new Intent(IBluetoothHeadset.class.getName());
+ } else {
+ return false;
+ }
+ psc = new ProfileServiceConnections(intent);
+ mProfileServices.put(new Integer(bluetoothProfile), psc);
+ psc.bindService();
+ }
+ }
+
+ // Introducing a delay to give the client app time to prepare
+ Message addProxyMsg = mHandler.obtainMessage(MESSAGE_ADD_PROXY_DELAYED);
+ addProxyMsg.arg1 = bluetoothProfile;
+ addProxyMsg.obj = proxy;
+ mHandler.sendMessageDelayed(addProxyMsg, ADD_PROXY_DELAY_MS);
+ return true;
+ }
+
+ @Override
+ public void unbindBluetoothProfileService(int bluetoothProfile,
+ IBluetoothProfileServiceConnection proxy) {
+ synchronized (mProfileServices) {
+ ProfileServiceConnections psc = mProfileServices.get(new Integer(bluetoothProfile));
+ if (psc == null) {
+ return;
+ }
+ psc.removeProxy(proxy);
+ }
+ }
+
+ private void unbindAllBluetoothProfileServices() {
+ synchronized (mProfileServices) {
+ for (Integer i : mProfileServices.keySet()) {
+ ProfileServiceConnections psc = mProfileServices.get(i);
+ mContext.unbindService(psc);
+ psc.removeAllProxies();
+ }
+ mProfileServices.clear();
+ }
+ }
+
+ /**
+ * This class manages the clients connected to a given ProfileService
+ * and maintains the connection with that service.
+ */
+ final private class ProfileServiceConnections implements ServiceConnection,
+ IBinder.DeathRecipient {
+ final RemoteCallbackList<IBluetoothProfileServiceConnection> mProxies =
+ new RemoteCallbackList <IBluetoothProfileServiceConnection>();
+ IBinder mService;
+ ComponentName mClassName;
+ Intent mIntent;
+
+ ProfileServiceConnections(Intent intent) {
+ mService = null;
+ mClassName = null;
+ mIntent = intent;
+ }
+
+ private void bindService() {
+ if (mIntent != null && mService == null) {
+ if (!doBind(mIntent, this, 0, UserHandle.CURRENT_OR_SELF)) {
+ Log.w(TAG, "Unable to bind with intent: " + mIntent
+ + ". Triggering retry.");
+ }
+ Message msg = mHandler.obtainMessage(MESSAGE_BIND_PROFILE_SERVICE);
+ msg.obj = this;
+ mHandler.sendMessageDelayed(msg, TIMEOUT_BIND_MS);
+ }
+ }
+
+ private void addProxy(IBluetoothProfileServiceConnection proxy) {
+ mProxies.register(proxy);
+ if (mService != null) {
+ try{
+ proxy.onServiceConnected(mClassName, mService);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Unable to connect to proxy", e);
+ }
+ } else {
+ if (!mHandler.hasMessages(MESSAGE_BIND_PROFILE_SERVICE, this)) {
+ Message msg = mHandler.obtainMessage(MESSAGE_BIND_PROFILE_SERVICE);
+ msg.obj = this;
+ mHandler.sendMessage(msg);
+ }
+ }
+ }
+
+ private void removeProxy(IBluetoothProfileServiceConnection proxy) {
+ if (proxy != null) {
+ if (mProxies.unregister(proxy)) {
+ try {
+ proxy.onServiceDisconnected(mClassName);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Unable to disconnect proxy", e);
+ }
+ }
+ } else {
+ Log.w(TAG, "Trying to remove a null proxy");
+ }
+ }
+
+ private void removeAllProxies() {
+ onServiceDisconnected(mClassName);
+ mProxies.kill();
+ }
+
+ @Override
+ public void onServiceConnected(ComponentName className, IBinder service) {
+ // remove timeout message
+ mHandler.removeMessages(MESSAGE_BIND_PROFILE_SERVICE, this);
+ mService = service;
+ mClassName = className;
+ try {
+ mService.linkToDeath(this, 0);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Unable to linkToDeath", e);
+ }
+ int n = mProxies.beginBroadcast();
+ for (int i = 0; i < n; i++) {
+ try {
+ mProxies.getBroadcastItem(i).onServiceConnected(className, service);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Unable to connect to proxy", e);
+ }
+ }
+ mProxies.finishBroadcast();
+ }
+
+ @Override
+ public void onServiceDisconnected(ComponentName className) {
+ if (mService == null) {
+ return;
+ }
+ mService.unlinkToDeath(this, 0);
+ mService = null;
+ mClassName = null;
+ int n = mProxies.beginBroadcast();
+ for (int i = 0; i < n; i++) {
+ try {
+ mProxies.getBroadcastItem(i).onServiceDisconnected(className);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Unable to disconnect from proxy", e);
+ }
+ }
+ mProxies.finishBroadcast();
+ }
+
+ @Override
+ public void binderDied() {
+ if (DBG) {
+ Log.w(TAG, "Profile service for profile: " + mClassName
+ + " died.");
+ }
+ onServiceDisconnected(mClassName);
+ // Trigger rebind
+ Message msg = mHandler.obtainMessage(MESSAGE_BIND_PROFILE_SERVICE);
+ msg.obj = this;
+ mHandler.sendMessageDelayed(msg, TIMEOUT_BIND_MS);
+ }
+ }
+
private void sendBluetoothStateCallback(boolean isUp) {
int n = mStateChangeCallbacks.beginBroadcast();
if (DBG) Log.d(TAG,"Broadcasting onBluetoothStateChange("+isUp+") to " + n + " receivers.");
@@ -803,6 +1003,28 @@
}
break;
}
+ case MESSAGE_ADD_PROXY_DELAYED:
+ {
+ ProfileServiceConnections psc = mProfileServices.get(
+ new Integer(msg.arg1));
+ if (psc == null) {
+ break;
+ }
+ IBluetoothProfileServiceConnection proxy =
+ (IBluetoothProfileServiceConnection) msg.obj;
+ psc.addProxy(proxy);
+ break;
+ }
+ case MESSAGE_BIND_PROFILE_SERVICE:
+ {
+ ProfileServiceConnections psc = (ProfileServiceConnections) msg.obj;
+ removeMessages(MESSAGE_BIND_PROFILE_SERVICE, msg.obj);
+ if (psc == null) {
+ break;
+ }
+ psc.bindService();
+ break;
+ }
case MESSAGE_BLUETOOTH_SERVICE_CONNECTED:
{
if (DBG) Log.d(TAG,"MESSAGE_BLUETOOTH_SERVICE_CONNECTED: " + msg.arg1);
@@ -1005,6 +1227,7 @@
bluetoothStateChangeHandler(mState, BluetoothAdapter.STATE_ON);
}
+ unbindAllBluetoothProfileServices();
// disable
handleDisable();
// Pbap service need receive STATE_TURNING_OFF intent to close
@@ -1129,16 +1352,21 @@
int callingUser = UserHandle.getCallingUserId();
int callingUid = Binder.getCallingUid();
long callingIdentity = Binder.clearCallingIdentity();
+ UserManager um = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
+ UserInfo ui = um.getProfileParent(callingUser);
+ int parentUser = (ui != null) ? ui.id : UserHandle.USER_NULL;
int callingAppId = UserHandle.getAppId(callingUid);
boolean valid = false;
try {
foregroundUser = ActivityManager.getCurrentUser();
valid = (callingUser == foregroundUser) ||
+ parentUser == foregroundUser ||
callingAppId == Process.NFC_UID ||
callingAppId == mSystemUiUid;
if (DBG) {
Log.d(TAG, "checkIfCallerIsForegroundUser: valid=" + valid
+ " callingUser=" + callingUser
+ + " parentUser=" + parentUser
+ " foregroundUser=" + foregroundUser);
}
} finally {
@@ -1165,6 +1393,7 @@
} else {
//If Bluetooth is off, send service down event to proxy objects, and unbind
if (!isUp && canUnbindBluetoothService()) {
+ unbindAllBluetoothProfileServices();
sendBluetoothServiceDownCallback();
unbindAndFinish();
}
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 0f1ed0a..348aa1b 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -797,6 +797,17 @@
throw new IllegalStateException("No free netIds");
}
+ private int getConnectivityChangeDelay() {
+ final ContentResolver cr = mContext.getContentResolver();
+
+ /** Check system properties for the default value then use secure settings value, if any. */
+ int defaultDelay = SystemProperties.getInt(
+ "conn." + Settings.Global.CONNECTIVITY_CHANGE_DELAY,
+ ConnectivityManager.CONNECTIVITY_CHANGE_DELAY_DEFAULT);
+ return Settings.Global.getInt(cr, Settings.Global.CONNECTIVITY_CHANGE_DELAY,
+ defaultDelay);
+ }
+
private boolean teardown(NetworkStateTracker netTracker) {
if (netTracker.teardown()) {
netTracker.setTeardownRequested(true);
@@ -1468,6 +1479,11 @@
sendGeneralBroadcast(info, CONNECTIVITY_ACTION);
}
+ private void sendConnectedBroadcastDelayed(NetworkInfo info, int delayMs) {
+ sendGeneralBroadcast(info, CONNECTIVITY_ACTION_IMMEDIATE);
+ sendGeneralBroadcastDelayed(info, CONNECTIVITY_ACTION, delayMs);
+ }
+
private void sendInetConditionBroadcast(NetworkInfo info) {
sendGeneralBroadcast(info, ConnectivityManager.INET_CONDITION_ACTION);
}
@@ -1499,6 +1515,10 @@
sendStickyBroadcast(makeGeneralIntent(info, bcastType));
}
+ private void sendGeneralBroadcastDelayed(NetworkInfo info, String bcastType, int delayMs) {
+ sendStickyBroadcastDelayed(makeGeneralIntent(info, bcastType), delayMs);
+ }
+
private void sendDataActivityBroadcast(int deviceType, boolean active, long tsNanos) {
Intent intent = new Intent(ConnectivityManager.ACTION_DATA_ACTIVITY_CHANGE);
intent.putExtra(ConnectivityManager.EXTRA_DEVICE_TYPE, deviceType);
@@ -1532,6 +1552,19 @@
}
}
+ private void sendStickyBroadcastDelayed(Intent intent, int delayMs) {
+ if (delayMs <= 0) {
+ sendStickyBroadcast(intent);
+ } else {
+ if (VDBG) {
+ log("sendStickyBroadcastDelayed: delayMs=" + delayMs + ", action="
+ + intent.getAction());
+ }
+ mHandler.sendMessageDelayed(mHandler.obtainMessage(
+ EVENT_SEND_STICKY_BROADCAST_INTENT, intent), delayMs);
+ }
+ }
+
void systemReady() {
// start network sampling ..
Intent intent = new Intent(ACTION_PKT_CNT_SAMPLE_INTERVAL_ELAPSED);
@@ -4268,7 +4301,7 @@
info.setType(type);
if (connected) {
info.setDetailedState(DetailedState.CONNECTED, null, info.getExtraInfo());
- sendConnectedBroadcast(info);
+ sendConnectedBroadcastDelayed(info, getConnectivityChangeDelay());
} else {
info.setDetailedState(DetailedState.DISCONNECTED, null, info.getExtraInfo());
Intent intent = new Intent(ConnectivityManager.CONNECTIVITY_ACTION);
@@ -4299,9 +4332,10 @@
final Intent immediateIntent = new Intent(intent);
immediateIntent.setAction(CONNECTIVITY_ACTION_IMMEDIATE);
sendStickyBroadcast(immediateIntent);
- sendStickyBroadcast(intent);
+ sendStickyBroadcastDelayed(intent, getConnectivityChangeDelay());
if (newDefaultAgent != null) {
- sendConnectedBroadcast(newDefaultAgent.networkInfo);
+ sendConnectedBroadcastDelayed(newDefaultAgent.networkInfo,
+ getConnectivityChangeDelay());
}
}
}
diff --git a/services/core/java/com/android/server/MountServiceIdler.java b/services/core/java/com/android/server/MountServiceIdler.java
index bc851a3..e0b2307 100644
--- a/services/core/java/com/android/server/MountServiceIdler.java
+++ b/services/core/java/com/android/server/MountServiceIdler.java
@@ -18,12 +18,14 @@
import java.util.Calendar;
+import android.app.ActivityManagerNative;
import android.app.job.JobInfo;
import android.app.job.JobParameters;
import android.app.job.JobScheduler;
import android.app.job.JobService;
import android.content.ComponentName;
import android.content.Context;
+import android.os.RemoteException;
import android.util.Slog;
public class MountServiceIdler extends JobService {
@@ -53,6 +55,13 @@
@Override
public boolean onStartJob(JobParameters params) {
+ // First have the activity manager do its idle maintenance. (Yes this job
+ // is really more than just mount, some day it should be renamed to be system
+ // idleer).
+ try {
+ ActivityManagerNative.getDefault().performIdleMaintenance();
+ } catch (RemoteException e) {
+ }
// The mount service will run an fstrim operation asynchronously
// on a designated separate thread, so we provide it with a callback
// that lets us cleanly end our idle timeslice. It's safe to call
@@ -98,7 +107,7 @@
private static Calendar tomorrowMidnight() {
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(System.currentTimeMillis());
- calendar.set(Calendar.HOUR_OF_DAY, 0);
+ calendar.set(Calendar.HOUR_OF_DAY, 3);
calendar.set(Calendar.MINUTE, 0);
calendar.set(Calendar.SECOND, 0);
calendar.set(Calendar.MILLISECOND, 0);
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 8cf1020..221a0a6 100755
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -9293,9 +9293,9 @@
"Attempt to launch content provider before system ready");
}
- // Make sure that the user who owns this provider is started. If not,
+ // Make sure that the user who owns this provider is running. If not,
// we don't want to allow it to run.
- if (mStartedUsers.get(userId) == null) {
+ if (!isUserRunningLocked(userId, false)) {
Slog.w(TAG, "Unable to launch app "
+ cpi.applicationInfo.packageName + "/"
+ cpi.applicationInfo.uid + " for provider "
@@ -12900,7 +12900,7 @@
+ PowerManagerInternal.wakefulnessToString(mWakefulness));
pw.println(" mSleeping=" + mSleeping + " mLockScreenShown="
+ lockScreenShownToString());
- pw.print(" mShuttingDown=" + mShuttingDown + " mRunningVoice=" + mRunningVoice);
+ pw.println(" mShuttingDown=" + mShuttingDown + " mRunningVoice=" + mRunningVoice);
}
if (mDebugApp != null || mOrigDebugApp != null || mDebugTransient
|| mOrigWaitForDebugger) {
@@ -15660,10 +15660,10 @@
userId = handleIncomingUser(callingPid, callingUid, userId,
true, ALLOW_NON_FULL, "broadcast", callerPackage);
- // Make sure that the user who is receiving this broadcast is started.
+ // Make sure that the user who is receiving this broadcast is running.
// If not, we will just skip it.
- if (userId != UserHandle.USER_ALL && mStartedUsers.get(userId) == null) {
+ if (userId != UserHandle.USER_ALL && !isUserRunningLocked(userId, false)) {
if (callingUid != Process.SYSTEM_UID || (intent.getFlags()
& Intent.FLAG_RECEIVER_BOOT_UPGRADE) == 0) {
Slog.w(TAG, "Skipping broadcast of " + intent
diff --git a/services/core/java/com/android/server/tv/TvInputManagerService.java b/services/core/java/com/android/server/tv/TvInputManagerService.java
index 5ab3fa1..5375bfc 100644
--- a/services/core/java/com/android/server/tv/TvInputManagerService.java
+++ b/services/core/java/com/android/server/tv/TvInputManagerService.java
@@ -461,7 +461,7 @@
UserState userState = getUserStateLocked(userId);
SessionState sessionState = userState.sessionStateMap.get(sessionToken);
if (sessionState == null) {
- throw new IllegalArgumentException("Session state not found for token " + sessionToken);
+ throw new SessionNotFoundException("Session state not found for token " + sessionToken);
}
// Only the application that requested this session or the system can access it.
if (callingUid != Process.SYSTEM_UID && callingUid != sessionState.callingUid) {
@@ -589,18 +589,22 @@
}
private void releaseSessionLocked(IBinder sessionToken, int callingUid, int userId) {
- SessionState sessionState = getSessionStateLocked(sessionToken, callingUid, userId);
- if (sessionState.session != null) {
- UserState userState = getUserStateLocked(userId);
- if (sessionToken == userState.mainSessionToken) {
- setMainLocked(sessionToken, false, callingUid, userId);
- }
- try {
+ SessionState sessionState = null;
+ try {
+ sessionState = getSessionStateLocked(sessionToken, callingUid, userId);
+ if (sessionState.session != null) {
+ UserState userState = getUserStateLocked(userId);
+ if (sessionToken == userState.mainSessionToken) {
+ setMainLocked(sessionToken, false, callingUid, userId);
+ }
sessionState.session.release();
- } catch (RemoteException e) {
- Slog.e(TAG, "session process has already died", e);
}
- sessionState.session = null;
+ } catch (RemoteException | SessionNotFoundException e) {
+ Slog.e(TAG, "error in releaseSession", e);
+ } finally {
+ if (sessionState != null) {
+ sessionState.session = null;
+ }
}
removeSessionStateLocked(sessionToken, userId);
}
@@ -648,19 +652,19 @@
}
private void setMainLocked(IBinder sessionToken, boolean isMain, int callingUid, int userId) {
- SessionState sessionState = getSessionStateLocked(sessionToken, callingUid, userId);
- if (sessionState.hardwareSessionToken != null) {
- sessionState = getSessionStateLocked(sessionState.hardwareSessionToken,
- Process.SYSTEM_UID, userId);
- }
- ServiceState serviceState = getServiceStateLocked(sessionState.info.getComponent(), userId);
- if (!serviceState.isHardware) {
- return;
- }
- ITvInputSession session = getSessionLocked(sessionState);
try {
+ SessionState sessionState = getSessionStateLocked(sessionToken, callingUid, userId);
+ if (sessionState.hardwareSessionToken != null) {
+ sessionState = getSessionStateLocked(sessionState.hardwareSessionToken,
+ Process.SYSTEM_UID, userId);
+ }
+ ServiceState serviceState = getServiceStateLocked(sessionState.info.getComponent(), userId);
+ if (!serviceState.isHardware) {
+ return;
+ }
+ ITvInputSession session = getSessionLocked(sessionState);
session.setMain(isMain);
- } catch (RemoteException e) {
+ } catch (RemoteException | SessionNotFoundException e) {
Slog.e(TAG, "error in setMain", e);
}
}
@@ -1085,7 +1089,7 @@
getSessionLocked(sessionState.hardwareSessionToken,
Process.SYSTEM_UID, resolvedUserId).setSurface(surface);
}
- } catch (RemoteException e) {
+ } catch (RemoteException | SessionNotFoundException e) {
Slog.e(TAG, "error in setSurface", e);
}
}
@@ -1116,7 +1120,7 @@
getSessionLocked(sessionState.hardwareSessionToken, Process.SYSTEM_UID,
resolvedUserId).dispatchSurfaceChanged(format, width, height);
}
- } catch (RemoteException e) {
+ } catch (RemoteException | SessionNotFoundException e) {
Slog.e(TAG, "error in dispatchSurfaceChanged", e);
}
}
@@ -1146,7 +1150,7 @@
Process.SYSTEM_UID, resolvedUserId).setVolume((volume > 0.0f)
? REMOTE_VOLUME_ON : REMOTE_VOLUME_OFF);
}
- } catch (RemoteException e) {
+ } catch (RemoteException | SessionNotFoundException e) {
Slog.e(TAG, "error in setVolume", e);
}
}
@@ -1183,7 +1187,7 @@
args.arg5 = sessionToken;
mWatchLogHandler.obtainMessage(WatchLogHandler.MSG_LOG_WATCH_START, args)
.sendToTarget();
- } catch (RemoteException e) {
+ } catch (RemoteException | SessionNotFoundException e) {
Slog.e(TAG, "error in tune", e);
return;
}
@@ -1205,7 +1209,7 @@
try {
getSessionLocked(sessionToken, callingUid, resolvedUserId)
.requestUnblockContent(unblockedRating);
- } catch (RemoteException e) {
+ } catch (RemoteException | SessionNotFoundException e) {
Slog.e(TAG, "error in requestUnblockContent", e);
}
}
@@ -1225,7 +1229,7 @@
try {
getSessionLocked(sessionToken, callingUid, resolvedUserId)
.setCaptionEnabled(enabled);
- } catch (RemoteException e) {
+ } catch (RemoteException | SessionNotFoundException e) {
Slog.e(TAG, "error in setCaptionEnabled", e);
}
}
@@ -1245,7 +1249,7 @@
try {
getSessionLocked(sessionToken, callingUid, resolvedUserId).selectTrack(
type, trackId);
- } catch (RemoteException e) {
+ } catch (RemoteException | SessionNotFoundException e) {
Slog.e(TAG, "error in selectTrack", e);
}
}
@@ -1266,7 +1270,7 @@
try {
getSessionLocked(sessionToken, callingUid, resolvedUserId)
.appPrivateCommand(command, data);
- } catch (RemoteException e) {
+ } catch (RemoteException | SessionNotFoundException e) {
Slog.e(TAG, "error in appPrivateCommand", e);
}
}
@@ -1287,7 +1291,7 @@
try {
getSessionLocked(sessionToken, callingUid, resolvedUserId)
.createOverlayView(windowToken, frame);
- } catch (RemoteException e) {
+ } catch (RemoteException | SessionNotFoundException e) {
Slog.e(TAG, "error in createOverlayView", e);
}
}
@@ -1307,7 +1311,7 @@
try {
getSessionLocked(sessionToken, callingUid, resolvedUserId)
.relayoutOverlayView(frame);
- } catch (RemoteException e) {
+ } catch (RemoteException | SessionNotFoundException e) {
Slog.e(TAG, "error in relayoutOverlayView", e);
}
}
@@ -1327,7 +1331,7 @@
try {
getSessionLocked(sessionToken, callingUid, resolvedUserId)
.removeOverlayView();
- } catch (RemoteException e) {
+ } catch (RemoteException | SessionNotFoundException e) {
Slog.e(TAG, "error in removeOverlayView", e);
}
}
@@ -2340,4 +2344,13 @@
}
}
}
+
+ private static class SessionNotFoundException extends IllegalArgumentException {
+ public SessionNotFoundException() {
+ }
+
+ public SessionNotFoundException(String name) {
+ super(name);
+ }
+ }
}
diff --git a/services/core/java/com/android/server/wm/InputMonitor.java b/services/core/java/com/android/server/wm/InputMonitor.java
index 0327cb3..27ac32a 100644
--- a/services/core/java/com/android/server/wm/InputMonitor.java
+++ b/services/core/java/com/android/server/wm/InputMonitor.java
@@ -242,6 +242,7 @@
final WindowStateAnimator universeBackground = mService.mAnimator.mUniverseBackground;
final int aboveUniverseLayer = mService.mAnimator.mAboveUniverseLayer;
boolean addedUniverse = false;
+ boolean disableWallpaperTouchEvents = false;
// If there's a drag in flight, provide a pseudowindow to catch drag input
final boolean inDrag = (mService.mDragState != null);
@@ -282,8 +283,14 @@
final boolean hasFocus = (child == mInputFocus);
final boolean isVisible = child.isVisibleLw();
+ if ((privateFlags
+ & WindowManager.LayoutParams.PRIVATE_FLAG_DISABLE_WALLPAPER_TOUCH_EVENTS)
+ != 0) {
+ disableWallpaperTouchEvents = true;
+ }
final boolean hasWallpaper = (child == mService.mWallpaperTarget)
- && (privateFlags & WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD) == 0;
+ && (privateFlags & WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD) == 0
+ && !disableWallpaperTouchEvents;
final boolean onDefaultDisplay = (child.getDisplayId() == Display.DEFAULT_DISPLAY);
// If there's a drag in progress and 'child' is a potential drop target,
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 2201d2b..72a3337 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -120,7 +120,6 @@
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintWriter;
-import java.security.cert.CertificateEncodingException;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
@@ -265,6 +264,8 @@
= new HashMap<ComponentName, ActiveAdmin>();
final ArrayList<ActiveAdmin> mAdminList
= new ArrayList<ActiveAdmin>();
+ final ArrayList<ComponentName> mRemovingAdmins
+ = new ArrayList<ComponentName>();
// This is the list of component allowed to start lock task mode.
final List<String> mLockTaskPackages = new ArrayList<String>();
@@ -303,8 +304,6 @@
if (Intent.ACTION_USER_REMOVED.equals(action)) {
removeUserData(userHandle);
} else if (Intent.ACTION_USER_STARTED.equals(action)
- || Intent.ACTION_PACKAGE_CHANGED.equals(action)
- || Intent.ACTION_PACKAGE_REMOVED.equals(action)
|| Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE.equals(action)) {
if (Intent.ACTION_USER_STARTED.equals(action)) {
@@ -313,8 +312,14 @@
mUserData.remove(userHandle);
}
}
-
- handlePackagesChanged(userHandle);
+ handlePackagesChanged(null /* check all admins */, userHandle);
+ } else if (Intent.ACTION_PACKAGE_CHANGED.equals(action)
+ || (Intent.ACTION_PACKAGE_ADDED.equals(action)
+ && intent.getBooleanExtra(Intent.EXTRA_REPLACING, false))) {
+ handlePackagesChanged(intent.getData().getSchemeSpecificPart(), userHandle);
+ } else if (Intent.ACTION_PACKAGE_REMOVED.equals(action)
+ && !intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) {
+ handlePackagesChanged(intent.getData().getSchemeSpecificPart(), userHandle);
}
}
};
@@ -899,7 +904,7 @@
}
}
- private void handlePackagesChanged(int userHandle) {
+ private void handlePackagesChanged(String packageName, int userHandle) {
boolean removed = false;
if (DBG) Slog.d(LOG_TAG, "Handling package changes for user " + userHandle);
DevicePolicyData policy = getUserData(userHandle);
@@ -908,11 +913,17 @@
for (int i = policy.mAdminList.size() - 1; i >= 0; i--) {
ActiveAdmin aa = policy.mAdminList.get(i);
try {
- if (pm.getPackageInfo(aa.info.getPackageName(), 0, userHandle) == null
- || pm.getReceiverInfo(aa.info.getComponent(), 0, userHandle) == null) {
- removed = true;
- policy.mAdminList.remove(i);
- policy.mAdminMap.remove(aa.info.getComponent());
+ // If we're checking all packages or if the specific one we're checking matches,
+ // then check if the package and receiver still exist.
+ final String adminPackage = aa.info.getPackageName();
+ if (packageName == null || packageName.equals(adminPackage)) {
+ if (pm.getPackageInfo(adminPackage, 0, userHandle) == null
+ || pm.getReceiverInfo(aa.info.getComponent(), 0, userHandle)
+ == null) {
+ removed = true;
+ policy.mAdminList.remove(i);
+ policy.mAdminMap.remove(aa.info.getComponent());
+ }
}
} catch (RemoteException re) {
// Shouldn't happen
@@ -1202,6 +1213,9 @@
void removeActiveAdminLocked(final ComponentName adminReceiver, int userHandle) {
final ActiveAdmin admin = getActiveAdminUncheckedLocked(adminReceiver, userHandle);
if (admin != null) {
+ synchronized (this) {
+ getUserData(userHandle).mRemovingAdmins.add(adminReceiver);
+ }
sendAdminCommandLocked(admin,
DeviceAdminReceiver.ACTION_DEVICE_ADMIN_DISABLED,
new BroadcastReceiver() {
@@ -1221,9 +1235,10 @@
}
saveSettingsLocked(userHandle);
updateMaximumTimeToLockLocked(policy);
+ policy.mRemovingAdmins.remove(adminReceiver);
}
}
- });
+ });
}
}
@@ -1788,6 +1803,18 @@
}
}
+ @Override
+ public boolean isRemovingAdmin(ComponentName adminReceiver, int userHandle) {
+ if (!mHasFeature) {
+ return false;
+ }
+ enforceCrossUserPermission(userHandle);
+ synchronized (this) {
+ DevicePolicyData policyData = getUserData(userHandle);
+ return policyData.mRemovingAdmins.contains(adminReceiver);
+ }
+ }
+
public boolean hasGrantedPolicy(ComponentName adminReceiver, int policyId, int userHandle) {
if (!mHasFeature) {
return false;
@@ -4091,6 +4118,10 @@
ap.dump(" ", pw);
}
}
+ if (!policy.mRemovingAdmins.isEmpty()) {
+ p.println(" Removing Device Admins (User " + policy.mUserHandle + "): "
+ + policy.mRemovingAdmins);
+ }
pw.println(" ");
pw.print(" mPasswordOwner="); pw.println(policy.mPasswordOwner);
diff --git a/telecomm/java/android/telecom/AudioState.java b/telecomm/java/android/telecom/AudioState.java
index 3271ebf..9c03319 100644
--- a/telecomm/java/android/telecom/AudioState.java
+++ b/telecomm/java/android/telecom/AudioState.java
@@ -54,14 +54,14 @@
public static final int ROUTE_ALL = ROUTE_EARPIECE | ROUTE_BLUETOOTH | ROUTE_WIRED_HEADSET |
ROUTE_SPEAKER;
- /** @hide */
- @Deprecated public final boolean isMuted;
+ /** Note: Deprecated, please do not use if possible. */
+ @SystemApi public final boolean isMuted;
- /** @hide */
- @Deprecated public final int route;
+ /** Note: Deprecated, please do not use if possible. */
+ @SystemApi public final int route;
- /** @hide */
- @Deprecated public final int supportedRouteMask;
+ /** Note: Deprecated, please do not use if possible. */
+ @SystemApi public final int supportedRouteMask;
public AudioState(boolean muted, int route, int supportedRouteMask) {
this.isMuted = muted;
diff --git a/telecomm/java/android/telecom/TelecomManager.java b/telecomm/java/android/telecom/TelecomManager.java
index 2a3d7ab8..6621726 100644
--- a/telecomm/java/android/telecom/TelecomManager.java
+++ b/telecomm/java/android/telecom/TelecomManager.java
@@ -732,6 +732,26 @@
}
/**
+ * Return whether a given phone account has a voicemail number configured.
+ *
+ * @param accountHandle The handle for the account to check for a voicemail number.
+ * @return {@code true} If the given phone account has a voicemail number.
+ *
+ * @hide
+ */
+ @SystemApi
+ public boolean hasVoiceMailNumber(PhoneAccountHandle accountHandle) {
+ try {
+ if (isServiceConnected()) {
+ return getTelecomService().hasVoiceMailNumber(accountHandle);
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "RemoteException calling isInCall().", e);
+ }
+ return false;
+ }
+
+ /**
* Returns whether there is an ongoing phone call (can be in dialing, ringing, active or holding
* states).
* <p>
diff --git a/telecomm/java/com/android/internal/telecom/ITelecomService.aidl b/telecomm/java/com/android/internal/telecom/ITelecomService.aidl
index cbd9d69..f8d7539 100644
--- a/telecomm/java/com/android/internal/telecom/ITelecomService.aidl
+++ b/telecomm/java/com/android/internal/telecom/ITelecomService.aidl
@@ -121,6 +121,11 @@
boolean isVoiceMailNumber(in PhoneAccountHandle accountHandle, String number);
/**
+ * @see TelecomServiceImpl#hasVoiceMailNumber
+ */
+ boolean hasVoiceMailNumber(in PhoneAccountHandle accountHandle);
+
+ /**
* @see TelecomServiceImpl#getDefaultPhoneApp
*/
ComponentName getDefaultPhoneApp();