Merge "MediaRouter/Wireless Display - correct initial state" into jb-mr1-dev
diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java
index fb02c0a..7e11c22 100644
--- a/core/java/android/os/PowerManager.java
+++ b/core/java/android/os/PowerManager.java
@@ -178,6 +178,16 @@
     /**
      * Wake lock level: Turns the screen off when the proximity sensor activates.
      * <p>
+     * If the proximity sensor detects that an object is nearby, the screen turns off
+     * immediately.  Shortly after the object moves away, the screen turns on again.
+     * </p><p>
+     * A proximity wake lock does not prevent the device from falling asleep
+     * unlike {@link #FULL_WAKE_LOCK}, {@link #SCREEN_BRIGHT_WAKE_LOCK} and
+     * {@link #SCREEN_DIM_WAKE_LOCK}.  If there is no user activity and no other
+     * wake locks are held, then the device will fall asleep (and lock) as usual.
+     * However, the device will not fall asleep while the screen has been turned off
+     * by the proximity sensor because it effectively counts as ongoing user activity.
+     * </p><p>
      * Since not all devices have proximity sensors, use {@link #isWakeLockLevelSupported}
      * to determine whether this wake lock level is supported.
      * </p>
diff --git a/location/java/android/location/LocationRequest.java b/location/java/android/location/LocationRequest.java
index f4f7b09..cb291ea 100644
--- a/location/java/android/location/LocationRequest.java
+++ b/location/java/android/location/LocationRequest.java
@@ -369,7 +369,15 @@
      * @return the same object, so that setters can be chained
      */
     public LocationRequest setExpireIn(long millis) {
-        mExpireAt = millis + SystemClock.elapsedRealtime();
+        long elapsedRealtime = SystemClock.elapsedRealtime();
+
+        // Check for > Long.MAX_VALUE overflow (elapsedRealtime > 0):
+        if (millis > Long.MAX_VALUE - elapsedRealtime) {
+          mExpireAt = Long.MAX_VALUE;
+        } else {
+          mExpireAt = millis + elapsedRealtime;
+        }
+
         if (mExpireAt < 0) mExpireAt = 0;
         return this;
     }
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index 1701f6e..76a5022 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -849,7 +849,6 @@
         if (TABLE_FAVORITES.equals(args.table)) {
             return null;
         }
-        checkWritePermissions(args);
 
         // Special case LOCATION_PROVIDERS_ALLOWED.
         // Support enabling/disabling a single provider (using "+" or "-" prefix)
@@ -869,6 +868,9 @@
             }
         }
 
+        // Check write permissions only after determining which table the insert will touch
+        checkWritePermissions(args);
+
         // The global table is stored under the owner, always
         if (TABLE_GLOBAL.equals(args.table)) {
             desiredUserHandle = UserHandle.USER_OWNER;
diff --git a/services/java/com/android/server/LocationManagerService.java b/services/java/com/android/server/LocationManagerService.java
index 3cea295..0087b57 100644
--- a/services/java/com/android/server/LocationManagerService.java
+++ b/services/java/com/android/server/LocationManagerService.java
@@ -325,6 +325,7 @@
      * @param userId the new active user's UserId
      */
     private void switchUser(int userId) {
+        mBlacklist.switchUser(userId);
         //Log.d("LocationManagerService", "switchUser(" + mCurrentUserId + " -> " + userId + ")"); // TODO: remove this
         synchronized (mLock) {
             // TODO: inform previous user's Receivers that they will no longer receive updates
@@ -639,7 +640,27 @@
                     == PackageManager.PERMISSION_GRANTED) ||
                     (mContext.checkCallingOrSelfPermission(ACCESS_COARSE_LOCATION)
                     == PackageManager.PERMISSION_GRANTED);
+        } else {
+            // mock providers
+            LocationProviderInterface lp = mMockProviders.get(provider);
+            if (lp != null) {
+                ProviderProperties properties = lp.getProperties();
+                if (properties != null) {
+                    if (properties.mRequiresSatellite) {
+                        // provider requiring satellites require FINE permission
+                        return mContext.checkCallingOrSelfPermission(ACCESS_FINE_LOCATION)
+                                == PackageManager.PERMISSION_GRANTED;
+                    } else if (properties.mRequiresNetwork || properties.mRequiresCell) {
+                        // provider requiring network and or cell require COARSE or FINE
+                        return (mContext.checkCallingOrSelfPermission(ACCESS_FINE_LOCATION)
+                                == PackageManager.PERMISSION_GRANTED) ||
+                                (mContext.checkCallingOrSelfPermission(ACCESS_COARSE_LOCATION)
+                                 == PackageManager.PERMISSION_GRANTED);
+                    }
+                }
+            }
         }
+
         return false;
     }
 
