summaryrefslogtreecommitdiffstats
path: root/core/java
diff options
context:
space:
mode:
Diffstat (limited to 'core/java')
-rw-r--r--core/java/android/app/ActivityManager.java12
-rw-r--r--core/java/android/app/ActivityManagerNative.java53
-rw-r--r--core/java/android/app/ActivityThread.java103
-rw-r--r--core/java/android/app/IActivityManager.java5
-rw-r--r--core/java/android/app/Notification.java11
-rw-r--r--core/java/android/content/ContentService.java4
-rw-r--r--core/java/android/content/Intent.java13
-rwxr-xr-xcore/java/android/content/res/Resources.java2
-rw-r--r--core/java/android/hardware/display/DisplayManager.java34
-rw-r--r--core/java/android/hardware/display/DisplayManagerGlobal.java25
-rw-r--r--core/java/android/hardware/display/IDisplayManager.aidl6
-rw-r--r--core/java/android/hardware/display/WifiDisplay.java38
-rw-r--r--core/java/android/hardware/display/WifiDisplayStatus.java109
-rw-r--r--core/java/android/net/CaptivePortalTracker.java247
-rw-r--r--core/java/android/net/NetworkStats.java5
-rw-r--r--core/java/android/os/Environment.java25
-rw-r--r--core/java/android/os/UserManager.java2
-rw-r--r--core/java/android/provider/Settings.java44
-rw-r--r--core/java/android/service/dreams/Dream.java250
-rw-r--r--core/java/android/service/dreams/DreamManagerService.java247
-rw-r--r--core/java/android/service/dreams/IDreamManager.aidl2
-rw-r--r--core/java/android/text/format/DateUtils.java68
-rw-r--r--core/java/android/text/format/Time.java28
-rw-r--r--core/java/android/view/HardwareRenderer.java9
-rw-r--r--core/java/android/view/View.java162
-rw-r--r--core/java/android/view/WindowManagerPolicy.java10
-rw-r--r--core/java/android/webkit/JWebCoreJavaBridge.java1
-rw-r--r--core/java/android/webkit/WebViewCore.java11
-rw-r--r--core/java/android/webkit/ZoomManager.java13
-rwxr-xr-xcore/java/android/widget/AppSecurityPermissions.java15
-rw-r--r--core/java/com/android/internal/app/AlertController.java16
-rw-r--r--core/java/com/android/internal/content/PackageMonitor.java51
-rw-r--r--core/java/com/android/internal/widget/LockPatternUtils.java46
33 files changed, 1036 insertions, 631 deletions
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index 06f79e7..0eda6b4 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -864,7 +864,17 @@ public class ActivityManager {
return null;
}
}
-
+
+ /** @hide */
+ public Bitmap getTaskTopThumbnail(int id) throws SecurityException {
+ try {
+ return ActivityManagerNative.getDefault().getTaskTopThumbnail(id);
+ } catch (RemoteException e) {
+ // System dead, we will be dead too soon!
+ return null;
+ }
+ }
+
/**
* Flag for {@link #moveTaskToFront(int, int)}: also move the "home"
* activity along with the task, so it is positioned immediately behind
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index 773f73c..b0df660 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -498,7 +498,7 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM
reply.writeTypedList(list);
return true;
}
-
+
case GET_TASK_THUMBNAILS_TRANSACTION: {
data.enforceInterface(IActivityManager.descriptor);
int id = data.readInt();
@@ -512,7 +512,21 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM
}
return true;
}
-
+
+ case GET_TASK_TOP_THUMBNAIL_TRANSACTION: {
+ data.enforceInterface(IActivityManager.descriptor);
+ int id = data.readInt();
+ Bitmap bm = getTaskTopThumbnail(id);
+ reply.writeNoException();
+ if (bm != null) {
+ reply.writeInt(1);
+ bm.writeToParcel(reply, 0);
+ } else {
+ reply.writeInt(0);
+ }
+ return true;
+ }
+
case GET_SERVICES_TRANSACTION: {
data.enforceInterface(IActivityManager.descriptor);
int maxNum = data.readInt();
@@ -1597,6 +1611,14 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM
return true;
}
+ case GET_RUNNING_USER_IDS_TRANSACTION: {
+ data.enforceInterface(IActivityManager.descriptor);
+ int[] result = getRunningUserIds();
+ reply.writeNoException();
+ reply.writeIntArray(result);
+ return true;
+ }
+
case REMOVE_SUB_TASK_TRANSACTION:
{
data.enforceInterface(IActivityManager.descriptor);
@@ -2307,6 +2329,21 @@ class ActivityManagerProxy implements IActivityManager
reply.recycle();
return bm;
}
+ public Bitmap getTaskTopThumbnail(int id) throws RemoteException {
+ Parcel data = Parcel.obtain();
+ Parcel reply = Parcel.obtain();
+ data.writeInterfaceToken(IActivityManager.descriptor);
+ data.writeInt(id);
+ mRemote.transact(GET_TASK_TOP_THUMBNAIL_TRANSACTION, data, reply, 0);
+ reply.readException();
+ Bitmap bm = null;
+ if (reply.readInt() != 0) {
+ bm = Bitmap.CREATOR.createFromParcel(reply);
+ }
+ data.recycle();
+ reply.recycle();
+ return bm;
+ }
public List getServices(int maxNum, int flags) throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
@@ -3817,6 +3854,18 @@ class ActivityManagerProxy implements IActivityManager
return result;
}
+ public int[] getRunningUserIds() throws RemoteException {
+ Parcel data = Parcel.obtain();
+ Parcel reply = Parcel.obtain();
+ data.writeInterfaceToken(IActivityManager.descriptor);
+ mRemote.transact(GET_RUNNING_USER_IDS_TRANSACTION, data, reply, 0);
+ reply.readException();
+ int[] result = reply.createIntArray();
+ reply.recycle();
+ data.recycle();
+ return result;
+ }
+
public boolean removeSubTask(int taskId, int subTaskIndex) throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 9b82f2a..67ecf5b 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -52,6 +52,7 @@ import android.os.AsyncTask;
import android.os.Binder;
import android.os.Bundle;
import android.os.Debug;
+import android.os.DropBoxManager;
import android.os.Environment;
import android.os.Handler;
import android.os.IBinder;
@@ -108,6 +109,7 @@ import java.util.Map;
import java.util.TimeZone;
import java.util.regex.Pattern;
+import libcore.io.DropBox;
import libcore.io.EventLogger;
import libcore.io.IoUtils;
@@ -3636,39 +3638,45 @@ public final class ActivityThread {
}
}
- ArrayList<ComponentCallbacks2> collectComponentCallbacksLocked(
+ ArrayList<ComponentCallbacks2> collectComponentCallbacks(
boolean allActivities, Configuration newConfig) {
ArrayList<ComponentCallbacks2> callbacks
= new ArrayList<ComponentCallbacks2>();
- if (mActivities.size() > 0) {
- for (ActivityClientRecord ar : mActivities.values()) {
- Activity a = ar.activity;
- if (a != null) {
- Configuration thisConfig = applyConfigCompatMainThread(mCurDefaultDisplayDpi,
- newConfig, ar.packageInfo.mCompatibilityInfo.getIfNeeded());
- if (!ar.activity.mFinished && (allActivities || !ar.paused)) {
- // If the activity is currently resumed, its configuration
- // needs to change right now.
- callbacks.add(a);
- } else if (thisConfig != null) {
- // Otherwise, we will tell it about the change
- // the next time it is resumed or shown. Note that
- // the activity manager may, before then, decide the
- // activity needs to be destroyed to handle its new
- // configuration.
- if (DEBUG_CONFIGURATION) {
- Slog.v(TAG, "Setting activity "
- + ar.activityInfo.name + " newConfig=" + thisConfig);
+ synchronized (mPackages) {
+ final int N = mAllApplications.size();
+ for (int i=0; i<N; i++) {
+ callbacks.add(mAllApplications.get(i));
+ }
+ if (mActivities.size() > 0) {
+ for (ActivityClientRecord ar : mActivities.values()) {
+ Activity a = ar.activity;
+ if (a != null) {
+ Configuration thisConfig = applyConfigCompatMainThread(mCurDefaultDisplayDpi,
+ newConfig, ar.packageInfo.mCompatibilityInfo.getIfNeeded());
+ if (!ar.activity.mFinished && (allActivities || !ar.paused)) {
+ // If the activity is currently resumed, its configuration
+ // needs to change right now.
+ callbacks.add(a);
+ } else if (thisConfig != null) {
+ // Otherwise, we will tell it about the change
+ // the next time it is resumed or shown. Note that
+ // the activity manager may, before then, decide the
+ // activity needs to be destroyed to handle its new
+ // configuration.
+ if (DEBUG_CONFIGURATION) {
+ Slog.v(TAG, "Setting activity "
+ + ar.activityInfo.name + " newConfig=" + thisConfig);
+ }
+ ar.newConfig = thisConfig;
}
- ar.newConfig = thisConfig;
}
}
}
- }
- if (mServices.size() > 0) {
- for (Service service : mServices.values()) {
- callbacks.add(service);
+ if (mServices.size() > 0) {
+ for (Service service : mServices.values()) {
+ callbacks.add(service);
+ }
}
}
synchronized (mProviderMap) {
@@ -3678,10 +3686,6 @@ public final class ActivityThread {
}
}
}
- final int N = mAllApplications.size();
- for (int i=0; i<N; i++) {
- callbacks.add(mAllApplications.get(i));
- }
return callbacks;
}
@@ -3842,7 +3846,6 @@ public final class ActivityThread {
final void handleConfigurationChanged(Configuration config, CompatibilityInfo compat) {
- ArrayList<ComponentCallbacks2> callbacks = null;
int configDiff = 0;
synchronized (mPackages) {
@@ -3873,9 +3876,10 @@ public final class ActivityThread {
configDiff = mConfiguration.diff(config);
mConfiguration.updateFrom(config);
config = applyCompatConfiguration(mCurDefaultDisplayDpi);
- callbacks = collectComponentCallbacksLocked(false, config);
}
-
+
+ ArrayList<ComponentCallbacks2> callbacks = collectComponentCallbacks(false, config);
+
// Cleanup hardware accelerated stuff
WindowManagerGlobal.getInstance().trimLocalMemory();
@@ -3988,11 +3992,7 @@ public final class ActivityThread {
}
final void handleLowMemory() {
- ArrayList<ComponentCallbacks2> callbacks;
-
- synchronized (mPackages) {
- callbacks = collectComponentCallbacksLocked(true, null);
- }
+ ArrayList<ComponentCallbacks2> callbacks = collectComponentCallbacks(true, null);
final int N = callbacks.size();
for (int i=0; i<N; i++) {
@@ -4020,10 +4020,7 @@ public final class ActivityThread {
final WindowManagerGlobal windowManager = WindowManagerGlobal.getInstance();
windowManager.startTrimMemory(level);
- ArrayList<ComponentCallbacks2> callbacks;
- synchronized (mPackages) {
- callbacks = collectComponentCallbacksLocked(true, null);
- }
+ ArrayList<ComponentCallbacks2> callbacks = collectComponentCallbacks(true, null);
final int N = callbacks.size();
for (int i = 0; i < N; i++) {
@@ -4831,7 +4828,10 @@ public final class ActivityThread {
"Unable to instantiate Application():" + e.toString(), e);
}
}
-
+
+ // add dropbox logging to libcore
+ DropBox.setReporter(new DropBoxReporter());
+
ViewRootImpl.addConfigCallback(new ComponentCallbacks2() {
public void onConfigurationChanged(Configuration newConfig) {
synchronized (mPackages) {
@@ -4887,6 +4887,25 @@ public final class ActivityThread {
}
}
+ private class DropBoxReporter implements DropBox.Reporter {
+
+ private DropBoxManager dropBox;
+
+ public DropBoxReporter() {
+ dropBox = (DropBoxManager) getSystemContext().getSystemService(Context.DROPBOX_SERVICE);
+ }
+
+ @Override
+ public void addData(String tag, byte[] data, int flags) {
+ dropBox.addData(tag, data, flags);
+ }
+
+ @Override
+ public void addText(String tag, String data) {
+ dropBox.addText(tag, data);
+ }
+ }
+
public static void main(String[] args) {
SamplingProfilerIntegration.start();
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index 2fb17b6..ed17d0e 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -104,6 +104,7 @@ public interface IActivityManager extends IInterface {
public List<ActivityManager.RecentTaskInfo> getRecentTasks(int maxNum,
int flags, int userId) throws RemoteException;
public ActivityManager.TaskThumbnails getTaskThumbnails(int taskId) throws RemoteException;
+ public Bitmap getTaskTopThumbnail(int taskId) throws RemoteException;
public List getServices(int maxNum, int flags) throws RemoteException;
public List<ActivityManager.ProcessErrorStateInfo> getProcessesInErrorState()
throws RemoteException;
@@ -326,6 +327,7 @@ public interface IActivityManager extends IInterface {
public int stopUser(int userid, IStopUserCallback callback) throws RemoteException;
public UserInfo getCurrentUser() throws RemoteException;
public boolean isUserRunning(int userid) throws RemoteException;
+ public int[] getRunningUserIds() throws RemoteException;
public boolean removeSubTask(int taskId, int subTaskIndex) throws RemoteException;
@@ -548,7 +550,7 @@ public interface IActivityManager extends IInterface {
int UNBIND_BACKUP_AGENT_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+91;
int GET_UID_FOR_INTENT_SENDER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+92;
int HANDLE_INCOMING_USER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+93;
-
+ int GET_TASK_TOP_THUMBNAIL_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+94;
int KILL_APPLICATION_WITH_APPID_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+95;
int CLOSE_SYSTEM_DIALOGS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+96;
int GET_PROCESS_MEMORY_INFO_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+97;
@@ -610,4 +612,5 @@ public interface IActivityManager extends IInterface {
int STOP_USER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+153;
int REGISTER_USER_SWITCH_OBSERVER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+154;
int UNREGISTER_USER_SWITCH_OBSERVER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+155;
+ int GET_RUNNING_USER_IDS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+156;
}
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index cb83dc2..7896450 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -1923,6 +1923,7 @@ public class Notification implements Parcelable
contentView.setViewVisibility(rowId, View.GONE);
}
+
int i=0;
while (i < mTexts.size() && i < rowIds.length) {
CharSequence str = mTexts.get(i);
@@ -1933,11 +1934,11 @@ public class Notification implements Parcelable
i++;
}
- if (mTexts.size() > rowIds.length) {
- contentView.setViewVisibility(R.id.inbox_more, View.VISIBLE);
- } else {
- contentView.setViewVisibility(R.id.inbox_more, View.GONE);
- }
+ contentView.setViewVisibility(R.id.inbox_end_pad,
+ mTexts.size() > 0 ? View.VISIBLE : View.GONE);
+
+ contentView.setViewVisibility(R.id.inbox_more,
+ mTexts.size() > rowIds.length ? View.VISIBLE : View.GONE);
return contentView;
}
diff --git a/core/java/android/content/ContentService.java b/core/java/android/content/ContentService.java
index 0f6488a..5986dcd 100644
--- a/core/java/android/content/ContentService.java
+++ b/core/java/android/content/ContentService.java
@@ -154,11 +154,15 @@ public final class ContentService extends IContentService.Stub {
throw new IllegalArgumentException("You must pass a valid uri and observer");
}
+ // STOPSHIP: disable the multi-user permission checks until a solid fix for the
+ // content provider / observer case is in place.
+ /*
final int callingUser = UserHandle.getCallingUserId();
if (callingUser != userHandle) {
mContext.enforceCallingOrSelfPermission(Manifest.permission.INTERACT_ACROSS_USERS_FULL,
"no permission to observe other users' provider view");
}
+ */
if (userHandle < 0) {
if (userHandle == UserHandle.USER_CURRENT) {
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index e8507bc..b9518b8 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -1254,7 +1254,9 @@ public class Intent implements Parcelable, Cloneable {
* Activity Action: Launch application installer.
* <p>
* Input: The data must be a content: or file: URI at which the application
- * can be retrieved. You can optionally supply
+ * can be retrieved. As of {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR1},
+ * you can also use "package:<package-name>" to install an application for the
+ * current user that is already installed for another user. You can optionally supply
* {@link #EXTRA_INSTALLER_PACKAGE_NAME}, {@link #EXTRA_NOT_UNKNOWN_SOURCE},
* {@link #EXTRA_ALLOW_REPLACE}, and {@link #EXTRA_RETURN_RESULT}.
* <p>
@@ -2795,6 +2797,15 @@ public class Intent implements Parcelable, Cloneable {
public static final String EXTRA_DATA_REMOVED = "android.intent.extra.DATA_REMOVED";
/**
+ * @hide
+ * Used as a boolean extra field in {@link android.content.Intent#ACTION_PACKAGE_REMOVED}
+ * intents to indicate that at this point the package has been removed for
+ * all users on the device.
+ */
+ public static final String EXTRA_REMOVED_FOR_ALL_USERS
+ = "android.intent.extra.REMOVED_FOR_ALL_USERS";
+
+ /**
* Used as a boolean extra field in {@link android.content.Intent#ACTION_PACKAGE_REMOVED}
* intents to indicate that this is a replacement of the package, so this
* broadcast will immediately be followed by an add broadcast for a
diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java
index b316f23..492e5e9 100755
--- a/core/java/android/content/res/Resources.java
+++ b/core/java/android/content/res/Resources.java
@@ -1554,6 +1554,8 @@ public class Resources {
public static void updateSystemConfiguration(Configuration config, DisplayMetrics metrics,
CompatibilityInfo compat) {
if (mSystem != null) {
+ // TODO: Remove once b/7094175 is fixed
+ Slog.v(TAG, "updateSystemConfiguration: b/7094175 config=" + config);
mSystem.updateConfiguration(config, metrics, compat);
//Log.i(TAG, "Updated system resources " + mSystem
// + ": " + mSystem.getConfiguration());
diff --git a/core/java/android/hardware/display/DisplayManager.java b/core/java/android/hardware/display/DisplayManager.java
index 4347e75..58a0f13 100644
--- a/core/java/android/hardware/display/DisplayManager.java
+++ b/core/java/android/hardware/display/DisplayManager.java
@@ -160,6 +160,10 @@ public final class DisplayManager {
/**
* Connects to a Wifi display.
* The results are sent as a {@link #ACTION_WIFI_DISPLAY_STATUS_CHANGED} broadcast.
+ * <p>
+ * Automatically remembers the display after a successful connection, if not
+ * already remembered.
+ * </p>
*
* @param deviceAddress The MAC address of the device to which we should connect.
* @hide
@@ -178,6 +182,36 @@ public final class DisplayManager {
}
/**
+ * Renames a Wifi display.
+ * <p>
+ * The display must already be remembered for this call to succeed. In other words,
+ * we must already have successfully connected to the display at least once and then
+ * not forgotten it.
+ * </p>
+ *
+ * @param deviceAddress The MAC address of the device to rename.
+ * @param alias The alias name by which to remember the device, or null
+ * or empty if no alias should be used.
+ * @hide
+ */
+ public void renameWifiDisplay(String deviceAddress, String alias) {
+ mGlobal.renameWifiDisplay(deviceAddress, alias);
+ }
+
+ /**
+ * Forgets a previously remembered Wifi display.
+ * <p>
+ * Automatically disconnects from the display if currently connected to it.
+ * </p>
+ *
+ * @param deviceAddress The MAC address of the device to forget.
+ * @hide
+ */
+ public void forgetWifiDisplay(String deviceAddress) {
+ mGlobal.forgetWifiDisplay(deviceAddress);
+ }
+
+ /**
* Gets the current Wifi display status.
* Watch for changes in the status by registering a broadcast receiver for
* {@link #ACTION_WIFI_DISPLAY_STATUS_CHANGED}.
diff --git a/core/java/android/hardware/display/DisplayManagerGlobal.java b/core/java/android/hardware/display/DisplayManagerGlobal.java
index 14b5440..a858681 100644
--- a/core/java/android/hardware/display/DisplayManagerGlobal.java
+++ b/core/java/android/hardware/display/DisplayManagerGlobal.java
@@ -281,6 +281,31 @@ public final class DisplayManagerGlobal {
}
}
+ public void renameWifiDisplay(String deviceAddress, String alias) {
+ if (deviceAddress == null) {
+ throw new IllegalArgumentException("deviceAddress must not be null");
+ }
+
+ try {
+ mDm.renameWifiDisplay(deviceAddress, alias);
+ } catch (RemoteException ex) {
+ Log.e(TAG, "Failed to rename Wifi display " + deviceAddress
+ + " with alias " + alias + ".", ex);
+ }
+ }
+
+ public void forgetWifiDisplay(String deviceAddress) {
+ if (deviceAddress == null) {
+ throw new IllegalArgumentException("deviceAddress must not be null");
+ }
+
+ try {
+ mDm.forgetWifiDisplay(deviceAddress);
+ } catch (RemoteException ex) {
+ Log.e(TAG, "Failed to forget Wifi display.", ex);
+ }
+ }
+
public WifiDisplayStatus getWifiDisplayStatus() {
try {
return mDm.getWifiDisplayStatus();
diff --git a/core/java/android/hardware/display/IDisplayManager.aidl b/core/java/android/hardware/display/IDisplayManager.aidl
index 36a9a7f..4b6fb53 100644
--- a/core/java/android/hardware/display/IDisplayManager.aidl
+++ b/core/java/android/hardware/display/IDisplayManager.aidl
@@ -38,5 +38,11 @@ interface IDisplayManager {
void disconnectWifiDisplay();
// Requires CONFIGURE_WIFI_DISPLAY permission.
+ void renameWifiDisplay(String address, String alias);
+
+ // Requires CONFIGURE_WIFI_DISPLAY permission.
+ void forgetWifiDisplay(String address);
+
+ // Requires CONFIGURE_WIFI_DISPLAY permission.
WifiDisplayStatus getWifiDisplayStatus();
}
diff --git a/core/java/android/hardware/display/WifiDisplay.java b/core/java/android/hardware/display/WifiDisplay.java
index e51e97e..0138b1c 100644
--- a/core/java/android/hardware/display/WifiDisplay.java
+++ b/core/java/android/hardware/display/WifiDisplay.java
@@ -19,6 +19,8 @@ package android.hardware.display;
import android.os.Parcel;
import android.os.Parcelable;
+import libcore.util.Objects;
+
/**
* Describes the properties of a Wifi display.
* <p>
@@ -30,6 +32,7 @@ import android.os.Parcelable;
public final class WifiDisplay implements Parcelable {
private final String mDeviceAddress;
private final String mDeviceName;
+ private final String mDeviceAlias;
public static final WifiDisplay[] EMPTY_ARRAY = new WifiDisplay[0];
@@ -37,7 +40,8 @@ public final class WifiDisplay implements Parcelable {
public WifiDisplay createFromParcel(Parcel in) {
String deviceAddress = in.readString();
String deviceName = in.readString();
- return new WifiDisplay(deviceAddress, deviceName);
+ String deviceAlias = in.readString();
+ return new WifiDisplay(deviceAddress, deviceName, deviceAlias);
}
public WifiDisplay[] newArray(int size) {
@@ -45,7 +49,7 @@ public final class WifiDisplay implements Parcelable {
}
};
- public WifiDisplay(String deviceAddress, String deviceName) {
+ public WifiDisplay(String deviceAddress, String deviceName, String deviceAlias) {
if (deviceAddress == null) {
throw new IllegalArgumentException("deviceAddress must not be null");
}
@@ -55,6 +59,7 @@ public final class WifiDisplay implements Parcelable {
mDeviceAddress = deviceAddress;
mDeviceName = deviceName;
+ mDeviceAlias = deviceAlias;
}
/**
@@ -71,6 +76,25 @@ public final class WifiDisplay implements Parcelable {
return mDeviceName;
}
+ /**
+ * Gets the user-specified alias of the Wifi display device, or null if none.
+ * <p>
+ * The alias should be used in the UI whenever available. It is the value
+ * provided by the user when renaming the device.
+ * </p>
+ */
+ public String getDeviceAlias() {
+ return mDeviceAlias;
+ }
+
+ /**
+ * Gets the name to show in the UI.
+ * Uses the device alias if available, otherwise uses the device name.
+ */
+ public String getFriendlyDisplayName() {
+ return mDeviceAlias != null ? mDeviceAlias : mDeviceName;
+ }
+
@Override
public boolean equals(Object o) {
return o instanceof WifiDisplay && equals((WifiDisplay)o);
@@ -79,7 +103,8 @@ public final class WifiDisplay implements Parcelable {
public boolean equals(WifiDisplay other) {
return other != null
&& mDeviceAddress.equals(other.mDeviceAddress)
- && mDeviceName.equals(other.mDeviceName);
+ && mDeviceName.equals(other.mDeviceName)
+ && Objects.equal(mDeviceAlias, other.mDeviceAlias);
}
@Override
@@ -92,6 +117,7 @@ public final class WifiDisplay implements Parcelable {
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(mDeviceAddress);
dest.writeString(mDeviceName);
+ dest.writeString(mDeviceAlias);
}
@Override
@@ -102,6 +128,10 @@ public final class WifiDisplay implements Parcelable {
// For debugging purposes only.
@Override
public String toString() {
- return mDeviceName + " (" + mDeviceAddress + ")";
+ String result = mDeviceName + " (" + mDeviceAddress + ")";
+ if (mDeviceAlias != null) {
+ result += ", alias " + mDeviceAlias;
+ }
+ return result;
}
}
diff --git a/core/java/android/hardware/display/WifiDisplayStatus.java b/core/java/android/hardware/display/WifiDisplayStatus.java
index d5fe45d..f7e72c4 100644
--- a/core/java/android/hardware/display/WifiDisplayStatus.java
+++ b/core/java/android/hardware/display/WifiDisplayStatus.java
@@ -23,7 +23,7 @@ import java.util.Arrays;
/**
* Describes the current global state of Wifi display connectivity, including the
- * currently connected display and all known displays.
+ * currently connected display and all available or remembered displays.
* <p>
* This object is immutable.
* </p>
@@ -31,22 +31,37 @@ import java.util.Arrays;
* @hide
*/
public final class WifiDisplayStatus implements Parcelable {
- private final boolean mEnabled;
+ private final int mFeatureState;
private final int mScanState;
private final int mActiveDisplayState;
private final WifiDisplay mActiveDisplay;
- private final WifiDisplay[] mKnownDisplays;
-
+ private final WifiDisplay[] mAvailableDisplays;
+ private final WifiDisplay[] mRememberedDisplays;
+
+ /** Feature state: Wifi display is not available on this device. */
+ public static final int FEATURE_STATE_UNAVAILABLE = 0;
+ /** Feature state: Wifi display is disabled, probably because Wifi is disabled. */
+ public static final int FEATURE_STATE_DISABLED = 1;
+ /** Feature state: Wifi display is turned off in settings. */
+ public static final int FEATURE_STATE_OFF = 2;
+ /** Feature state: Wifi display is turned on in settings. */
+ public static final int FEATURE_STATE_ON = 3;
+
+ /** Scan state: Not currently scanning. */
public static final int SCAN_STATE_NOT_SCANNING = 0;
+ /** Scan state: Currently scanning. */
public static final int SCAN_STATE_SCANNING = 1;
+ /** Display state: Not connected. */
public static final int DISPLAY_STATE_NOT_CONNECTED = 0;
+ /** Display state: Connecting to active display. */
public static final int DISPLAY_STATE_CONNECTING = 1;
+ /** Display state: Connected to active display. */
public static final int DISPLAY_STATE_CONNECTED = 2;
public static final Creator<WifiDisplayStatus> CREATOR = new Creator<WifiDisplayStatus>() {
public WifiDisplayStatus createFromParcel(Parcel in) {
- boolean enabled = (in.readInt() != 0);
+ int featureState = in.readInt();
int scanState = in.readInt();
int activeDisplayState= in.readInt();
@@ -55,13 +70,18 @@ public final class WifiDisplayStatus implements Parcelable {
activeDisplay = WifiDisplay.CREATOR.createFromParcel(in);
}
- WifiDisplay[] knownDisplays = WifiDisplay.CREATOR.newArray(in.readInt());
- for (int i = 0; i < knownDisplays.length; i++) {
- knownDisplays[i] = WifiDisplay.CREATOR.createFromParcel(in);
+ WifiDisplay[] availableDisplays = WifiDisplay.CREATOR.newArray(in.readInt());
+ for (int i = 0; i < availableDisplays.length; i++) {
+ availableDisplays[i] = WifiDisplay.CREATOR.createFromParcel(in);
+ }
+
+ WifiDisplay[] rememberedDisplays = WifiDisplay.CREATOR.newArray(in.readInt());
+ for (int i = 0; i < rememberedDisplays.length; i++) {
+ rememberedDisplays[i] = WifiDisplay.CREATOR.createFromParcel(in);
}
- return new WifiDisplayStatus(enabled, scanState, activeDisplayState,
- activeDisplay, knownDisplays);
+ return new WifiDisplayStatus(featureState, scanState, activeDisplayState,
+ activeDisplay, availableDisplays, rememberedDisplays);
}
public WifiDisplayStatus[] newArray(int size) {
@@ -70,33 +90,38 @@ public final class WifiDisplayStatus implements Parcelable {
};
public WifiDisplayStatus() {
- this(false, SCAN_STATE_NOT_SCANNING, DISPLAY_STATE_NOT_CONNECTED,
- null, WifiDisplay.EMPTY_ARRAY);
+ this(FEATURE_STATE_UNAVAILABLE, SCAN_STATE_NOT_SCANNING, DISPLAY_STATE_NOT_CONNECTED,
+ null, WifiDisplay.EMPTY_ARRAY, WifiDisplay.EMPTY_ARRAY);
}
- public WifiDisplayStatus(boolean enabled, int scanState, int activeDisplayState,
- WifiDisplay activeDisplay, WifiDisplay[] knownDisplays) {
- if (knownDisplays == null) {
- throw new IllegalArgumentException("knownDisplays must not be null");
+ public WifiDisplayStatus(int featureState, int scanState,
+ int activeDisplayState, WifiDisplay activeDisplay,
+ WifiDisplay[] availableDisplays, WifiDisplay[] rememberedDisplays) {
+ if (availableDisplays == null) {
+ throw new IllegalArgumentException("availableDisplays must not be null");
+ }
+ if (rememberedDisplays == null) {
+ throw new IllegalArgumentException("rememberedDisplays must not be null");
}
- mEnabled = enabled;
+ mFeatureState = featureState;
mScanState = scanState;
mActiveDisplayState = activeDisplayState;
mActiveDisplay = activeDisplay;
- mKnownDisplays = knownDisplays;
+ mAvailableDisplays = availableDisplays;
+ mRememberedDisplays = rememberedDisplays;
}
/**
- * Returns true if the Wifi display feature is enabled and available for use.
+ * Returns the state of the Wifi display feature on this device.
* <p>
- * The value of this property reflects whether Wifi and Wifi P2P functions
- * are enabled. Enablement is not directly controllable by the user at this
- * time, except indirectly such as by turning off Wifi altogether.
+ * The value of this property reflects whether the device supports the Wifi display,
+ * whether it has been enabled by the user and whether the prerequisites for
+ * connecting to displays have been met.
* </p>
*/
- public boolean isEnabled() {
- return mEnabled;
+ public int getFeatureState() {
+ return mFeatureState;
}
/**
@@ -127,15 +152,29 @@ public final class WifiDisplayStatus implements Parcelable {
}
/**
- * Gets the list of all known Wifi displays, never null.
+ * Gets the list of all available Wifi displays as reported by the most recent
+ * scan, never null.
+ * <p>
+ * Some of these displays may already be remembered, others may be unknown.
+ * </p>
*/
- public WifiDisplay[] getKnownDisplays() {
- return mKnownDisplays;
+ public WifiDisplay[] getAvailableDisplays() {
+ return mAvailableDisplays;
+ }
+
+ /**
+ * Gets the list of all remembered Wifi displays, never null.
+ * <p>
+ * Not all remembered displays will necessarily be available.
+ * </p>
+ */
+ public WifiDisplay[] getRememberedDisplays() {
+ return mRememberedDisplays;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
- dest.writeInt(mEnabled ? 1 : 0);
+ dest.writeInt(mFeatureState);
dest.writeInt(mScanState);
dest.writeInt(mActiveDisplayState);
@@ -146,8 +185,13 @@ public final class WifiDisplayStatus implements Parcelable {
dest.writeInt(0);
}
- dest.writeInt(mKnownDisplays.length);
- for (WifiDisplay display : mKnownDisplays) {
+ dest.writeInt(mAvailableDisplays.length);
+ for (WifiDisplay display : mAvailableDisplays) {
+ display.writeToParcel(dest, flags);
+ }
+
+ dest.writeInt(mRememberedDisplays.length);
+ for (WifiDisplay display : mRememberedDisplays) {
display.writeToParcel(dest, flags);
}
}
@@ -160,11 +204,12 @@ public final class WifiDisplayStatus implements Parcelable {
// For debugging purposes only.
@Override
public String toString() {
- return "WifiDisplayStatus{enabled=" + mEnabled
+ return "WifiDisplayStatus{featureState=" + mFeatureState
+ ", scanState=" + mScanState
+ ", activeDisplayState=" + mActiveDisplayState
+ ", activeDisplay=" + mActiveDisplay
- + ", knownDisplays=" + Arrays.toString(mKnownDisplays)
+ + ", availableDisplays=" + Arrays.toString(mAvailableDisplays)
+ + ", rememberedDisplays=" + Arrays.toString(mRememberedDisplays)
+ "}";
}
}
diff --git a/core/java/android/net/CaptivePortalTracker.java b/core/java/android/net/CaptivePortalTracker.java
index 8218e37..24dc898 100644
--- a/core/java/android/net/CaptivePortalTracker.java
+++ b/core/java/android/net/CaptivePortalTracker.java
@@ -16,6 +16,7 @@
package android.net;
+import android.app.Activity;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
@@ -24,33 +25,32 @@ import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.res.Resources;
-import android.database.ContentObserver;
import android.net.ConnectivityManager;
import android.net.IConnectivityManager;
-import android.os.Handler;
-import android.os.HandlerThread;
-import android.os.Looper;
+import android.os.UserHandle;
import android.os.Message;
import android.os.RemoteException;
import android.provider.Settings;
import android.util.Log;
+import com.android.internal.util.State;
+import com.android.internal.util.StateMachine;
+
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.InetAddress;
import java.net.Inet4Address;
import java.net.URL;
import java.net.UnknownHostException;
-import java.util.concurrent.atomic.AtomicBoolean;
import com.android.internal.R;
/**
- * This class allows captive portal detection
+ * This class allows captive portal detection on a network.
* @hide
*/
-public class CaptivePortalTracker {
- private static final boolean DBG = true;
+public class CaptivePortalTracker extends StateMachine {
+ private static final boolean DBG = false;
private static final String TAG = "CaptivePortalTracker";
private static final String DEFAULT_SERVER = "clients3.google.com";
@@ -62,37 +62,31 @@ public class CaptivePortalTracker {
private String mUrl;
private boolean mNotificationShown = false;
private boolean mIsCaptivePortalCheckEnabled = false;
- private InternalHandler mHandler;
private IConnectivityManager mConnService;
private Context mContext;
private NetworkInfo mNetworkInfo;
- private boolean mIsCaptivePortal = false;
- private static final int DETECT_PORTAL = 0;
- private static final int HANDLE_CONNECT = 1;
+ private static final int CMD_DETECT_PORTAL = 0;
+ private static final int CMD_CONNECTIVITY_CHANGE = 1;
+ private static final int CMD_DELAYED_CAPTIVE_CHECK = 2;
- /**
- * Activity Action: Switch to the captive portal network
- * <p>Input: Nothing.
- * <p>Output: Nothing.
- */
- public static final String ACTION_SWITCH_TO_CAPTIVE_PORTAL
- = "android.net.SWITCH_TO_CAPTIVE_PORTAL";
+ /* This delay happens every time before we do a captive check on a network */
+ private static final int DELAYED_CHECK_INTERVAL_MS = 10000;
+ private int mDelayedCheckToken = 0;
+
+ private State mDefaultState = new DefaultState();
+ private State mNoActiveNetworkState = new NoActiveNetworkState();
+ private State mActiveNetworkState = new ActiveNetworkState();
+ private State mDelayedCaptiveCheckState = new DelayedCaptiveCheckState();
+
+ private CaptivePortalTracker(Context context, IConnectivityManager cs) {
+ super(TAG);
- private CaptivePortalTracker(Context context, NetworkInfo info, IConnectivityManager cs) {
mContext = context;
- mNetworkInfo = info;
mConnService = cs;
- HandlerThread handlerThread = new HandlerThread("CaptivePortalThread");
- handlerThread.start();
- mHandler = new InternalHandler(handlerThread.getLooper());
- mHandler.obtainMessage(DETECT_PORTAL).sendToTarget();
-
IntentFilter filter = new IntentFilter();
- filter.addAction(ACTION_SWITCH_TO_CAPTIVE_PORTAL);
filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
-
mContext.registerReceiver(mReceiver, filter);
mServer = Settings.Secure.getString(mContext.getContentResolver(),
@@ -101,100 +95,180 @@ public class CaptivePortalTracker {
mIsCaptivePortalCheckEnabled = Settings.Secure.getInt(mContext.getContentResolver(),
Settings.Secure.CAPTIVE_PORTAL_DETECTION_ENABLED, 1) == 1;
+
+ addState(mDefaultState);
+ addState(mNoActiveNetworkState, mDefaultState);
+ addState(mActiveNetworkState, mDefaultState);
+ addState(mDelayedCaptiveCheckState, mActiveNetworkState);
+ setInitialState(mNoActiveNetworkState);
}
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
- if (action.equals(ACTION_SWITCH_TO_CAPTIVE_PORTAL)) {
- notifyPortalCheckComplete();
- } else if (action.equals(ConnectivityManager.CONNECTIVITY_ACTION)) {
+ if (action.equals(ConnectivityManager.CONNECTIVITY_ACTION)) {
NetworkInfo info = intent.getParcelableExtra(
ConnectivityManager.EXTRA_NETWORK_INFO);
- mHandler.obtainMessage(HANDLE_CONNECT, info).sendToTarget();
+ sendMessage(obtainMessage(CMD_CONNECTIVITY_CHANGE, info));
}
}
};
- public static CaptivePortalTracker detect(Context context, NetworkInfo info,
+ public static CaptivePortalTracker makeCaptivePortalTracker(Context context,
IConnectivityManager cs) {
- CaptivePortalTracker captivePortal = new CaptivePortalTracker(context, info, cs);
+ CaptivePortalTracker captivePortal = new CaptivePortalTracker(context, cs);
+ captivePortal.start();
return captivePortal;
}
- private class InternalHandler extends Handler {
- public InternalHandler(Looper looper) {
- super(looper);
+ public void detectCaptivePortal(NetworkInfo info) {
+ sendMessage(obtainMessage(CMD_DETECT_PORTAL, info));
+ }
+
+ private class DefaultState extends State {
+ @Override
+ public void enter() {
+ if (DBG) log(getName() + "\n");
}
@Override
- public void handleMessage(Message msg) {
- switch (msg.what) {
- case DETECT_PORTAL:
- InetAddress server = lookupHost(mServer);
- if (server != null) {
- requestRouteToHost(server);
- if (isCaptivePortal(server)) {
- if (DBG) log("Captive portal " + mNetworkInfo);
- setNotificationVisible(true);
- mIsCaptivePortal = true;
- break;
- }
- }
- notifyPortalCheckComplete();
- quit();
+ public boolean processMessage(Message message) {
+ if (DBG) log(getName() + message.toString() + "\n");
+ switch (message.what) {
+ case CMD_DETECT_PORTAL:
+ NetworkInfo info = (NetworkInfo) message.obj;
+ // Checking on a secondary connection is not supported
+ // yet
+ notifyPortalCheckComplete(info);
break;
- case HANDLE_CONNECT:
- NetworkInfo info = (NetworkInfo) msg.obj;
- if (info.getType() != mNetworkInfo.getType()) break;
+ case CMD_CONNECTIVITY_CHANGE:
+ case CMD_DELAYED_CAPTIVE_CHECK:
+ break;
+ default:
+ loge("Ignoring " + message);
+ break;
+ }
+ return HANDLED;
+ }
+ }
- if (info.getState() == NetworkInfo.State.CONNECTED ||
- info.getState() == NetworkInfo.State.DISCONNECTED) {
- setNotificationVisible(false);
- }
+ private class NoActiveNetworkState extends State {
+ @Override
+ public void enter() {
+ if (DBG) log(getName() + "\n");
+ mNetworkInfo = null;
+ /* Clear any previous notification */
+ setNotificationVisible(false);
+ }
- /* Connected to a captive portal */
- if (info.getState() == NetworkInfo.State.CONNECTED &&
- mIsCaptivePortal) {
- launchBrowser();
- quit();
+ @Override
+ public boolean processMessage(Message message) {
+ if (DBG) log(getName() + message.toString() + "\n");
+ InetAddress server;
+ NetworkInfo info;
+ switch (message.what) {
+ case CMD_CONNECTIVITY_CHANGE:
+ info = (NetworkInfo) message.obj;
+ if (info.isConnected() && isActiveNetwork(info)) {
+ mNetworkInfo = info;
+ transitionTo(mDelayedCaptiveCheckState);
}
break;
default:
- loge("Unhandled message " + msg);
- break;
+ return NOT_HANDLED;
}
+ return HANDLED;
+ }
+ }
+
+ private class ActiveNetworkState extends State {
+ @Override
+ public void enter() {
+ if (DBG) log(getName() + "\n");
}
- private void quit() {
- mIsCaptivePortal = false;
- getLooper().quit();
- mContext.unregisterReceiver(mReceiver);
+ @Override
+ public boolean processMessage(Message message) {
+ NetworkInfo info;
+ switch (message.what) {
+ case CMD_CONNECTIVITY_CHANGE:
+ info = (NetworkInfo) message.obj;
+ if (!info.isConnected()
+ && info.getType() == mNetworkInfo.getType()) {
+ if (DBG) log("Disconnected from active network " + info);
+ transitionTo(mNoActiveNetworkState);
+ } else if (info.getType() != mNetworkInfo.getType() &&
+ info.isConnected() &&
+ isActiveNetwork(info)) {
+ if (DBG) log("Active network switched " + info);
+ deferMessage(message);
+ transitionTo(mNoActiveNetworkState);
+ }
+ break;
+ default:
+ return NOT_HANDLED;
+ }
+ return HANDLED;
}
}
- private void launchBrowser() {
- Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(mUrl));
- intent.setFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT | Intent.FLAG_ACTIVITY_NEW_TASK);
- mContext.startActivity(intent);
+
+
+ private class DelayedCaptiveCheckState extends State {
+ @Override
+ public void enter() {
+ if (DBG) log(getName() + "\n");
+ sendMessageDelayed(obtainMessage(CMD_DELAYED_CAPTIVE_CHECK,
+ ++mDelayedCheckToken, 0), DELAYED_CHECK_INTERVAL_MS);
+ }
+
+ @Override
+ public boolean processMessage(Message message) {
+ if (DBG) log(getName() + message.toString() + "\n");
+ switch (message.what) {
+ case CMD_DELAYED_CAPTIVE_CHECK:
+ if (message.arg1 == mDelayedCheckToken) {
+ InetAddress server = lookupHost(mServer);
+ if (server != null) {
+ if (isCaptivePortal(server)) {
+ if (DBG) log("Captive network " + mNetworkInfo);
+ setNotificationVisible(true);
+ }
+ }
+ if (DBG) log("Not captive network " + mNetworkInfo);
+ transitionTo(mActiveNetworkState);
+ }
+ break;
+ default:
+ return NOT_HANDLED;
+ }
+ return HANDLED;
+ }
}
- private void notifyPortalCheckComplete() {
+ private void notifyPortalCheckComplete(NetworkInfo info) {
+ if (info == null) {
+ loge("notifyPortalCheckComplete on null");
+ return;
+ }
try {
- mConnService.captivePortalCheckComplete(mNetworkInfo);
+ mConnService.captivePortalCheckComplete(info);
} catch(RemoteException e) {
e.printStackTrace();
}
}
- private void requestRouteToHost(InetAddress server) {
+ private boolean isActiveNetwork(NetworkInfo info) {
try {
- mConnService.requestRouteToHostAddress(mNetworkInfo.getType(),
- server.getAddress());
+ NetworkInfo active = mConnService.getActiveNetworkInfo();
+ if (active != null && active.getType() == info.getType()) {
+ return true;
+ }
} catch (RemoteException e) {
e.printStackTrace();
}
+ return false;
}
/**
@@ -205,6 +279,7 @@ public class CaptivePortalTracker {
if (!mIsCaptivePortalCheckEnabled) return false;
mUrl = "http://" + server.getHostAddress() + "/generate_204";
+ if (DBG) log("Checking " + mUrl);
try {
URL url = new URL(mUrl);
urlConnection = (HttpURLConnection) url.openConnection();
@@ -250,7 +325,12 @@ public class CaptivePortalTracker {
.getSystemService(Context.NOTIFICATION_SERVICE);
if (visible) {
- CharSequence title = r.getString(R.string.wifi_available_sign_in, 0);
+ CharSequence title;
+ if (mNetworkInfo.getType() == ConnectivityManager.TYPE_WIFI) {
+ title = r.getString(R.string.wifi_available_sign_in, 0);
+ } else {
+ title = r.getString(R.string.network_available_sign_in, 0);
+ }
CharSequence details = r.getString(R.string.network_available_sign_in_detailed,
mNetworkInfo.getExtraInfo());
@@ -258,9 +338,10 @@ public class CaptivePortalTracker {
notification.when = 0;
notification.icon = com.android.internal.R.drawable.stat_notify_wifi_in_range;
notification.flags = Notification.FLAG_AUTO_CANCEL;
- notification.contentIntent = PendingIntent.getBroadcast(mContext, 0,
- new Intent(CaptivePortalTracker.ACTION_SWITCH_TO_CAPTIVE_PORTAL), 0);
-
+ Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(mUrl));
+ intent.setFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT |
+ Intent.FLAG_ACTIVITY_NEW_TASK);
+ notification.contentIntent = PendingIntent.getActivity(mContext, 0, intent, 0);
notification.tickerText = title;
notification.setLatestEventInfo(mContext, title, details, notification.contentIntent);
diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java
index fb7a4f8..446bbf0 100644
--- a/core/java/android/net/NetworkStats.java
+++ b/core/java/android/net/NetworkStats.java
@@ -21,6 +21,7 @@ import android.os.Parcelable;
import android.os.SystemClock;
import android.util.SparseBooleanArray;
+import com.android.internal.util.ArrayUtils;
import com.android.internal.util.Objects;
import java.io.CharArrayWriter;
@@ -608,13 +609,13 @@ public class NetworkStats implements Parcelable {
* Return all rows except those attributed to the requested UID; doesn't
* mutate the original structure.
*/
- public NetworkStats withoutUid(int uid) {
+ public NetworkStats withoutUids(int[] uids) {
final NetworkStats stats = new NetworkStats(elapsedRealtime, 10);
Entry entry = new Entry();
for (int i = 0; i < size; i++) {
entry = getValues(i, entry);
- if (entry.uid != uid) {
+ if (!ArrayUtils.contains(uids, entry.uid)) {
stats.addValues(entry);
}
}
diff --git a/core/java/android/os/Environment.java b/core/java/android/os/Environment.java
index 1607b96..364004b 100644
--- a/core/java/android/os/Environment.java
+++ b/core/java/android/os/Environment.java
@@ -32,6 +32,7 @@ public class Environment {
private static final String ENV_EXTERNAL_STORAGE = "EXTERNAL_STORAGE";
private static final String ENV_EMULATED_STORAGE_TARGET = "EMULATED_STORAGE_TARGET";
+ private static final String ENV_MEDIA_STORAGE = "MEDIA_STORAGE";
/** {@hide} */
public static String DIRECTORY_ANDROID = "Android";
@@ -88,21 +89,30 @@ public class Environment {
private final File mExternalStorageAndroidData;
private final File mExternalStorageAndroidMedia;
private final File mExternalStorageAndroidObb;
+ private final File mMediaStorage;
public UserEnvironment(int userId) {
// See storage config details at http://source.android.com/tech/storage/
String rawExternalStorage = System.getenv(ENV_EXTERNAL_STORAGE);
String rawEmulatedStorageTarget = System.getenv(ENV_EMULATED_STORAGE_TARGET);
+ String rawMediaStorage = System.getenv(ENV_MEDIA_STORAGE);
+ if (TextUtils.isEmpty(rawMediaStorage)) {
+ rawMediaStorage = "/data/media";
+ }
if (!TextUtils.isEmpty(rawEmulatedStorageTarget)) {
// Device has emulated storage; external storage paths should have
// userId burned into them.
+ final String rawUserId = Integer.toString(userId);
final File emulatedBase = new File(rawEmulatedStorageTarget);
+ final File mediaBase = new File(rawMediaStorage);
// /storage/emulated/0
- mExternalStorage = buildPath(emulatedBase, Integer.toString(userId));
+ mExternalStorage = buildPath(emulatedBase, rawUserId);
// /storage/emulated/obb
mExternalStorageAndroidObb = buildPath(emulatedBase, "obb");
+ // /data/media/0
+ mMediaStorage = buildPath(mediaBase, rawUserId);
} else {
// Device has physical external storage; use plain paths.
@@ -115,6 +125,8 @@ public class Environment {
mExternalStorage = new File(rawExternalStorage);
// /storage/sdcard0/Android/obb
mExternalStorageAndroidObb = buildPath(mExternalStorage, DIRECTORY_ANDROID, "obb");
+ // /data/media
+ mMediaStorage = new File(rawMediaStorage);
}
mExternalStorageAndroidData = buildPath(mExternalStorage, DIRECTORY_ANDROID, "data");
@@ -152,6 +164,10 @@ public class Environment {
public File getExternalStorageAppCacheDirectory(String packageName) {
return new File(new File(mExternalStorageAndroidData, packageName), "cache");
}
+
+ public File getMediaStorageDirectory() {
+ return mMediaStorage;
+ }
}
/**
@@ -198,7 +214,8 @@ public class Environment {
* @hide
*/
public static File getMediaStorageDirectory() {
- return MEDIA_STORAGE_DIRECTORY;
+ throwIfSystem();
+ return sCurrentUser.getMediaStorageDirectory();
}
/**
@@ -231,10 +248,6 @@ public class Environment {
private static final File SECURE_DATA_DIRECTORY
= getDirectory("ANDROID_SECURE_DATA", "/data/secure");
- /** @hide */
- private static final File MEDIA_STORAGE_DIRECTORY
- = getDirectory("MEDIA_STORAGE", "/data/media");
-
private static final File DOWNLOAD_CACHE_DIRECTORY = getDirectory("DOWNLOAD_CACHE", "/cache");
/**
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index 44b0b62..b532966 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -44,7 +44,7 @@ public class UserManager {
* @return true if multiple users can be created, false if it is a single user device.
* @hide
*/
- public boolean supportsMultipleUsers() {
+ public static boolean supportsMultipleUsers() {
return getMaxSupportedUsers() > 1;
}
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 68ce72f..cc9abff 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -214,6 +214,21 @@ public final class Settings {
"android.settings.BLUETOOTH_SETTINGS";
/**
+ * Activity Action: Show settings to allow configuration of Wifi Displays.
+ * <p>
+ * In some cases, a matching Activity may not exist, so ensure you
+ * safeguard against this.
+ * <p>
+ * Input: Nothing.
+ * <p>
+ * Output: Nothing.
+ * @hide
+ */
+ @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+ public static final String ACTION_WIFI_DISPLAY_SETTINGS =
+ "android.settings.WIFI_DISPLAY_SETTINGS";
+
+ /**
* Activity Action: Show settings to allow configuration of date and time.
* <p>
* In some cases, a matching Activity may not exist, so ensure you
@@ -919,6 +934,7 @@ public final class Settings {
MOVED_TO_GLOBAL.add(Settings.Global.POWER_SOUNDS_ENABLED);
MOVED_TO_GLOBAL.add(Settings.Global.STAY_ON_WHILE_PLUGGED_IN);
MOVED_TO_GLOBAL.add(Settings.Global.WIFI_SLEEP_POLICY);
+ MOVED_TO_GLOBAL.add(Settings.Global.MODE_RINGER);
}
private static void lazyInitCache() {
@@ -1338,7 +1354,7 @@ public final class Settings {
/** @deprecated - Do not use */
@Deprecated
public static void setShowGTalkServiceStatus(ContentResolver cr, boolean flag) {
- /* intentionally empty */
+ setShowGTalkServiceStatusForUser(cr, flag, UserHandle.myUserId());
}
/**
@@ -1482,6 +1498,12 @@ public final class Settings {
@Deprecated
public static final int WIFI_SLEEP_POLICY_NEVER = Global.WIFI_SLEEP_POLICY_NEVER;
+ /**
+ * @deprecated Use {@link android.provider.Settings.Global#MODE_RINGER} instead
+ */
+ @Deprecated
+ public static final String MODE_RINGER = Global.MODE_RINGER;
+
//TODO: deprecate static IP constants
/**
* Whether to use static IP and other static network attributes.
@@ -1651,13 +1673,6 @@ public final class Settings {
public static final String ALWAYS_FINISH_ACTIVITIES =
"always_finish_activities";
-
- /**
- * Ringer mode. This is used internally, changing this value will not
- * change the ringer mode. See AudioManager.
- */
- public static final String MODE_RINGER = "mode_ringer";
-
/**
* Determines which streams are affected by ringer mode changes. The
* stream type's bit should be set to 1 if it should be muted when going
@@ -5540,6 +5555,13 @@ public final class Settings {
"web_autofill_query_url";
/**
+ * Whether Wifi display is enabled/disabled
+ * 0=disabled. 1=enabled.
+ * @hide
+ */
+ public static final String WIFI_DISPLAY_ON = "wifi_display_on";
+
+ /**
* Whether to notify the user of open networks.
* <p>
* If not connected and the scan results have an open network, we will
@@ -5716,7 +5738,11 @@ public final class Settings {
*/
public static final String WTF_IS_FATAL = "wtf_is_fatal";
-
+ /**
+ * Ringer mode. This is used internally, changing this value will not
+ * change the ringer mode. See AudioManager.
+ */
+ public static final String MODE_RINGER = "mode_ringer";
// Populated lazily, guarded by class object:
diff --git a/core/java/android/service/dreams/Dream.java b/core/java/android/service/dreams/Dream.java
index ba2ac67..4a23d39 100644
--- a/core/java/android/service/dreams/Dream.java
+++ b/core/java/android/service/dreams/Dream.java
@@ -22,7 +22,6 @@ import android.content.Intent;
import android.graphics.drawable.ColorDrawable;
import android.os.Handler;
import android.os.IBinder;
-import android.os.RemoteException;
import android.os.ServiceManager;
import android.util.Slog;
import android.view.ActionMode;
@@ -40,12 +39,16 @@ import android.view.accessibility.AccessibilityEvent;
import com.android.internal.policy.PolicyManager;
/**
- * Extend this class to implement a custom screensaver.
+ * Extend this class to implement a custom Dream.
+ *
+ * <p>Dreams are interactive screensavers launched when a charging device is idle, or docked in a
+ * desk dock. Dreams provide another modality for apps to express themselves, tailored for
+ * an exhibition/lean-back experience.</p>
*/
public class Dream extends Service implements Window.Callback {
private final static boolean DEBUG = true;
- private final static String TAG = "Dream";
-
+ private final String TAG = Dream.class.getSimpleName() + "[" + getClass().getSimpleName() + "]";
+
/**
* The {@link Intent} that must be declared as handled by the service.
* To be supported, the service must also require the
@@ -60,28 +63,43 @@ public class Dream extends Service implements Window.Callback {
public static final String METADATA_NAME_CONFIG_ACTIVITY =
"android.service.dreams.config_activity";
- private Window mWindow;
+ /**
+ * Broadcast Action: Sent after the system starts dreaming.
+ *
+ * <p class="note">This is a protected intent that can only be sent by the system.
+ * It is only sent to registered receivers.</p>
+ */
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ public static final String ACTION_DREAMING_STARTED = "android.intent.action.DREAMING_STARTED";
+ /**
+ * Broadcast Action: Sent after the system stops dreaming.
+ *
+ * <p class="note">This is a protected intent that can only be sent by the system.
+ * It is only sent to registered receivers.</p>
+ */
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ public static final String ACTION_DREAMING_STOPPED = "android.intent.action.DREAMING_STOPPED";
+
+ private final Handler mHandler = new Handler();
+ private IBinder mWindowToken;
+ private Window mWindow;
private WindowManager mWindowManager;
private IDreamManager mSandman;
-
private boolean mInteractive;
-
- final Handler mHandler = new Handler();
-
- boolean mFinished = false;
+ private boolean mFinished;
// begin Window.Callback methods
@Override
public boolean dispatchKeyEvent(KeyEvent event) {
// TODO: create more flexible version of mInteractive that allows use of KEYCODE_BACK
if (!mInteractive) {
- if (DEBUG) Slog.v(TAG, "finishing on keyEvent");
- finish();
+ if (DEBUG) Slog.v(TAG, "Finishing on keyEvent");
+ safelyFinish();
return true;
} else if (event.getKeyCode() == KeyEvent.KEYCODE_BACK) {
- if (DEBUG) Slog.v(TAG, "finishing on back key");
- finish();
+ if (DEBUG) Slog.v(TAG, "Finishing on back key");
+ safelyFinish();
return true;
}
return mWindow.superDispatchKeyEvent(event);
@@ -90,8 +108,8 @@ public class Dream extends Service implements Window.Callback {
@Override
public boolean dispatchKeyShortcutEvent(KeyEvent event) {
if (!mInteractive) {
- if (DEBUG) Slog.v(TAG, "finishing on keyShortcutEvent");
- finish();
+ if (DEBUG) Slog.v(TAG, "Finishing on keyShortcutEvent");
+ safelyFinish();
return true;
}
return mWindow.superDispatchKeyShortcutEvent(event);
@@ -102,8 +120,8 @@ public class Dream extends Service implements Window.Callback {
// TODO: create more flexible version of mInteractive that allows clicks
// but finish()es on any other kind of activity
if (!mInteractive) {
- if (DEBUG) Slog.v(TAG, "finishing on touchEvent");
- finish();
+ if (DEBUG) Slog.v(TAG, "Finishing on touchEvent");
+ safelyFinish();
return true;
}
return mWindow.superDispatchTouchEvent(event);
@@ -112,8 +130,8 @@ public class Dream extends Service implements Window.Callback {
@Override
public boolean dispatchTrackballEvent(MotionEvent event) {
if (!mInteractive) {
- if (DEBUG) Slog.v(TAG, "finishing on trackballEvent");
- finish();
+ if (DEBUG) Slog.v(TAG, "Finishing on trackballEvent");
+ safelyFinish();
return true;
}
return mWindow.superDispatchTrackballEvent(event);
@@ -122,8 +140,8 @@ public class Dream extends Service implements Window.Callback {
@Override
public boolean dispatchGenericMotionEvent(MotionEvent event) {
if (!mInteractive) {
- if (DEBUG) Slog.v(TAG, "finishing on genericMotionEvent");
- finish();
+ if (DEBUG) Slog.v(TAG, "Finishing on genericMotionEvent");
+ safelyFinish();
return true;
}
return mWindow.superDispatchGenericMotionEvent(event);
@@ -212,30 +230,9 @@ public class Dream extends Service implements Window.Callback {
public Window getWindow() {
return mWindow;
}
-
- /**
- * Called when this Dream is constructed. Place your initialization here.
- *
- * Subclasses must call through to the superclass implementation.
- */
- @Override
- public void onCreate() {
- super.onCreate();
-
- if (DEBUG) Slog.v(TAG, "Dream created on thread " + Thread.currentThread().getId());
-
- mSandman = IDreamManager.Stub.asInterface(ServiceManager.getService("dreams"));
- }
-
- /**
- * Called when this Dream is started.
- */
- public void onStart() {
- // hook for subclasses
- }
/**
- * Inflate a layout resource and set it to be the content view for this Dream.
+ * Inflates a layout resource and set it to be the content view for this Dream.
* Behaves similarly to {@link android.app.Activity#setContentView(int)}.
*
* @param layoutResID Resource ID to be inflated.
@@ -248,7 +245,7 @@ public class Dream extends Service implements Window.Callback {
}
/**
- * Set a view to be the content view for this Dream.
+ * Sets a view to be the content view for this Dream.
* Behaves similarly to {@link android.app.Activity#setContentView(android.view.View)},
* including using {@link ViewGroup.LayoutParams#MATCH_PARENT} as the layout height and width of the view.
*
@@ -262,7 +259,7 @@ public class Dream extends Service implements Window.Callback {
}
/**
- * Set a view to be the content view for this Dream.
+ * Sets a view to be the content view for this Dream.
* Behaves similarly to
* {@link android.app.Activity#setContentView(android.view.View, android.view.ViewGroup.LayoutParams)}.
*
@@ -277,7 +274,7 @@ public class Dream extends Service implements Window.Callback {
}
/**
- * Add a view to the Dream's window, leaving other content views in place.
+ * Adds a view to the Dream's window, leaving other content views in place.
*
* @param view The desired content to display.
* @param params Layout parameters for the view.
@@ -285,21 +282,27 @@ public class Dream extends Service implements Window.Callback {
public void addContentView(View view, ViewGroup.LayoutParams params) {
getWindow().addContentView(view, params);
}
-
+
/**
- * @param mInteractive the mInteractive to set
+ * Marks this dream as interactive to receive input events.
+ *
+ * <p>Non-interactive dreams (default) will dismiss on the first input event.</p>
+ *
+ * <p>Interactive dreams should call {@link #finish()} to dismiss themselves.</p>
+ *
+ * @param interactive True if this dream will handle input events.
*/
- public void setInteractive(boolean mInteractive) {
- this.mInteractive = mInteractive;
+ public void setInteractive(boolean interactive) {
+ mInteractive = interactive;
}
/**
- * @return the mInteractive
+ * Returns whether or not this dream is interactive.
*/
public boolean isInteractive() {
return mInteractive;
}
-
+
/** Convenience method for setting View.SYSTEM_UI_FLAG_LOW_PROFILE on the content view. */
protected void lightsOut() {
// turn the lights down low
@@ -319,14 +322,29 @@ public class Dream extends Service implements Window.Callback {
public View findViewById(int id) {
return getWindow().findViewById(id);
}
-
+
/**
- * Called when this Dream is being removed from the screen and stopped.
+ * Called when this Dream is constructed. Place your initialization here.
+ *
+ * Subclasses must call through to the superclass implementation.
*/
@Override
- public void onDestroy() {
- super.onDestroy();
- mWindowManager.removeView(mWindow.getDecorView());
+ public void onCreate() {
+ if (DEBUG) Slog.v(TAG, "onCreate() on thread " + Thread.currentThread().getId());
+ super.onCreate();
+ loadSandman();
+ }
+
+ /**
+ * Called when this Dream is started.
+ */
+ public void onStart() {
+ // hook for subclasses
+ Slog.v(TAG, "called Dream.onStart()");
+ }
+
+ private void loadSandman() {
+ mSandman = IDreamManager.Stub.asInterface(ServiceManager.getService("dreams"));
}
/**
@@ -335,16 +353,21 @@ public class Dream extends Service implements Window.Callback {
* @param windowToken Binder to attach to the window to allow access to the correct window type.
* @hide
*/
- final /*package*/ void attach(IBinder windowToken) {
- if (DEBUG) Slog.v(TAG, "Dream attached on thread " + Thread.currentThread().getId());
-
+ private final void attach(IBinder windowToken) {
+ if (DEBUG) Slog.v(TAG, "Attached on thread " + Thread.currentThread().getId());
+
+ if (mSandman == null) {
+ Slog.w(TAG, "No dream manager found, super.onCreate may not have been called");
+ loadSandman();
+ }
+ mWindowToken = windowToken;
mWindow = PolicyManager.makeNewWindow(this);
mWindow.setCallback(this);
mWindow.requestFeature(Window.FEATURE_NO_TITLE);
mWindow.setBackgroundDrawable(new ColorDrawable(0xFF000000));
- if (DEBUG) Slog.v(TAG, "attaching window token: " + windowToken
- + " to window of type " + WindowManager.LayoutParams.TYPE_DREAM);
+ if (DEBUG) Slog.v(TAG, String.format("Attaching window token: %s to window of type %s",
+ windowToken, WindowManager.LayoutParams.TYPE_DREAM));
WindowManager.LayoutParams lp = mWindow.getAttributes();
lp.type = WindowManager.LayoutParams.TYPE_DREAM;
@@ -355,58 +378,105 @@ public class Dream extends Service implements Window.Callback {
| WindowManager.LayoutParams.FLAG_ALLOW_LOCK_WHILE_SCREEN_ON
);
mWindow.setAttributes(lp);
-
- //WindowManagerImpl.getDefault().addView(mWindow.getDecorView(), lp);
-
- if (DEBUG) Slog.v(TAG, "created and attached window: " + mWindow);
+
+ if (DEBUG) Slog.v(TAG, "Created and attached window: " + mWindow);
mWindow.setWindowManager(null, windowToken, "dream", true);
mWindowManager = mWindow.getWindowManager();
-
- // now make it visible
+
+ // now make it visible (on the ui thread)
mHandler.post(new Runnable(){
@Override
public void run() {
- if (DEBUG) Slog.v(TAG, "Dream window added on thread " + Thread.currentThread().getId());
+ if (DEBUG) Slog.v(TAG, "Window added on thread " + Thread.currentThread().getId());
- getWindowManager().addView(mWindow.getDecorView(), mWindow.getAttributes());
+ try {
+ getWindowManager().addView(mWindow.getDecorView(), mWindow.getAttributes());
+ } catch (Throwable t) {
+ Slog.w("Crashed adding window view", t);
+ safelyFinish();
+ return;
+ }
// start it up
- onStart();
+ try {
+ onStart();
+ } catch (Throwable t) {
+ Slog.w("Crashed in onStart()", t);
+ safelyFinish();
+ }
}});
}
-
+
+ private void safelyFinish() {
+ if (DEBUG) Slog.v(TAG, "safelyFinish()");
+ try {
+ finish();
+ } catch (Throwable t) {
+ Slog.w(TAG, "Crashed in safelyFinish()", t);
+ finishInternal();
+ return;
+ }
+
+ if (!mFinished) {
+ Slog.w(TAG, "Bad dream, did not call super.finish()");
+ finishInternal();
+ }
+ }
+
/**
- * Stop the dream and wake up.
- *
- * After this method is called, the service will be stopped.
+ * Stops the dream, detaches from the window, and wakes up.
+ *
+ * Subclasses must call through to the superclass implementation.
+ *
+ * <p>After this method is called, the service will be stopped.</p>
*/
public void finish() {
+ if (DEBUG) Slog.v(TAG, "finish()");
+ finishInternal();
+ }
+
+ private void finishInternal() {
+ if (DEBUG) Slog.v(TAG, "finishInternal() mFinished = " + mFinished);
if (mFinished) return;
try {
- mSandman.awaken(); // assuming we were started by the DreamManager
- stopSelf(); // if launched via any other means
mFinished = true;
- } catch (RemoteException ex) {
- // sigh
+
+ if (mSandman != null) {
+ mSandman.awakenSelf(mWindowToken);
+ } else {
+ Slog.w(TAG, "No dream manager found");
+ }
+ stopSelf(); // if launched via any other means
+
+ } catch (Throwable t) {
+ Slog.w(TAG, "Crashed in finishInternal()", t);
}
}
- class IDreamServiceWrapper extends IDreamService.Stub {
- public IDreamServiceWrapper() {
- }
+ @Override
+ public void onDestroy() {
+ if (DEBUG) Slog.v(TAG, "onDestroy()");
+ super.onDestroy();
- public void attach(IBinder windowToken) {
- Dream.this.attach(windowToken);
+ if (DEBUG) Slog.v(TAG, "Removing window");
+ try {
+ mWindowManager.removeView(mWindow.getDecorView());
+ } catch (Throwable t) {
+ Slog.w(TAG, "Crashed removing window view", t);
}
}
- /**
- * Implement to return the implementation of the internal accessibility
- * service interface. Subclasses should not override.
- */
@Override
public final IBinder onBind(Intent intent) {
- return new IDreamServiceWrapper();
+ if (DEBUG) Slog.v(TAG, "onBind() intent = " + intent);
+ return new DreamServiceWrapper();
}
+
+ private class DreamServiceWrapper extends IDreamService.Stub {
+ public void attach(IBinder windowToken) {
+ Dream.this.attach(windowToken);
+ }
+ }
+
}
diff --git a/core/java/android/service/dreams/DreamManagerService.java b/core/java/android/service/dreams/DreamManagerService.java
deleted file mode 100644
index 4aa1cbb..0000000
--- a/core/java/android/service/dreams/DreamManagerService.java
+++ /dev/null
@@ -1,247 +0,0 @@
-package android.service.dreams;
-
-import static android.provider.Settings.Secure.SCREENSAVER_COMPONENTS;
-import static android.provider.Settings.Secure.SCREENSAVER_DEFAULT_COMPONENT;
-import java.io.FileDescriptor;
-import java.io.PrintWriter;
-
-import android.app.ActivityManagerNative;
-import android.content.BroadcastReceiver;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.ServiceConnection;
-import android.content.pm.PackageManager;
-import android.os.Binder;
-import android.os.IBinder;
-import android.os.RemoteException;
-import android.os.UserHandle;
-import android.provider.Settings;
-import android.util.Slog;
-import android.view.IWindowManager;
-import android.view.WindowManager;
-import android.view.WindowManagerGlobal;
-
-/**
- *
- * @hide
- *
- */
-
-public class DreamManagerService
- extends IDreamManager.Stub
- implements ServiceConnection
-{
- private static final boolean DEBUG = true;
- private static final String TAG = "DreamManagerService";
-
- final Object mLock = new Object[0];
-
- private Context mContext;
- private IWindowManager mIWindowManager;
-
- private ComponentName mCurrentDreamComponent;
- private IDreamService mCurrentDream;
- private Binder mCurrentDreamToken;
- private int mCurrentUserId;
-
- public DreamManagerService(Context context) {
- if (DEBUG) Slog.v(TAG, "DreamManagerService startup");
- mContext = context;
- mIWindowManager = WindowManagerGlobal.getWindowManagerService();
- }
-
- private void checkPermission(String permission) {
- if (PackageManager.PERMISSION_GRANTED != mContext.checkCallingOrSelfPermission(permission)) {
- throw new SecurityException("Access denied to process: " + Binder.getCallingPid()
- + ", must have permission " + permission);
- }
- }
-
- // IDreamManager method
- @Override
- public void dream() {
- ComponentName[] dreams = getDreamComponentsForUser(mCurrentUserId);
- ComponentName name = dreams != null && dreams.length > 0 ? dreams[0] : null;
- if (name != null) {
- synchronized (mLock) {
- final long ident = Binder.clearCallingIdentity();
- try {
- bindDreamComponentL(name, false);
- } finally {
- Binder.restoreCallingIdentity(ident);
- }
- }
- }
- }
-
- // IDreamManager method
- @Override
- public void setDreamComponents(ComponentName[] componentNames) {
- Settings.Secure.putStringForUser(mContext.getContentResolver(),
- SCREENSAVER_COMPONENTS,
- componentsToString(componentNames),
- UserHandle.getCallingUserId());
- }
-
- private static String componentsToString(ComponentName[] componentNames) {
- StringBuilder names = new StringBuilder();
- if (componentNames != null) {
- for (ComponentName componentName : componentNames) {
- if (names.length() > 0)
- names.append(',');
- names.append(componentName.flattenToString());
- }
- }
- return names.toString();
- }
-
- private static ComponentName[] componentsFromString(String names) {
- String[] namesArray = names.split(",");
- ComponentName[] componentNames = new ComponentName[namesArray.length];
- for (int i = 0; i < namesArray.length; i++)
- componentNames[i] = ComponentName.unflattenFromString(namesArray[i]);
- return componentNames;
- }
-
- // IDreamManager method
- @Override
- public ComponentName[] getDreamComponents() {
- return getDreamComponentsForUser(UserHandle.getCallingUserId());
- }
-
- private ComponentName[] getDreamComponentsForUser(int userId) {
- String names = Settings.Secure.getStringForUser(mContext.getContentResolver(),
- SCREENSAVER_COMPONENTS,
- userId);
- return names == null ? null : componentsFromString(names);
- }
-
- // IDreamManager method
- @Override
- public ComponentName getDefaultDreamComponent() {
- String name = Settings.Secure.getStringForUser(mContext.getContentResolver(),
- SCREENSAVER_DEFAULT_COMPONENT,
- UserHandle.getCallingUserId());
- return name == null ? null : ComponentName.unflattenFromString(name);
- }
-
- // IDreamManager method
- @Override
- public void testDream(ComponentName name) {
- if (DEBUG) Slog.v(TAG, "startDream name=" + name
- + " pid=" + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid());
-// checkPermission(android.Manifest.permission.SET_WALLPAPER_COMPONENT);
- synchronized (mLock) {
- final long ident = Binder.clearCallingIdentity();
- try {
- bindDreamComponentL(name, true);
- } finally {
- Binder.restoreCallingIdentity(ident);
- }
- }
- }
-
- // IDreamManager method
- @Override
- public void awaken() {
- if (DEBUG) Slog.v(TAG, "awaken()");
- synchronized (mLock) {
- if (mCurrentDream != null) {
- if (DEBUG) Slog.v(TAG, "disconnecting: " + mCurrentDreamComponent + " service: " + mCurrentDream);
- mContext.unbindService(this);
- mCurrentDream = null;
- mCurrentDreamToken = null;
- }
- }
- }
-
- // IDreamManager method
- @Override
- public boolean isDreaming() {
- synchronized (mLock) {
- return mCurrentDreamToken != null;
- }
- }
-
- public void bindDreamComponentL(ComponentName componentName, boolean test) {
- if (DEBUG) Slog.v(TAG, "bindDreamComponent: componentName=" + componentName
- + " pid=" + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid());
-
- Intent intent = new Intent(Intent.ACTION_MAIN)
- .setComponent(componentName)
- .addFlags(
- Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
- )
- .putExtra("android.dreams.TEST", test);
-
- mCurrentDreamComponent = componentName;
- mCurrentDreamToken = new Binder();
- try {
- if (DEBUG) Slog.v(TAG, "Adding window token: " + mCurrentDreamToken
- + " for window type: " + WindowManager.LayoutParams.TYPE_DREAM);
- mIWindowManager.addWindowToken(mCurrentDreamToken,
- WindowManager.LayoutParams.TYPE_DREAM);
- } catch (RemoteException e) {
- Slog.w(TAG, "Unable to add window token. Proceed at your own risk.");
- }
-
- if (!mContext.bindService(intent, this, Context.BIND_AUTO_CREATE)) {
- Slog.w(TAG, "unable to bind service: " + componentName);
- }
- }
-
- @Override
- public void onServiceConnected(ComponentName name, IBinder service) {
- if (DEBUG) Slog.v(TAG, "connected to dream: " + name + " binder=" + service + " thread=" + Thread.currentThread().getId());
-
- mCurrentDream = IDreamService.Stub.asInterface(service);
- try {
- if (DEBUG) Slog.v(TAG, "attaching with token:" + mCurrentDreamToken);
- mCurrentDream.attach(mCurrentDreamToken);
- } catch (RemoteException ex) {
- Slog.w(TAG, "Unable to send window token to dream:" + ex);
- }
- }
-
- @Override
- public void onServiceDisconnected(ComponentName name) {
- if (DEBUG) Slog.v(TAG, "disconnected: " + name + " service: " + mCurrentDream);
- // Only happens in exceptional circumstances
- }
-
- @Override
- protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
- mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, TAG);
-
- pw.println("Dreamland:");
- pw.print(" component="); pw.println(mCurrentDreamComponent);
- pw.print(" token="); pw.println(mCurrentDreamToken);
- pw.print(" dream="); pw.println(mCurrentDream);
- }
-
- public void systemReady() {
-
- // dream settings are kept per user, so keep track of current user
- try {
- mCurrentUserId = ActivityManagerNative.getDefault().getCurrentUser().id;
- } catch (RemoteException e) {
- Slog.w(TAG, "Couldn't get current user ID; guessing it's 0", e);
- }
- IntentFilter filter = new IntentFilter();
- filter.addAction(Intent.ACTION_USER_SWITCHED);
- mContext.registerReceiver(new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- String action = intent.getAction();
- if (Intent.ACTION_USER_SWITCHED.equals(action)) {
- mCurrentUserId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0);
- if (DEBUG) Slog.v(TAG, "userId " + mCurrentUserId + " is in the house");
- }
- }}, filter);
-
- if (DEBUG) Slog.v(TAG, "ready to dream!");
- }
-
-}
diff --git a/core/java/android/service/dreams/IDreamManager.aidl b/core/java/android/service/dreams/IDreamManager.aidl
index b6fcdf0..bd1c524 100644
--- a/core/java/android/service/dreams/IDreamManager.aidl
+++ b/core/java/android/service/dreams/IDreamManager.aidl
@@ -19,6 +19,7 @@ package android.service.dreams;
import android.os.Bundle;
import android.os.ParcelFileDescriptor;
import android.content.ComponentName;
+import android.os.IBinder;
/** @hide */
interface IDreamManager {
@@ -29,4 +30,5 @@ interface IDreamManager {
ComponentName getDefaultDreamComponent();
void testDream(in ComponentName componentName);
boolean isDreaming();
+ void awakenSelf(in IBinder token);
} \ No newline at end of file
diff --git a/core/java/android/text/format/DateUtils.java b/core/java/android/text/format/DateUtils.java
index 0babcc5..1060bd8 100644
--- a/core/java/android/text/format/DateUtils.java
+++ b/core/java/android/text/format/DateUtils.java
@@ -45,7 +45,6 @@ public class DateUtils
private static final String FAST_FORMAT_HMMSS = "%1$d:%2$02d:%3$02d";
private static final String FAST_FORMAT_MMSS = "%1$02d:%2$02d";
- private static final char TIME_PADDING = '0';
private static final char TIME_SEPARATOR = ':';
@@ -648,33 +647,36 @@ public class DateUtils
}
}
+ private static void append(StringBuilder sb, long value, boolean pad, char zeroDigit) {
+ if (value < 10) {
+ if (pad) {
+ sb.append(zeroDigit);
+ }
+ } else {
+ sb.append((char) (zeroDigit + (value / 10)));
+ }
+ sb.append((char) (zeroDigit + (value % 10)));
+ }
+
/**
- * Fast formatting of h:mm:ss
+ * Fast formatting of h:mm:ss.
*/
private static String formatElapsedTime(StringBuilder recycle, String format, long hours,
long minutes, long seconds) {
if (FAST_FORMAT_HMMSS.equals(format)) {
+ char zeroDigit = LocaleData.get(Locale.getDefault()).zeroDigit;
+
StringBuilder sb = recycle;
if (sb == null) {
sb = new StringBuilder(8);
} else {
sb.setLength(0);
}
- sb.append(hours);
+ append(sb, hours, false, zeroDigit);
sb.append(TIME_SEPARATOR);
- if (minutes < 10) {
- sb.append(TIME_PADDING);
- } else {
- sb.append(toDigitChar(minutes / 10));
- }
- sb.append(toDigitChar(minutes % 10));
+ append(sb, minutes, true, zeroDigit);
sb.append(TIME_SEPARATOR);
- if (seconds < 10) {
- sb.append(TIME_PADDING);
- } else {
- sb.append(toDigitChar(seconds / 10));
- }
- sb.append(toDigitChar(seconds % 10));
+ append(sb, seconds, true, zeroDigit);
return sb.toString();
} else {
return String.format(format, hours, minutes, seconds);
@@ -682,40 +684,28 @@ public class DateUtils
}
/**
- * Fast formatting of m:ss
+ * Fast formatting of mm:ss.
*/
private static String formatElapsedTime(StringBuilder recycle, String format, long minutes,
long seconds) {
if (FAST_FORMAT_MMSS.equals(format)) {
+ char zeroDigit = LocaleData.get(Locale.getDefault()).zeroDigit;
+
StringBuilder sb = recycle;
if (sb == null) {
sb = new StringBuilder(8);
} else {
sb.setLength(0);
}
- if (minutes < 10) {
- sb.append(TIME_PADDING);
- } else {
- sb.append(toDigitChar(minutes / 10));
- }
- sb.append(toDigitChar(minutes % 10));
+ append(sb, minutes, false, zeroDigit);
sb.append(TIME_SEPARATOR);
- if (seconds < 10) {
- sb.append(TIME_PADDING);
- } else {
- sb.append(toDigitChar(seconds / 10));
- }
- sb.append(toDigitChar(seconds % 10));
+ append(sb, seconds, true, zeroDigit);
return sb.toString();
} else {
return String.format(format, minutes, seconds);
}
}
- private static char toDigitChar(long digit) {
- return (char) (digit + '0');
- }
-
/**
* Format a date / time such that if the then is on the same day as now, it shows
* just the time and if it's a different day, it shows just the date.
@@ -1387,6 +1377,14 @@ public class DateUtils
String endMonthDayString = isInstant ? null : endDate.format(MONTH_DAY_FORMAT);
String endYearString = isInstant ? null : endDate.format(YEAR_FORMAT);
+ String startStandaloneMonthString = startMonthString;
+ String endStandaloneMonthString = endMonthString;
+ // We need standalone months for these strings in Persian (fa): http://b/6811327
+ if (!numericDate && !abbrevMonth && Locale.getDefault().getLanguage().equals("fa")) {
+ startStandaloneMonthString = startDate.format("%-B");
+ endStandaloneMonthString = endDate.format("%-B");
+ }
+
if (startMonthNum != endMonthNum) {
// Same year, different month.
// Example: "October 28 - November 3"
@@ -1407,7 +1405,8 @@ public class DateUtils
startWeekDayString, startMonthString, startMonthDayString,
startYearString, startTimeString,
endWeekDayString, endMonthString, endMonthDayString,
- endYearString, endTimeString);
+ endYearString, endTimeString,
+ startStandaloneMonthString, endStandaloneMonthString);
}
if (startDay != endDay) {
@@ -1426,7 +1425,8 @@ public class DateUtils
startWeekDayString, startMonthString, startMonthDayString,
startYearString, startTimeString,
endWeekDayString, endMonthString, endMonthDayString,
- endYearString, endTimeString);
+ endYearString, endTimeString,
+ startStandaloneMonthString, endStandaloneMonthString);
}
// Same start and end day
diff --git a/core/java/android/text/format/Time.java b/core/java/android/text/format/Time.java
index 45d5a70..5ef86b1 100644
--- a/core/java/android/text/format/Time.java
+++ b/core/java/android/text/format/Time.java
@@ -151,6 +151,9 @@ public class Time {
private static String sDateTimeFormat;
private static String sAm;
private static String sPm;
+ private static char sZeroDigit;
+
+ // Referenced by native code.
private static String sDateCommand = "%a %b %e %H:%M:%S %Z %Y";
/**
@@ -323,6 +326,7 @@ public class Time {
sAm = localeData.amPm[0];
sPm = localeData.amPm[1];
+ sZeroDigit = localeData.zeroDigit;
sShortMonths = localeData.shortMonthNames;
sLongMonths = localeData.longMonthNames;
@@ -338,12 +342,32 @@ public class Time {
sLocale = locale;
}
- return format1(format);
+ String result = format1(format);
+ if (sZeroDigit != '0') {
+ result = localizeDigits(result);
+ }
+ return result;
}
}
native private String format1(String format);
+ // TODO: unify this with java.util.Formatter's copy.
+ private String localizeDigits(String s) {
+ int length = s.length();
+ int offsetToLocalizedDigits = sZeroDigit - '0';
+ StringBuilder result = new StringBuilder(length);
+ for (int i = 0; i < length; ++i) {
+ char ch = s.charAt(i);
+ if (ch >= '0' && ch <= '9') {
+ ch += offsetToLocalizedDigits;
+ }
+ result.append(ch);
+ }
+ return result.toString();
+ }
+
+
/**
* Return the current time in YYYYMMDDTHHMMSS<tz> format
*/
@@ -673,7 +697,7 @@ public class Time {
int minutes = (offset % 3600) / 60;
int hours = offset / 3600;
- return String.format("%s%s%02d:%02d", base, sign, hours, minutes);
+ return String.format(Locale.US, "%s%s%02d:%02d", base, sign, hours, minutes);
}
}
diff --git a/core/java/android/view/HardwareRenderer.java b/core/java/android/view/HardwareRenderer.java
index 446a51e..ef5dc56 100644
--- a/core/java/android/view/HardwareRenderer.java
+++ b/core/java/android/view/HardwareRenderer.java
@@ -1136,9 +1136,8 @@ public abstract class HardwareRenderer {
}
}
- int status = onPreDraw(dirty);
- int saveCount = canvas.save();
- callbacks.onHardwarePreDraw(canvas);
+ int saveCount = 0;
+ int status = DisplayList.STATUS_DONE;
try {
view.mRecreateDisplayList = (view.mPrivateFlags & View.PFLAG_INVALIDATED)
@@ -1164,6 +1163,10 @@ public abstract class HardwareRenderer {
Trace.traceEnd(Trace.TRACE_TAG_VIEW);
}
+ status = onPreDraw(dirty);
+ saveCount = canvas.save();
+ callbacks.onHardwarePreDraw(canvas);
+
if (mProfileEnabled) {
long now = System.nanoTime();
float total = (now - getDisplayListStartTime) * 0.000001f;
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index c374ca6..87221e0 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -83,12 +83,18 @@ import static java.lang.Math.max;
import com.android.internal.R;
import com.android.internal.util.Predicate;
import com.android.internal.view.menu.MenuBuilder;
+import com.google.android.collect.Lists;
+import com.google.android.collect.Maps;
import java.lang.ref.WeakReference;
+import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
import java.util.Locale;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.atomic.AtomicInteger;
@@ -1503,7 +1509,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
private SparseArray<Object> mKeyedTags;
/**
- * The next available accessiiblity id.
+ * The next available accessibility id.
*/
private static int sNextAccessibilityViewId;
@@ -1727,7 +1733,51 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
*/
static final int PFLAG_INVALIDATED = 0x80000000;
- /* Masks for mPrivateFlags2 */
+ /**
+ * Masks for mPrivateFlags2, as generated by dumpFlags():
+ *
+ * -------|-------|-------|-------|
+ * PFLAG2_TEXT_ALIGNMENT_FLAGS[0]
+ * PFLAG2_TEXT_DIRECTION_FLAGS[0]
+ * 1 PFLAG2_DRAG_CAN_ACCEPT
+ * 1 PFLAG2_DRAG_HOVERED
+ * 1 PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT
+ * 11 PFLAG2_TEXT_DIRECTION_MASK_SHIFT
+ * 1 1 PFLAG2_TEXT_DIRECTION_RESOLVED_MASK_SHIFT
+ * 11 PFLAG2_LAYOUT_DIRECTION_MASK
+ * 11 1 PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT
+ * 1 PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL
+ * 1 1 PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK_SHIFT
+ * 1 1 PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_SHIFT
+ * 1 PFLAG2_LAYOUT_DIRECTION_RESOLVED
+ * 11 PFLAG2_LAYOUT_DIRECTION_RESOLVED_MASK
+ * 1 PFLAG2_TEXT_DIRECTION_FLAGS[1]
+ * 1 PFLAG2_TEXT_DIRECTION_FLAGS[2]
+ * 11 PFLAG2_TEXT_DIRECTION_FLAGS[3]
+ * 1 PFLAG2_TEXT_DIRECTION_FLAGS[4]
+ * 1 1 PFLAG2_TEXT_DIRECTION_FLAGS[5]
+ * 111 PFLAG2_TEXT_DIRECTION_MASK
+ * 1 PFLAG2_TEXT_DIRECTION_RESOLVED
+ * 1 PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT
+ * 111 PFLAG2_TEXT_DIRECTION_RESOLVED_MASK
+ * 1 PFLAG2_TEXT_ALIGNMENT_FLAGS[1]
+ * 1 PFLAG2_TEXT_ALIGNMENT_FLAGS[2]
+ * 11 PFLAG2_TEXT_ALIGNMENT_FLAGS[3]
+ * 1 PFLAG2_TEXT_ALIGNMENT_FLAGS[4]
+ * 1 1 PFLAG2_TEXT_ALIGNMENT_FLAGS[5]
+ * 11 PFLAG2_TEXT_ALIGNMENT_FLAGS[6]
+ * 111 PFLAG2_TEXT_ALIGNMENT_MASK
+ * 1 PFLAG2_TEXT_ALIGNMENT_RESOLVED
+ * 1 PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT
+ * 111 PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK
+ * 11 PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_MASK
+ * 1 PFLAG2_HAS_TRANSIENT_STATE
+ * 1 PFLAG2_ACCESSIBILITY_FOCUSED
+ * 1 PFLAG2_ACCESSIBILITY_STATE_CHANGED
+ * 1 PFLAG2_VIEW_QUICK_REJECTED
+ * 1 PFLAG2_PADDING_RESOLVED
+ * -------|-------|-------|-------|
+ */
/**
* Indicates that this view has reported that it can accept the current drag's content.
@@ -1825,8 +1875,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
*
* @hide
*/
- static final int PFLAG2_HAS_TRANSIENT_STATE = 0x00000100;
-
+ static final int PFLAG2_HAS_TRANSIENT_STATE = 0x1 << 22;
/**
* Text direction is inherited thru {@link ViewGroup}
@@ -2053,7 +2102,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
public static final int IMPORTANT_FOR_ACCESSIBILITY_NO = 0x00000002;
/**
- * The default whether the view is important for accessiblity.
+ * The default whether the view is important for accessibility.
*/
static final int IMPORTANT_FOR_ACCESSIBILITY_DEFAULT = IMPORTANT_FOR_ACCESSIBILITY_AUTO;
@@ -2814,18 +2863,18 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
int mUserPaddingEnd;
/**
- * Whether a left padding has been defined during layout inflation.
+ * Cache initial left padding.
*
* @hide
*/
- boolean mUserPaddingLeftDefined = false;
+ int mUserPaddingLeftInitial = UNDEFINED_PADDING;
/**
- * Whether a right padding has been defined during layout inflation.
+ * Cache initial right padding.
*
* @hide
*/
- boolean mUserPaddingRightDefined = false;
+ int mUserPaddingRightInitial = UNDEFINED_PADDING;
/**
* Default undefined padding
@@ -3125,7 +3174,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
private boolean mSendingHoverAccessibilityEvents;
/**
- * Delegate for injecting accessiblity functionality.
+ * Delegate for injecting accessibility functionality.
*/
AccessibilityDelegate mAccessibilityDelegate;
@@ -3247,19 +3296,19 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
break;
case com.android.internal.R.styleable.View_padding:
padding = a.getDimensionPixelSize(attr, -1);
- mUserPaddingLeftDefined = true;
- mUserPaddingRightDefined = true;
+ mUserPaddingLeftInitial = padding;
+ mUserPaddingRightInitial = padding;
break;
case com.android.internal.R.styleable.View_paddingLeft:
leftPadding = a.getDimensionPixelSize(attr, -1);
- mUserPaddingLeftDefined = true;
+ mUserPaddingLeftInitial = leftPadding;
break;
case com.android.internal.R.styleable.View_paddingTop:
topPadding = a.getDimensionPixelSize(attr, -1);
break;
case com.android.internal.R.styleable.View_paddingRight:
rightPadding = a.getDimensionPixelSize(attr, -1);
- mUserPaddingRightDefined = true;
+ mUserPaddingRightInitial = rightPadding;
break;
case com.android.internal.R.styleable.View_paddingBottom:
bottomPadding = a.getDimensionPixelSize(attr, -1);
@@ -3561,15 +3610,19 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
topPadding = padding;
rightPadding = padding;
bottomPadding = padding;
+ mUserPaddingLeftInitial = padding;
+ mUserPaddingRightInitial = padding;
}
// If the user specified the padding (either with android:padding or
// android:paddingLeft/Top/Right/Bottom), use this padding, otherwise
// use the default padding or the padding from the background drawable
// (stored at this point in mPadding*)
- internalSetPadding(leftPadding >= 0 ? leftPadding : mPaddingLeft,
+ mUserPaddingLeftInitial = leftPadding >= 0 ? leftPadding : mPaddingLeft;
+ mUserPaddingRightInitial = rightPadding >= 0 ? rightPadding : mPaddingRight;
+ internalSetPadding(mUserPaddingLeftInitial,
topPadding >= 0 ? topPadding : mPaddingTop,
- rightPadding >= 0 ? rightPadding : mPaddingRight,
+ mUserPaddingRightInitial,
bottomPadding >= 0 ? bottomPadding : mPaddingBottom);
if (viewFlagMasks != 0) {
@@ -4475,7 +4528,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
}
/**
- * Sends an accessibility event of the given type. If accessiiblity is
+ * Sends an accessibility event of the given type. If accessibility is
* not enabled this method has no effect. The default implementation calls
* {@link #onInitializeAccessibilityEvent(AccessibilityEvent)} first
* to populate information about the event source (this View), then calls
@@ -4894,7 +4947,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
info.setLongClickable(isLongClickable());
// TODO: These make sense only if we are in an AdapterView but all
- // views can be selected. Maybe from accessiiblity perspective
+ // views can be selected. Maybe from accessibility perspective
// we should report as selectable view in an AdapterView.
info.addAction(AccessibilityNodeInfo.ACTION_SELECT);
info.addAction(AccessibilityNodeInfo.ACTION_CLEAR_SELECTION);
@@ -5004,7 +5057,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
}
/**
- * Sets a delegate for implementing accessibility support via compositon as
+ * Sets a delegate for implementing accessibility support via composition as
* opposed to inheritance. The delegate's primary use is for implementing
* backwards compatible widgets. For more details see {@link AccessibilityDelegate}.
*
@@ -6680,7 +6733,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
/**
* Returns whether the View is considered actionable from
* accessibility perspective. Such view are important for
- * accessiiblity.
+ * accessibility.
*
* @return True if the view is actionable for accessibility.
*
@@ -6692,7 +6745,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
/**
* Returns whether the View has registered callbacks wich makes it
- * important for accessiiblity.
+ * important for accessibility.
*
* @return True if the view is actionable for accessibility.
*/
@@ -6731,7 +6784,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
/**
* Reset the state indicating the this view has requested clients
- * interested in its accessiblity state to be notified.
+ * interested in its accessibility state to be notified.
*
* @hide
*/
@@ -11540,10 +11593,12 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
// left / right padding are used if defined. If they are not defined and start / end
// padding are defined (e.g. in Frameworks resources), then we use start / end and
// resolve them as left / right (layout direction is not taken into account).
- if (!mUserPaddingLeftDefined && mUserPaddingStart != UNDEFINED_PADDING) {
+ if (mUserPaddingLeftInitial == UNDEFINED_PADDING &&
+ mUserPaddingStart != UNDEFINED_PADDING) {
mUserPaddingLeft = mUserPaddingStart;
}
- if (!mUserPaddingRightDefined && mUserPaddingEnd != UNDEFINED_PADDING) {
+ if (mUserPaddingRightInitial == UNDEFINED_PADDING
+ && mUserPaddingEnd != UNDEFINED_PADDING) {
mUserPaddingRight = mUserPaddingEnd;
}
@@ -11557,6 +11612,12 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
// left / right or right / left depending on the resolved layout direction.
// If start / end padding are not defined, use the left / right ones.
int resolvedLayoutDirection = getResolvedLayoutDirection();
+ // Set user padding to initial values ...
+ mUserPaddingLeft = (mUserPaddingLeftInitial == UNDEFINED_PADDING) ?
+ 0 : mUserPaddingLeftInitial;
+ mUserPaddingRight = (mUserPaddingRightInitial == UNDEFINED_PADDING) ?
+ 0 : mUserPaddingRightInitial;
+ // ... then resolve it.
switch (resolvedLayoutDirection) {
case LAYOUT_DIRECTION_RTL:
if (mUserPaddingStart != UNDEFINED_PADDING) {
@@ -14322,10 +14383,14 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
mPrivateFlags2 &= ~PFLAG2_PADDING_RESOLVED;
switch (background.getLayoutDirection()) {
case LAYOUT_DIRECTION_RTL:
+ mUserPaddingLeftInitial = padding.right;
+ mUserPaddingRightInitial = padding.left;
internalSetPadding(padding.right, padding.top, padding.left, padding.bottom);
break;
case LAYOUT_DIRECTION_LTR:
default:
+ mUserPaddingLeftInitial = padding.left;
+ mUserPaddingRightInitial = padding.right;
internalSetPadding(padding.left, padding.top, padding.right, padding.bottom);
}
}
@@ -14422,6 +14487,9 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
mUserPaddingStart = UNDEFINED_PADDING;
mUserPaddingEnd = UNDEFINED_PADDING;
+ mUserPaddingLeftInitial = left;
+ mUserPaddingRightInitial = right;
+
internalSetPadding(left, top, right, bottom);
}
@@ -14511,10 +14579,14 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
switch(getResolvedLayoutDirection()) {
case LAYOUT_DIRECTION_RTL:
+ mUserPaddingLeftInitial = end;
+ mUserPaddingRightInitial = start;
internalSetPadding(end, top, start, bottom);
break;
case LAYOUT_DIRECTION_LTR:
default:
+ mUserPaddingLeftInitial = start;
+ mUserPaddingRightInitial = end;
internalSetPadding(start, top, end, bottom);
}
}
@@ -18091,4 +18163,46 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
return (view.mLabelForId == mLabeledId);
}
}
+
+ /**
+ * Dump all private flags in readable format, useful for documentation and
+ * sanity checking.
+ */
+ private static void dumpFlags() {
+ final HashMap<String, String> found = Maps.newHashMap();
+ try {
+ for (Field field : View.class.getDeclaredFields()) {
+ final int modifiers = field.getModifiers();
+ if (Modifier.isStatic(modifiers) && Modifier.isFinal(modifiers)) {
+ if (field.getType().equals(int.class)) {
+ final int value = field.getInt(null);
+ dumpFlag(found, field.getName(), value);
+ } else if (field.getType().equals(int[].class)) {
+ final int[] values = (int[]) field.get(null);
+ for (int i = 0; i < values.length; i++) {
+ dumpFlag(found, field.getName() + "[" + i + "]", values[i]);
+ }
+ }
+ }
+ }
+ } catch (IllegalAccessException e) {
+ throw new RuntimeException(e);
+ }
+
+ final ArrayList<String> keys = Lists.newArrayList();
+ keys.addAll(found.keySet());
+ Collections.sort(keys);
+ for (String key : keys) {
+ Log.d(VIEW_LOG_TAG, found.get(key));
+ }
+ }
+
+ private static void dumpFlag(HashMap<String, String> found, String name, int value) {
+ // Sort flags by prefix, then by bits, always keeping unique keys
+ final String bits = String.format("%32s", Integer.toBinaryString(value)).replace('0', ' ');
+ final int prefix = name.indexOf('_');
+ final String key = (prefix > 0 ? name.substring(0, prefix) : name) + bits + name;
+ final String output = bits + " " + name;
+ found.put(key, output);
+ }
}
diff --git a/core/java/android/view/WindowManagerPolicy.java b/core/java/android/view/WindowManagerPolicy.java
index 75554da..82f07c7 100644
--- a/core/java/android/view/WindowManagerPolicy.java
+++ b/core/java/android/view/WindowManagerPolicy.java
@@ -1111,7 +1111,15 @@ public interface WindowManagerPolicy {
* @param attrs The window's LayoutParams.
* @return Whether magnification can be applied.
*/
- public boolean canMagnifyWindow(WindowManager.LayoutParams attrs);
+ public boolean canMagnifyWindowLw(WindowManager.LayoutParams attrs);
+
+ /**
+ * Called when the current user changes. Guaranteed to be called before the broadcast
+ * of the new user id is made to all listeners.
+ *
+ * @param newUserId The id of the incoming user.
+ */
+ public void setCurrentUserLw(int newUserId);
/**
* Print the WindowManagerPolicy's state into the given stream.
diff --git a/core/java/android/webkit/JWebCoreJavaBridge.java b/core/java/android/webkit/JWebCoreJavaBridge.java
index d9aeb70..e6eaa14 100644
--- a/core/java/android/webkit/JWebCoreJavaBridge.java
+++ b/core/java/android/webkit/JWebCoreJavaBridge.java
@@ -89,7 +89,6 @@ final class JWebCoreJavaBridge extends Handler {
private void fireSharedTimer() {
// clear the flag so that sharedTimerFired() can set a new timer
mHasInstantTimer = false;
- removeMessages(TIMER_MESSAGE);
sharedTimerFired();
}
diff --git a/core/java/android/webkit/WebViewCore.java b/core/java/android/webkit/WebViewCore.java
index 2d834ff..33fe834 100644
--- a/core/java/android/webkit/WebViewCore.java
+++ b/core/java/android/webkit/WebViewCore.java
@@ -2198,20 +2198,12 @@ public final class WebViewCore {
mEventHub.sendMessage(Message.obtain(null, EventHub.WEBKIT_DRAW));
}
m_skipDrawFlag = false;
- m_skipDrawFlagLock.notify();
}
}
private void webkitDraw() {
synchronized (m_skipDrawFlagLock) {
if (m_skipDrawFlag) {
- try {
- // Aggressively throttle webkit to give the UI more CPU
- // to catch up with
- m_skipDrawFlagLock.wait(50);
- } catch (InterruptedException e) {}
- }
- if (m_skipDrawFlag) {
m_drawWasSkipped = true;
return;
}
@@ -2536,6 +2528,9 @@ public final class WebViewCore {
adjust = (float) mContext.getResources().getDisplayMetrics().densityDpi
/ mViewportDensityDpi;
}
+ // We make bad assumptions about multiplying and dividing by 100, force
+ // them to be true with this hack
+ adjust = ((int) (adjust * 100)) / 100.0f;
// Remove any update density messages in flight.
// If the density is indeed different from WebView's default scale,
// a new message will be queued.
diff --git a/core/java/android/webkit/ZoomManager.java b/core/java/android/webkit/ZoomManager.java
index 80a6782..1d864e5 100644
--- a/core/java/android/webkit/ZoomManager.java
+++ b/core/java/android/webkit/ZoomManager.java
@@ -287,6 +287,7 @@ class ZoomManager {
if (!exceedsMinScaleIncrement(mMinZoomScale, mMaxZoomScale)) {
mMaxZoomScale = mMinZoomScale;
}
+ sanitizeMinMaxScales();
}
public final float getScale() {
@@ -909,6 +910,14 @@ class ZoomManager {
}
}
+ private void sanitizeMinMaxScales() {
+ if (mMinZoomScale > mMaxZoomScale) {
+ Log.w(LOGTAG, "mMinZoom > mMaxZoom!!! " + mMinZoomScale + " > " + mMaxZoomScale,
+ new Exception());
+ mMaxZoomScale = mMinZoomScale;
+ }
+ }
+
public void onSizeChanged(int w, int h, int ow, int oh) {
// reset zoom and anchor to the top left corner of the screen
// unless we are already zooming
@@ -933,6 +942,7 @@ class ZoomManager {
if (mInitialScale > 0 && mInitialScale < mMinZoomScale) {
mMinZoomScale = mInitialScale;
}
+ sanitizeMinMaxScales();
}
dismissZoomPicker();
@@ -1004,6 +1014,7 @@ class ZoomManager {
} else {
mMaxZoomScale = viewState.mMaxScale;
}
+ sanitizeMinMaxScales();
}
/**
@@ -1033,6 +1044,7 @@ class ZoomManager {
if (!mMinZoomScaleFixed || settings.getUseWideViewPort()) {
mMinZoomScale = newZoomOverviewScale;
mMaxZoomScale = Math.max(mMaxZoomScale, mMinZoomScale);
+ sanitizeMinMaxScales();
}
// fit the content width to the current view for the first new picture
// after first layout.
@@ -1113,6 +1125,7 @@ class ZoomManager {
mMinZoomScale = (mInitialScale > 0) ?
Math.min(mInitialScale, overviewScale) : overviewScale;
mMaxZoomScale = Math.max(mMaxZoomScale, mMinZoomScale);
+ sanitizeMinMaxScales();
}
if (!mWebView.drawHistory()) {
diff --git a/core/java/android/widget/AppSecurityPermissions.java b/core/java/android/widget/AppSecurityPermissions.java
index f79ec42..27d15f6 100755
--- a/core/java/android/widget/AppSecurityPermissions.java
+++ b/core/java/android/widget/AppSecurityPermissions.java
@@ -24,8 +24,6 @@ import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
-import android.content.pm.PackageParser;
-import android.content.pm.PackageUserState;
import android.content.pm.PermissionGroupInfo;
import android.content.pm.PermissionInfo;
import android.graphics.drawable.Drawable;
@@ -272,7 +270,7 @@ public class AppSecurityPermissions {
setPermissions(mPermsList);
}
- public AppSecurityPermissions(Context context, PackageParser.Package pkg) {
+ public AppSecurityPermissions(Context context, PackageInfo info) {
mContext = context;
mPm = mContext.getPackageManager();
loadResources();
@@ -280,14 +278,11 @@ public class AppSecurityPermissions {
mPermGroupComparator = new PermissionGroupInfoComparator();
mPermsList = new ArrayList<MyPermissionInfo>();
Set<MyPermissionInfo> permSet = new HashSet<MyPermissionInfo>();
- if(pkg == null) {
+ if(info == null) {
return;
}
// Convert to a PackageInfo
- PackageInfo info = PackageParser.generatePackageInfo(pkg, null,
- PackageManager.GET_PERMISSIONS, 0, 0, null,
- new PackageUserState());
PackageInfo installedPkgInfo = null;
// Get requested permissions
if (info.requestedPermissions != null) {
@@ -299,13 +294,13 @@ public class AppSecurityPermissions {
extractPerms(info, permSet, installedPkgInfo);
}
// Get permissions related to shared user if any
- if (pkg.mSharedUserId != null) {
+ if (info.sharedUserId != null) {
int sharedUid;
try {
- sharedUid = mPm.getUidForSharedUser(pkg.mSharedUserId);
+ sharedUid = mPm.getUidForSharedUser(info.sharedUserId);
getAllUsedPermissions(sharedUid, permSet);
} catch (NameNotFoundException e) {
- Log.w(TAG, "Could'nt retrieve shared user id for:"+pkg.packageName);
+ Log.w(TAG, "Could'nt retrieve shared user id for:"+info.packageName);
}
}
// Retrieve list of permissions
diff --git a/core/java/com/android/internal/app/AlertController.java b/core/java/com/android/internal/app/AlertController.java
index bcf0ea4..43a02cf 100644
--- a/core/java/com/android/internal/app/AlertController.java
+++ b/core/java/com/android/internal/app/AlertController.java
@@ -347,6 +347,18 @@ public class AlertController {
}
}
+ /**
+ * @param attrId the attributeId of the theme-specific drawable
+ * to resolve the resourceId for.
+ *
+ * @return resId the resourceId of the theme-specific drawable
+ */
+ public int getIconAttributeResId(int attrId) {
+ TypedValue out = new TypedValue();
+ mContext.getTheme().resolveAttribute(attrId, out, true);
+ return out.resourceId;
+ }
+
public void setInverseBackgroundForced(boolean forceInverseBackground) {
mForceInverseBackground = forceInverseBackground;
}
@@ -740,6 +752,7 @@ public class AlertController {
public int mIconId = 0;
public Drawable mIcon;
+ public int mIconAttrId = 0;
public CharSequence mTitle;
public View mCustomTitleView;
public CharSequence mMessage;
@@ -807,6 +820,9 @@ public class AlertController {
if (mIconId >= 0) {
dialog.setIcon(mIconId);
}
+ if (mIconAttrId > 0) {
+ dialog.setIcon(dialog.getIconAttributeResId(mIconAttrId));
+ }
}
if (mMessage != null) {
dialog.setMessage(mMessage);
diff --git a/core/java/com/android/internal/content/PackageMonitor.java b/core/java/com/android/internal/content/PackageMonitor.java
index 3477a90..20ecace 100644
--- a/core/java/com/android/internal/content/PackageMonitor.java
+++ b/core/java/com/android/internal/content/PackageMonitor.java
@@ -24,6 +24,7 @@ import android.net.Uri;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Looper;
+import android.os.UserHandle;
import java.util.HashSet;
@@ -62,11 +63,17 @@ public abstract class PackageMonitor extends android.content.BroadcastReceiver {
String[] mAppearingPackages;
String[] mModifiedPackages;
int mChangeType;
+ int mChangeUserId = UserHandle.USER_NULL;
boolean mSomePackagesChanged;
-
+
String[] mTempArray = new String[1];
-
+
public void register(Context context, Looper thread, boolean externalStorage) {
+ register(context, thread, null, externalStorage);
+ }
+
+ public void register(Context context, Looper thread, UserHandle user,
+ boolean externalStorage) {
if (mRegisteredContext != null) {
throw new IllegalStateException("Already registered");
}
@@ -84,10 +91,19 @@ public abstract class PackageMonitor extends android.content.BroadcastReceiver {
} else {
mRegisteredHandler = new Handler(thread);
}
- context.registerReceiver(this, sPackageFilt, null, mRegisteredHandler);
- context.registerReceiver(this, sNonDataFilt, null, mRegisteredHandler);
- if (externalStorage) {
- context.registerReceiver(this, sExternalFilt, null, mRegisteredHandler);
+ if (user != null) {
+ context.registerReceiverAsUser(this, user, sPackageFilt, null, mRegisteredHandler);
+ context.registerReceiverAsUser(this, user, sNonDataFilt, null, mRegisteredHandler);
+ if (externalStorage) {
+ context.registerReceiverAsUser(this, user, sExternalFilt, null,
+ mRegisteredHandler);
+ }
+ } else {
+ context.registerReceiver(this, sPackageFilt, null, mRegisteredHandler);
+ context.registerReceiver(this, sNonDataFilt, null, mRegisteredHandler);
+ if (externalStorage) {
+ context.registerReceiver(this, sExternalFilt, null, mRegisteredHandler);
+ }
}
}
@@ -125,6 +141,13 @@ public abstract class PackageMonitor extends android.content.BroadcastReceiver {
public void onPackageRemoved(String packageName, int uid) {
}
+ /**
+ * Called when a package is really removed (and not replaced) for
+ * all users on the device.
+ */
+ public void onPackageRemovedAllUsers(String packageName, int uid) {
+ }
+
public void onPackageUpdateStarted(String packageName, int uid) {
}
@@ -220,7 +243,11 @@ public abstract class PackageMonitor extends android.content.BroadcastReceiver {
public void onFinishPackageChanges() {
}
-
+
+ public int getChangingUserId() {
+ return mChangeUserId;
+ }
+
String getPackageName(Intent intent) {
Uri uri = intent.getData();
String pkg = uri != null ? uri.getSchemeSpecificPart() : null;
@@ -229,6 +256,12 @@ public abstract class PackageMonitor extends android.content.BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
+ mChangeUserId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE,
+ UserHandle.USER_NULL);
+ if (mChangeUserId == UserHandle.USER_NULL) {
+ throw new IllegalArgumentException(
+ "Intent broadcast does not contain user handle: " + intent);
+ }
onBeginPackageChanges();
mDisappearingPackages = mAppearingPackages = null;
@@ -281,6 +314,9 @@ public abstract class PackageMonitor extends android.content.BroadcastReceiver {
// it when it is re-added.
mSomePackagesChanged = true;
onPackageRemoved(pkg, uid);
+ if (intent.getBooleanExtra(Intent.EXTRA_REMOVED_FOR_ALL_USERS, false)) {
+ onPackageRemovedAllUsers(pkg, uid);
+ }
}
onPackageDisappeared(pkg, mChangeType);
}
@@ -344,5 +380,6 @@ public abstract class PackageMonitor extends android.content.BroadcastReceiver {
}
onFinishPackageChanges();
+ mChangeUserId = UserHandle.USER_NULL;
}
}
diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java
index 3207435..8756950 100644
--- a/core/java/com/android/internal/widget/LockPatternUtils.java
+++ b/core/java/com/android/internal/widget/LockPatternUtils.java
@@ -22,14 +22,11 @@ import com.google.android.collect.Lists;
import android.app.ActivityManagerNative;
import android.app.admin.DevicePolicyManager;
-import android.content.BroadcastReceiver;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
-import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.os.Binder;
-import android.os.FileObserver;
import android.os.IBinder;
import android.os.Process;
import android.os.RemoteException;
@@ -45,16 +42,10 @@ import android.util.Log;
import android.view.View;
import android.widget.Button;
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.io.RandomAccessFile;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
-import java.util.Arrays;
import java.util.List;
-import java.util.concurrent.atomic.AtomicBoolean;
/**
* Utilities for the lock pattern and its settings.
@@ -134,7 +125,7 @@ public class LockPatternUtils {
private final ContentResolver mContentResolver;
private DevicePolicyManager mDevicePolicyManager;
private ILockSettings mLockSettingsService;
- private int mCurrentUserId = 0;
+ private int mCurrentUserId = UserHandle.USER_NULL;
public DevicePolicyManager getDevicePolicyManager() {
if (mDevicePolicyManager == null) {
@@ -233,10 +224,14 @@ public class LockPatternUtils {
public int getCurrentUser() {
if (Process.myUid() == Process.SYSTEM_UID) {
+ if (mCurrentUserId != UserHandle.USER_NULL) {
+ // Someone is regularly updating using setCurrentUser() use that value.
+ return mCurrentUserId;
+ }
try {
return ActivityManagerNative.getDefault().getCurrentUser().id;
} catch (RemoteException re) {
- return mCurrentUserId;
+ return UserHandle.USER_OWNER;
}
} else {
throw new SecurityException("Only the system process can get the current user");
@@ -1117,8 +1112,13 @@ public class LockPatternUtils {
* {@link TelephonyManager#CALL_STATE_RINGING}
* {@link TelephonyManager#CALL_STATE_OFFHOOK}
* @param shown indicates whether the given screen wants the emergency button to show at all
+ * @param button
+ * @param phoneState
+ * @param shown shown if true; hidden if false
+ * @param upperCase if true, converts button label string to upper case
*/
- public void updateEmergencyCallButtonState(Button button, int phoneState, boolean shown) {
+ public void updateEmergencyCallButtonState(Button button, int phoneState, boolean shown,
+ boolean upperCase, boolean showIcon) {
if (isEmergencyCallCapable() && shown) {
button.setVisibility(View.VISIBLE);
} else {
@@ -1130,14 +1130,30 @@ public class LockPatternUtils {
if (phoneState == TelephonyManager.CALL_STATE_OFFHOOK) {
// show "return to call" text and show phone icon
textId = R.string.lockscreen_return_to_call;
- int phoneCallIcon = R.drawable.stat_sys_phone_call;
+ int phoneCallIcon = showIcon ? R.drawable.stat_sys_phone_call : 0;
button.setCompoundDrawablesWithIntrinsicBounds(phoneCallIcon, 0, 0, 0);
} else {
textId = R.string.lockscreen_emergency_call;
- int emergencyIcon = R.drawable.ic_emergency;
+ int emergencyIcon = showIcon ? R.drawable.ic_emergency : 0;
button.setCompoundDrawablesWithIntrinsicBounds(emergencyIcon, 0, 0, 0);
}
- button.setText(textId);
+ if (upperCase) {
+ CharSequence original = mContext.getResources().getText(textId);
+ String upper = original != null ? original.toString().toUpperCase() : null;
+ button.setText(upper);
+ } else {
+ button.setText(textId);
+ }
+ }
+
+ /**
+ * @deprecated
+ * @param button
+ * @param phoneState
+ * @param shown
+ */
+ public void updateEmergencyCallButtonState(Button button, int phoneState, boolean shown) {
+ updateEmergencyCallButtonState(button, phoneState, shown, false, true);
}
/**