Merge "Defer wifi bounce following restore for 1 minute..." into jb-mr1-dev
diff --git a/core/java/android/hardware/Camera.java b/core/java/android/hardware/Camera.java
index 1e8671b..6624eb8 100644
--- a/core/java/android/hardware/Camera.java
+++ b/core/java/android/hardware/Camera.java
@@ -18,13 +18,18 @@
 
 import android.annotation.SdkConstant;
 import android.annotation.SdkConstant.SdkConstantType;
+import android.content.Context;
 import android.graphics.ImageFormat;
 import android.graphics.Point;
 import android.graphics.Rect;
 import android.graphics.SurfaceTexture;
+import android.media.IAudioService;
 import android.os.Handler;
+import android.os.IBinder;
 import android.os.Looper;
 import android.os.Message;
+import android.os.RemoteException;
+import android.os.ServiceManager;
 import android.util.Log;
 import android.text.TextUtils;
 import android.view.Surface;
@@ -192,7 +197,21 @@
      * Returns the information about a particular camera.
      * If {@link #getNumberOfCameras()} returns N, the valid id is 0 to N-1.
      */
-    public native static void getCameraInfo(int cameraId, CameraInfo cameraInfo);
+    public static void getCameraInfo(int cameraId, CameraInfo cameraInfo) {
+        _getCameraInfo(cameraId, cameraInfo);
+        IBinder b = ServiceManager.getService(Context.AUDIO_SERVICE);
+        IAudioService audioService = IAudioService.Stub.asInterface(b);
+        try {
+            if (audioService.isCameraSoundForced()) {
+                // Only set this when sound is forced; otherwise let native code
+                // decide.
+                cameraInfo.canDisableShutterSound = false;
+            }
+        } catch (RemoteException e) {
+            Log.e(TAG, "Audio service is unavailable for queries");
+        }
+    }
+    private native static void _getCameraInfo(int cameraId, CameraInfo cameraInfo);
 
     /**
      * Information about a camera
@@ -1185,7 +1204,20 @@
      * @see CameraInfo#canDisableShutterSound
      * @see ShutterCallback
      */
-    public native final boolean enableShutterSound(boolean enabled);
+    public final boolean enableShutterSound(boolean enabled) {
+        if (!enabled) {
+            IBinder b = ServiceManager.getService(Context.AUDIO_SERVICE);
+            IAudioService audioService = IAudioService.Stub.asInterface(b);
+            try {
+                if (audioService.isCameraSoundForced()) return false;
+            } catch (RemoteException e) {
+                Log.e(TAG, "Audio service is unavailable for queries");
+            }
+        }
+        return _enableShutterSound(enabled);
+    }
+
+    private native final boolean _enableShutterSound(boolean enabled);
 
     /**
      * Callback interface for zoom changes during a smooth zoom operation.
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 91c6db5..3c4a8fe 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -5321,6 +5321,7 @@
             ENABLE_ACCESSIBILITY_GLOBAL_GESTURE_ENABLED,
             WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON,
             WIFI_NETWORKS_AVAILABLE_REPEAT_DELAY,
+            WIFI_WATCHDOG_POOR_NETWORK_TEST_ENABLED,
             WIFI_NUM_OPEN_NETWORKS_KEPT,
             EMERGENCY_TONE,
             CALL_AUTO_RETRY,
diff --git a/core/jni/android_hardware_Camera.cpp b/core/jni/android_hardware_Camera.cpp
index 99d49ec..67d831c 100644
--- a/core/jni/android_hardware_Camera.cpp
+++ b/core/jni/android_hardware_Camera.cpp
@@ -854,7 +854,7 @@
   { "getNumberOfCameras",
     "()I",
     (void *)android_hardware_Camera_getNumberOfCameras },
-  { "getCameraInfo",
+  { "_getCameraInfo",
     "(ILandroid/hardware/Camera$CameraInfo;)V",
     (void*)android_hardware_Camera_getCameraInfo },
   { "native_setup",
@@ -917,7 +917,7 @@
   { "setDisplayOrientation",
     "(I)V",
     (void *)android_hardware_Camera_setDisplayOrientation },
-  { "enableShutterSound",
+  { "_enableShutterSound",
     "(Z)Z",
     (void *)android_hardware_Camera_enableShutterSound },
   { "_startFaceDetection",
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardHostView.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardHostView.java
index 6ea3513..840edaf 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardHostView.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardHostView.java
@@ -33,6 +33,8 @@
 import android.graphics.Canvas;
 import android.graphics.Rect;
 import android.os.Looper;
+import android.os.Parcel;
+import android.os.Parcelable;
 import android.os.UserManager;
 import android.util.AttributeSet;
 import android.util.Log;
@@ -43,12 +45,14 @@
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.WindowManager;
+import android.view.View.BaseSavedState;
 import android.view.animation.AnimationUtils;
 import android.widget.RemoteViews.OnClickHandler;
 import android.widget.ViewFlipper;
 
 import com.android.internal.R;
 import com.android.internal.policy.impl.keyguard.KeyguardSecurityModel.SecurityMode;
+import com.android.internal.policy.impl.keyguard.KeyguardTransportControlView.SavedState;
 import com.android.internal.widget.LockPatternUtils;
 
 import java.io.File;
@@ -64,6 +68,10 @@
     static final int APPWIDGET_HOST_ID = 0x4B455947;
     private static final String KEYGUARD_WIDGET_PREFS = "keyguard_widget_prefs";
 
+    private static final int TRANSPORT_GONE = 0;
+    private static final int TRANSPORT_INVISIBLE = 1;
+    private static final int TRANSPORT_VISIBLE = 2;
+
     private AppWidgetHost mAppWidgetHost;
     private KeyguardWidgetRegion mAppWidgetRegion;
     private KeyguardWidgetPager mAppWidgetContainer;
@@ -83,10 +91,12 @@
     private KeyguardSecurityModel mSecurityModel;
 
     private Rect mTempRect = new Rect();
+    private int mTransportState = TRANSPORT_GONE;
 
     /*package*/ interface TransportCallback {
-        void hide();
-        void show();
+        void onListenerDetached();
+        void onListenerAttached();
+        void onPlayStateChanged();
     }
 
     /*package*/ interface UserSwitcherCallback {
@@ -185,7 +195,7 @@
         mAppWidgetHost.startListening();
         maybePopulateWidgets();
         disableStatusViewInteraction();
-        showAppropriateWidgetPage();
+        post(mSwitchPageRunnable);
     }
 
     private void disableStatusViewInteraction() {
@@ -712,7 +722,7 @@
     private void addDefaultWidgets() {
         LayoutInflater inflater = LayoutInflater.from(mContext);
         inflater.inflate(R.layout.keyguard_status_view, mAppWidgetContainer, true);
-        inflater.inflate(R.layout.keyguard_transport_control_view, mAppWidgetContainer, true);
+        inflater.inflate(R.layout.keyguard_transport_control_view, this, true);
 
         inflateAndAddUserSelectorWidgetIfNecessary();
         initializeTransportControl();
@@ -721,16 +731,16 @@
     private void initializeTransportControl() {
         mTransportControl =
             (KeyguardTransportControlView) findViewById(R.id.keyguard_transport_control);
+        mTransportControl.setVisibility(View.GONE);
 
         // This code manages showing/hiding the transport control. We keep it around and only
         // add it to the hierarchy if it needs to be present.
         if (mTransportControl != null) {
             mTransportControl.setKeyguardCallback(new TransportCallback() {
-                boolean mSticky = false;
                 @Override
-                public void hide() {
+                public void onListenerDetached() {
                     int page = getWidgetPosition(R.id.keyguard_transport_control);
-                    if (page != -1 && !mSticky) {
+                    if (page != -1) {
                         if (page == mAppWidgetContainer.getCurrentPage()) {
                             // Switch back to clock view if music was showing.
                             mAppWidgetContainer
@@ -741,20 +751,23 @@
                         // from AudioManager
                         KeyguardHostView.this.addView(mTransportControl);
                         mTransportControl.setVisibility(View.GONE);
+                        mTransportState = TRANSPORT_GONE;
                     }
                 }
 
                 @Override
-                public void show() {
+                public void onListenerAttached() {
                     if (getWidgetPosition(R.id.keyguard_transport_control) == -1) {
                         KeyguardHostView.this.removeView(mTransportControl);
-                        mAppWidgetContainer.addView(mTransportControl,
-                                getWidgetPosition(R.id.keyguard_status_view) + 1);
+                        mAppWidgetContainer.addView(mTransportControl, 0);
                         mTransportControl.setVisibility(View.VISIBLE);
-                        // Once shown, leave it showing
-                        mSticky = true;
                     }
                 }
+
+                @Override
+                public void onPlayStateChanged() {
+                    mTransportControl.post(mSwitchPageRunnable);
+                }
             });
         }
     }
@@ -796,12 +809,87 @@
         }
     }
 
-    private void showAppropriateWidgetPage() {
-        int page = mAppWidgetContainer.indexOfChild(findViewById(R.id.keyguard_status_view));
-        if (mAppWidgetContainer.indexOfChild(mTransportControl) != -1) {
-            page = mAppWidgetContainer.indexOfChild(mTransportControl);
+    Runnable mSwitchPageRunnable = new Runnable() {
+        @Override
+        public void run() {
+           showAppropriateWidgetPage();
         }
-        mAppWidgetContainer.setCurrentPage(page);
+    };
+
+    static class SavedState extends BaseSavedState {
+        int transportState;
+
+        SavedState(Parcelable superState) {
+            super(superState);
+        }
+
+        private SavedState(Parcel in) {
+            super(in);
+            this.transportState = in.readInt();
+        }
+
+        @Override
+        public void writeToParcel(Parcel out, int flags) {
+            super.writeToParcel(out, flags);
+            out.writeInt(this.transportState);
+        }
+
+        public static final Parcelable.Creator<SavedState> CREATOR
+                = new Parcelable.Creator<SavedState>() {
+            public SavedState createFromParcel(Parcel in) {
+                return new SavedState(in);
+            }
+
+            public SavedState[] newArray(int size) {
+                return new SavedState[size];
+            }
+        };
+    }
+
+    @Override
+    public Parcelable onSaveInstanceState() {
+        Parcelable superState = super.onSaveInstanceState();
+        SavedState ss = new SavedState(superState);
+        ss.transportState = mTransportState;
+        return ss;
+    }
+
+    @Override
+    public void onRestoreInstanceState(Parcelable state) {
+        if (!(state instanceof SavedState)) {
+            super.onRestoreInstanceState(state);
+            return;
+        }
+        SavedState ss = (SavedState) state;
+        super.onRestoreInstanceState(ss.getSuperState());
+        mTransportState = ss.transportState;
+        post(mSwitchPageRunnable);
+    }
+
+    private void showAppropriateWidgetPage() {
+
+        // The following sets the priority for showing widgets. Transport should be shown if
+        // music is playing, followed by the multi-user widget if enabled, followed by the
+        // status widget.
+        final int pageToShow;
+        if (mTransportControl.isMusicPlaying() || mTransportState == TRANSPORT_VISIBLE) {
+            mTransportState = TRANSPORT_VISIBLE;
+            pageToShow = mAppWidgetContainer.indexOfChild(mTransportControl);
+        } else {
+            UserManager mUm = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
+            final View multiUserView = findViewById(R.id.keyguard_multi_user_selector);
+            final int multiUserPosition = mAppWidgetContainer.indexOfChild(multiUserView);
+            if (multiUserPosition != -1 && mUm.getUsers(true).size() > 1) {
+                pageToShow = multiUserPosition;
+            } else {
+                final View statusView = findViewById(R.id.keyguard_status_view);
+                pageToShow = mAppWidgetContainer.indexOfChild(statusView);
+            }
+            if (mTransportState == TRANSPORT_VISIBLE) {
+                mTransportState = TRANSPORT_INVISIBLE;
+            }
+        }
+        mAppWidgetContainer.setCurrentPage(pageToShow);
     }
 
     private void inflateAndAddUserSelectorWidgetIfNecessary() {
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardTransportControlView.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardTransportControlView.java
index e2f3059..7e71f94 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardTransportControlView.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardTransportControlView.java
@@ -42,7 +42,6 @@
 import android.view.KeyEvent;
 import android.view.View;
 import android.view.View.OnClickListener;
-import android.widget.FrameLayout;
 import android.widget.ImageView;
 import android.widget.TextView;
 
@@ -59,7 +58,7 @@
     private static final int MSG_SET_GENERATION_ID = 104;
     private static final int MAXDIM = 512;
     private static final int DISPLAY_TIMEOUT_MS = 5000; // 5s
-    protected static final boolean DEBUG = false;
+    protected static final boolean DEBUG = true;
     protected static final String TAG = "TransportControlView";
 
     private ImageView mAlbumArt;
@@ -75,6 +74,7 @@
     private int mCurrentPlayState;
     private AudioManager mAudioManager;
     private IRemoteControlDisplayWeak mIRCD;
+    private boolean mMusicClientPresent = true;
 
     /**
      * The metadata which should be populated into the view once we've been attached
@@ -112,7 +112,9 @@
             case MSG_SET_GENERATION_ID:
                 if (msg.arg2 != 0) {
                     // This means nobody is currently registered. Hide the view.
-                    hide();
+                    onListenerDetached();
+                } else {
+                    onListenerAttached();
                 }
                 if (DEBUG) Log.v(TAG, "New genId = " + msg.arg1 + ", clearing = " + msg.arg2);
                 mClientGeneration = msg.arg1;
@@ -193,28 +195,26 @@
         mIRCD = new IRemoteControlDisplayWeak(mHandler);
     }
 
-    protected void hide() {
-        if (DEBUG) Log.v(TAG, "Transport was told to hide");
+    protected void onListenerDetached() {
+        mMusicClientPresent = false;
+        if (DEBUG) Log.v(TAG, "onListenerDetached()");
         if (mTransportCallback != null) {
-            mTransportCallback.hide();
+            mTransportCallback.onListenerDetached();
         } else {
-            Log.w(TAG, "Hide music, but callback wasn't set");
+            Log.w(TAG, "onListenerDetached: no callback");
         }
     }
 
-    private void show() {
-        if (DEBUG) Log.v(TAG, "Transport was told to show");
+    private void onListenerAttached() {
+        mMusicClientPresent = true;
+        if (DEBUG) Log.v(TAG, "onListenerAttached()");
         if (mTransportCallback != null) {
-            mTransportCallback.show();
+            mTransportCallback.onListenerAttached();
         } else {
-            Log.w(TAG, "Show music, but callback wasn't set");
+            Log.w(TAG, "onListenerAttached(): no callback");
         }
     }
 
-    private void userActivity() {
-        // TODO Auto-generated method stub
-    }
-
     private void updateTransportControls(int transportControlFlags) {
         mTransportControlFlags = transportControlFlags;
     }
@@ -341,6 +341,11 @@
         updatePlayPauseState(mCurrentPlayState);
     }
 
+    public boolean isMusicPlaying() {
+       return mCurrentPlayState == RemoteControlClient.PLAYSTATE_PLAYING
+               || mCurrentPlayState == RemoteControlClient.PLAYSTATE_BUFFERING;
+    }
+
     private static void setVisibilityBasedOnFlag(View view, int flags, int flag) {
         if ((flags & flag) != 0) {
             view.setVisibility(View.VISIBLE);
@@ -357,7 +362,6 @@
         }
         final int imageResId;
         final int imageDescId;
-        boolean showIfHidden = false;
         switch (state) {
             case RemoteControlClient.PLAYSTATE_ERROR:
                 imageResId = com.android.internal.R.drawable.stat_sys_warning;
@@ -369,32 +373,27 @@
             case RemoteControlClient.PLAYSTATE_PLAYING:
                 imageResId = com.android.internal.R.drawable.ic_media_pause;
                 imageDescId = com.android.internal.R.string.lockscreen_transport_pause_description;
-                showIfHidden = true;
                 break;
 
             case RemoteControlClient.PLAYSTATE_BUFFERING:
                 imageResId = com.android.internal.R.drawable.ic_media_stop;
                 imageDescId = com.android.internal.R.string.lockscreen_transport_stop_description;
-                showIfHidden = true;
                 break;
 
             case RemoteControlClient.PLAYSTATE_PAUSED:
             default:
                 imageResId = com.android.internal.R.drawable.ic_media_play;
                 imageDescId = com.android.internal.R.string.lockscreen_transport_play_description;
-                showIfHidden = false;
                 break;
         }
         mBtnPlay.setImageResource(imageResId);
         mBtnPlay.setContentDescription(getResources().getString(imageDescId));
-        if (showIfHidden) {
-            show();
-        }
         mCurrentPlayState = state;
+        mTransportCallback.onPlayStateChanged();
     }
 
     static class SavedState extends BaseSavedState {
-        boolean wasShowing;
+        boolean clientPresent;
 
         SavedState(Parcelable superState) {
             super(superState);
@@ -402,13 +401,13 @@
 
         private SavedState(Parcel in) {
             super(in);
-            this.wasShowing = in.readInt() != 0;
+            this.clientPresent = in.readInt() != 0;
         }
 
         @Override
         public void writeToParcel(Parcel out, int flags) {
             super.writeToParcel(out, flags);
-            out.writeInt(this.wasShowing ? 1 : 0);
+            out.writeInt(this.clientPresent ? 1 : 0);
         }
 
         public static final Parcelable.Creator<SavedState> CREATOR
@@ -425,24 +424,23 @@
 
     @Override
     public Parcelable onSaveInstanceState() {
-        if (DEBUG) Log.v(TAG, "onSaveInstanceState()");
         Parcelable superState = super.onSaveInstanceState();
         SavedState ss = new SavedState(superState);
-        ss.wasShowing = getVisibility() == View.VISIBLE;
+        ss.clientPresent = mMusicClientPresent;
         return ss;
     }
 
     @Override
     public void onRestoreInstanceState(Parcelable state) {
-        if (DEBUG) Log.v(TAG, "onRestoreInstanceState()");
         if (!(state instanceof SavedState)) {
             super.onRestoreInstanceState(state);
             return;
         }
         SavedState ss = (SavedState) state;
         super.onRestoreInstanceState(ss.getSuperState());
-        if (ss.wasShowing) {
-            show();
+        if (ss.clientPresent) {
+            if (DEBUG) Log.v(TAG, "Reattaching client because it was attached");
+            onListenerAttached();
         }
     }
 
@@ -458,7 +456,6 @@
         }
         if (keyCode != -1) {
             sendMediaButtonClick(keyCode);
-            userActivity();
         }
     }
 
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewManager.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewManager.java
index 33ff71e..d25444f 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewManager.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewManager.java
@@ -48,7 +48,7 @@
  * reported to this class by the current {@link KeyguardViewBase}.
  */
 public class KeyguardViewManager {
-    private final static boolean DEBUG = false;
+    private final static boolean DEBUG = true;
     private static String TAG = "KeyguardViewManager";
     public static boolean USE_UPPER_CASE = true;
 
@@ -359,6 +359,12 @@
 
         if (mKeyguardHost != null) {
             mKeyguardHost.setVisibility(View.GONE);
+
+            // We really only want to preserve keyguard state for configuration changes. Hence
+            // we should clear state of widgets (e.g. Music) when we hide keyguard so it can
+            // start with a fresh state when we return.
+            mStateContainer.clear();
+
             // Don't do this right away, so we can let the view continue to animate
             // as it goes away.
             if (mKeyguardView != null) {
diff --git a/services/java/com/android/server/LocationManagerService.java b/services/java/com/android/server/LocationManagerService.java
index ca28e4c..c5016e6 100644
--- a/services/java/com/android/server/LocationManagerService.java
+++ b/services/java/com/android/server/LocationManagerService.java
@@ -308,6 +308,7 @@
             addProviderLocked(fusedLocationProvider);
             mProxyProviders.add(fusedLocationProvider);
             mEnabledProviders.add(fusedLocationProvider.getName());
+            mRealProviders.put(LocationManager.FUSED_PROVIDER, fusedLocationProvider);
         } else {
             Slog.e(TAG, "no fused location provider found",
                     new IllegalStateException("Location service needs a fused location provider"));
diff --git a/services/java/com/android/server/pm/PackageManagerService.java b/services/java/com/android/server/pm/PackageManagerService.java
index 0600f5c..b8d7286 100644
--- a/services/java/com/android/server/pm/PackageManagerService.java
+++ b/services/java/com/android/server/pm/PackageManagerService.java
@@ -6374,12 +6374,22 @@
             mArgs = args;
 
             if (ret == PackageManager.INSTALL_SUCCEEDED) {
+                 /*
+                 * ADB installs appear as UserHandle.USER_ALL, and can only be performed by
+                 * UserHandle.USER_OWNER, so use the package verifier for UserHandle.USER_OWNER.
+                 */
+                int userIdentifier = getUser().getIdentifier();
+                if (userIdentifier == UserHandle.USER_ALL
+                        && ((flags & PackageManager.INSTALL_FROM_ADB) != 0)) {
+                    userIdentifier = UserHandle.USER_OWNER;
+                }
+
                 /*
                  * Determine if we have any installed package verifiers. If we
                  * do, then we'll defer to them to verify the packages.
                  */
                 final int requiredUid = mRequiredVerifierPackage == null ? -1
-                        : getPackageUid(mRequiredVerifierPackage, getUser().getIdentifier());
+                        : getPackageUid(mRequiredVerifierPackage, userIdentifier);
                 if (requiredUid != -1 && isVerificationEnabled(flags)) {
                     final Intent verification = new Intent(
                             Intent.ACTION_PACKAGE_NEEDS_VERIFICATION);