diff --git a/services/java/com/android/server/WallpaperManagerService.java b/services/java/com/android/server/WallpaperManagerService.java
index 4225913..98f561c 100644
--- a/services/java/com/android/server/WallpaperManagerService.java
+++ b/services/java/com/android/server/WallpaperManagerService.java
@@ -38,6 +38,7 @@
 import android.content.pm.ResolveInfo;
 import android.content.pm.ServiceInfo;
 import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.pm.UserInfo;
 import android.content.res.Resources;
 import android.os.Binder;
 import android.os.Bundle;
@@ -53,6 +54,7 @@
 import android.os.ServiceManager;
 import android.os.SystemClock;
 import android.os.UserHandle;
+import android.os.UserManager;
 import android.service.wallpaper.IWallpaperConnection;
 import android.service.wallpaper.IWallpaperEngine;
 import android.service.wallpaper.IWallpaperService;
@@ -511,6 +513,9 @@
                 wallpaper = new WallpaperData(userId);
                 mWallpaperMap.put(userId, wallpaper);
                 loadSettingsLocked(userId);
+            }
+            // Not started watching yet, in case wallpaper data was loaded for other reasons.
+            if (wallpaper.wallpaperObserver == null) {
                 wallpaper.wallpaperObserver = new WallpaperObserver(wallpaper);
                 wallpaper.wallpaperObserver.startWatching();
             }
@@ -580,9 +585,21 @@
 
     public boolean hasNamedWallpaper(String name) {
         synchronized (mLock) {
-            for (int i=0; i<mWallpaperMap.size(); i++) {
-                WallpaperData wd = mWallpaperMap.valueAt(i);
-                if (name.equals(wd.name)) {
+            List<UserInfo> users;
+            long ident = Binder.clearCallingIdentity();
+            try {
+                users = ((UserManager) mContext.getSystemService(Context.USER_SERVICE)).getUsers();
+            } finally {
+                Binder.restoreCallingIdentity(ident);
+            }
+            for (UserInfo user: users) {
+                WallpaperData wd = mWallpaperMap.get(user.id);
+                if (wd == null) {
+                    // User hasn't started yet, so load her settings to peek at the wallpaper
+                    loadSettingsLocked(user.id);
+                    wd = mWallpaperMap.get(user.id);
+                }
+                if (wd != null && name.equals(wd.name)) {
                     return true;
                 }
             }
diff --git a/services/java/com/android/server/connectivity/Tethering.java b/services/java/com/android/server/connectivity/Tethering.java
index b38d617..e4a7ead 100644
--- a/services/java/com/android/server/connectivity/Tethering.java
+++ b/services/java/com/android/server/connectivity/Tethering.java
@@ -454,7 +454,8 @@
             if (mTetheredNotification.icon == icon) {
                 return;
             }
-            notificationManager.cancel(mTetheredNotification.icon);
+            notificationManager.cancelAsUser(null, mTetheredNotification.icon,
+                    UserHandle.ALL);
         }
 
         Intent intent = new Intent();
diff --git a/services/java/com/android/server/location/LocationBlacklist.java b/services/java/com/android/server/location/LocationBlacklist.java
index 6ad1a92e..2437a37 100644
--- a/services/java/com/android/server/location/LocationBlacklist.java
+++ b/services/java/com/android/server/location/LocationBlacklist.java
@@ -20,6 +20,7 @@
 import android.content.Context;
 import android.database.ContentObserver;
 import android.os.Handler;
+import android.os.UserHandle;
 import android.provider.Settings;
 import android.util.Log;
 import android.util.Slog;
@@ -48,6 +49,8 @@
     // all fields below synchronized on mLock
     private String[] mWhitelist = new String[0];
     private String[] mBlacklist = new String[0];
+
+    private int mCurrentUserId = UserHandle.USER_OWNER;
     
     public LocationBlacklist(Context context, Handler handler) {
         super(handler);
@@ -56,20 +59,22 @@
 
     public void init() {
         mContext.getContentResolver().registerContentObserver(Settings.Secure.getUriFor(
-                BLACKLIST_CONFIG_NAME), false, this);
+                BLACKLIST_CONFIG_NAME), false, this, UserHandle.USER_ALL);
 //        mContext.getContentResolver().registerContentObserver(Settings.Secure.getUriFor(
-//                WHITELIST_CONFIG_NAME), false, this);
+//                WHITELIST_CONFIG_NAME), false, this, UserHandle.USER_ALL);
         reloadBlacklist();
     }
 
+    private void reloadBlacklistLocked() {
+        mWhitelist = getStringArrayLocked(WHITELIST_CONFIG_NAME);
+        Slog.i(TAG, "whitelist: " + Arrays.toString(mWhitelist));
+        mBlacklist = getStringArrayLocked(BLACKLIST_CONFIG_NAME);
+        Slog.i(TAG, "blacklist: " + Arrays.toString(mBlacklist));
+    }
+
     private void reloadBlacklist() {
-        String blacklist[] = getStringArray(BLACKLIST_CONFIG_NAME);
-        String whitelist[] = getStringArray(WHITELIST_CONFIG_NAME);
         synchronized (mLock) {
-            mWhitelist = whitelist;
-            Slog.i(TAG, "whitelist: " + Arrays.toString(mWhitelist));
-            mBlacklist = blacklist;
-            Slog.i(TAG, "blacklist: " + Arrays.toString(mBlacklist));
+            reloadBlacklistLocked();
         }
     }
 
@@ -78,7 +83,6 @@
      * (package name matches blacklist, and does not match whitelist)
      */
     public boolean isBlacklisted(String packageName) {
-        /*
         synchronized (mLock) {
             for (String black : mBlacklist) {
                 if (packageName.startsWith(black)) {
@@ -92,7 +96,6 @@
                 }
             }
         }
-        */
         return false;
     }
 
@@ -113,8 +116,19 @@
         reloadBlacklist();
     }
 
-    private String[] getStringArray(String key) {
-        String flatString = Settings.Secure.getString(mContext.getContentResolver(), key);
+    public void switchUser(int userId) {
+        synchronized(mLock) {
+            mCurrentUserId = userId;
+            reloadBlacklistLocked();
+        }
+    }
+
+    private String[] getStringArrayLocked(String key) {
+        String flatString;
+        synchronized(mLock) {
+            flatString = Settings.Secure.getStringForUser(mContext.getContentResolver(), key,
+                    mCurrentUserId);
+        }
         if (flatString == null) {
             return new String[0];
         }
diff --git a/services/java/com/android/server/power/DisplayPowerController.java b/services/java/com/android/server/power/DisplayPowerController.java
index 4f8cdde..d0e758f 100644
--- a/services/java/com/android/server/power/DisplayPowerController.java
+++ b/services/java/com/android/server/power/DisplayPowerController.java
@@ -117,8 +117,9 @@
     private static final int PROXIMITY_NEGATIVE = 0;
     private static final int PROXIMITY_POSITIVE = 1;
 
-    // Proximity sensor debounce delay in milliseconds.
-    private static final int PROXIMITY_SENSOR_DEBOUNCE_DELAY = 250;
+    // Proximity sensor debounce delay in milliseconds for positive or negative transitions.
+    private static final int PROXIMITY_SENSOR_POSITIVE_DEBOUNCE_DELAY = 0;
+    private static final int PROXIMITY_SENSOR_NEGATIVE_DEBOUNCE_DELAY = 500;
 
     // Trigger proximity if distance is less than 5 cm.
     private static final float TYPICAL_PROXIMITY_THRESHOLD = 5.0f;
@@ -562,6 +563,7 @@
                 if (!mScreenOffBecauseOfProximity
                         && mProximity == PROXIMITY_POSITIVE) {
                     mScreenOffBecauseOfProximity = true;
+                    sendOnProximityPositive();
                     setScreenOn(false);
                 }
             } else if (mWaitingForNegativeProximity
@@ -734,8 +736,13 @@
         // Only accept a proximity sensor reading if it remains
         // stable for the entire debounce delay.
         mHandler.removeMessages(MSG_PROXIMITY_SENSOR_DEBOUNCED);
-        mPendingProximity = positive ? PROXIMITY_POSITIVE : PROXIMITY_NEGATIVE;
-        mPendingProximityDebounceTime = time + PROXIMITY_SENSOR_DEBOUNCE_DELAY;
+        if (positive) {
+            mPendingProximity = PROXIMITY_POSITIVE;
+            mPendingProximityDebounceTime = time + PROXIMITY_SENSOR_POSITIVE_DEBOUNCE_DELAY;
+        } else {
+            mPendingProximity = PROXIMITY_NEGATIVE;
+            mPendingProximityDebounceTime = time + PROXIMITY_SENSOR_NEGATIVE_DEBOUNCE_DELAY;
+        }
         debounceProximitySensor();
     }
 
@@ -973,6 +980,17 @@
         }
     };
 
+    private void sendOnProximityPositive() {
+        mCallbackHandler.post(mOnProximityPositiveRunnable);
+    }
+
+    private final Runnable mOnProximityPositiveRunnable = new Runnable() {
+        @Override
+        public void run() {
+            mCallbacks.onProximityPositive();
+        }
+    };
+
     private void sendOnProximityNegative() {
         mCallbackHandler.post(mOnProximityNegativeRunnable);
     }
@@ -1090,6 +1108,7 @@
      */
     public interface Callbacks {
         void onStateChanged();
+        void onProximityPositive();
         void onProximityNegative();
     }
 
diff --git a/services/java/com/android/server/power/PowerManagerService.java b/services/java/com/android/server/power/PowerManagerService.java
index 9a01022..eecac07 100644
--- a/services/java/com/android/server/power/PowerManagerService.java
+++ b/services/java/com/android/server/power/PowerManagerService.java
@@ -98,6 +98,8 @@
     private static final int DIRTY_STAY_ON = 1 << 7;
     // Dirty bit: battery state changed
     private static final int DIRTY_BATTERY_STATE = 1 << 8;
+    // Dirty bit: proximity state changed
+    private static final int DIRTY_PROXIMITY_POSITIVE = 1 << 9;
 
     // Wakefulness: The device is asleep and can only be awoken by a call to wakeUp().
     // The screen should be off or in the process of being turned off by the display controller.
@@ -258,6 +260,9 @@
     // True if the device should stay on.
     private boolean mStayOn;
 
+    // True if the proximity sensor reads a positive result.
+    private boolean mProximityPositive;
+
     // Screen brightness setting limits.
     private int mScreenBrightnessSettingMinimum;
     private int mScreenBrightnessSettingMaximum;
@@ -1101,12 +1106,17 @@
      */
     private void updateStayOnLocked(int dirty) {
         if ((dirty & (DIRTY_BATTERY_STATE | DIRTY_SETTINGS)) != 0) {
+            final boolean wasStayOn = mStayOn;
             if (mStayOnWhilePluggedInSetting != 0
                     && !isMaximumScreenOffTimeoutFromDeviceAdminEnforcedLocked()) {
                 mStayOn = mBatteryService.isPowered(mStayOnWhilePluggedInSetting);
             } else {
                 mStayOn = false;
             }
+
+            if (mStayOn != wasStayOn) {
+                mDirty |= DIRTY_STAY_ON;
+            }
         }
     }
 
@@ -1265,7 +1275,7 @@
     private boolean updateWakefulnessLocked(int dirty) {
         boolean changed = false;
         if ((dirty & (DIRTY_WAKE_LOCKS | DIRTY_USER_ACTIVITY | DIRTY_BOOT_COMPLETED
-                | DIRTY_WAKEFULNESS | DIRTY_STAY_ON)) != 0) {
+                | DIRTY_WAKEFULNESS | DIRTY_STAY_ON | DIRTY_PROXIMITY_POSITIVE)) != 0) {
             if (mWakefulness == WAKEFULNESS_AWAKE && isItBedTimeYetLocked()) {
                 if (DEBUG_SPEW) {
                     Slog.d(TAG, "updateWakefulnessLocked: Bed time...");
@@ -1288,17 +1298,17 @@
      * to being fully awake or else go to sleep for good.
      */
     private boolean isItBedTimeYetLocked() {
-        return mBootCompleted && !isScreenBeingKeptOnLocked();
+        return mBootCompleted && !isBeingKeptAwakeLocked();
     }
 
     /**
-     * Returns true if the screen is being kept on by a wake lock, user activity
+     * Returns true if the device is being kept awake by a wake lock, user activity
      * or the stay on while powered setting.
      */
-    private boolean isScreenBeingKeptOnLocked() {
+    private boolean isBeingKeptAwakeLocked() {
         return mStayOn
-                || (mWakeLockSummary & (WAKE_LOCK_SCREEN_BRIGHT | WAKE_LOCK_SCREEN_DIM
-                        | WAKE_LOCK_PROXIMITY_SCREEN_OFF)) != 0
+                || mProximityPositive
+                || (mWakeLockSummary & (WAKE_LOCK_SCREEN_BRIGHT | WAKE_LOCK_SCREEN_DIM)) != 0
                 || (mUserActivitySummary & (USER_ACTIVITY_SCREEN_BRIGHT
                         | USER_ACTIVITY_SCREEN_DIM)) != 0;
     }
@@ -1314,6 +1324,7 @@
                 | DIRTY_SETTINGS
                 | DIRTY_IS_POWERED
                 | DIRTY_STAY_ON
+                | DIRTY_PROXIMITY_POSITIVE
                 | DIRTY_BATTERY_STATE)) != 0) {
             scheduleSandmanLocked();
         }
@@ -1401,7 +1412,7 @@
                 && mDreamsEnabledSetting
                 && mDisplayPowerRequest.screenState != DisplayPowerRequest.SCREEN_STATE_OFF
                 && mBootCompleted
-                && (mIsPowered || isScreenBeingKeptOnLocked());
+                && (mIsPowered || isBeingKeptAwakeLocked());
     }
 
     /**
@@ -1528,7 +1539,16 @@
         }
 
         @Override
+        public void onProximityPositive() {
+            mProximityPositive = true;
+            mDirty |= DIRTY_PROXIMITY_POSITIVE;
+            updatePowerStateLocked();
+        }
+
+        @Override
         public void onProximityNegative() {
+            mProximityPositive = false;
+            mDirty |= DIRTY_PROXIMITY_POSITIVE;
             userActivityNoUpdateLocked(SystemClock.uptimeMillis(),
                     PowerManager.USER_ACTIVITY_EVENT_OTHER, 0, Process.SYSTEM_UID);
             updatePowerStateLocked();
@@ -1986,6 +2006,7 @@
             pw.println("  mIsPowered=" + mIsPowered);
             pw.println("  mPlugType=" + mPlugType);
             pw.println("  mStayOn=" + mStayOn);
+            pw.println("  mProximityPositive=" + mProximityPositive);
             pw.println("  mBootCompleted=" + mBootCompleted);
             pw.println("  mSystemReady=" + mSystemReady);
             pw.println("  mWakeLockSummary=0x" + Integer.toHexString(mWakeLockSummary));