Merge "Add battery to AOD"
diff --git a/cmds/statsd/Android.mk b/cmds/statsd/Android.mk
index 2ebbba6..2c35d41 100644
--- a/cmds/statsd/Android.mk
+++ b/cmds/statsd/Android.mk
@@ -199,6 +199,24 @@
 
 include $(BUILD_NATIVE_TEST)
 
+##############################
+# stats proto static java lib
+##############################
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := statsdprotolite
+
+LOCAL_SRC_FILES := \
+    src/stats_log.proto \
+    src/statsd_config.proto \
+    src/atoms.proto
+
+LOCAL_PROTOC_OPTIMIZE_TYPE := lite
+
+LOCAL_STATIC_JAVA_LIBRARIES := \
+    platformprotoslite
+
+include $(BUILD_STATIC_JAVA_LIBRARY)
 
 statsd_common_src:=
 statsd_common_aidl_includes:=
@@ -209,4 +227,4 @@
 
 ##############################
 
-include $(call all-makefiles-under,$(LOCAL_PATH))
\ No newline at end of file
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 850aedd..6d91f59 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -6830,7 +6830,7 @@
          * @hide
          */
         public static final int SHOW_ROTATION_SUGGESTIONS_DEFAULT =
-                SHOW_ROTATION_SUGGESTIONS_DISABLED;
+                SHOW_ROTATION_SUGGESTIONS_ENABLED;
 
         /**
          * Read only list of the service components that the current user has explicitly allowed to
diff --git a/core/java/android/widget/VideoView2.java b/core/java/android/widget/VideoView2.java
new file mode 100644
index 0000000..310a7bb
--- /dev/null
+++ b/core/java/android/widget/VideoView2.java
@@ -0,0 +1,363 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.widget;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.Context;
+import android.graphics.Canvas;
+import android.media.AudioAttributes;
+import android.media.MediaPlayer;
+import android.media.update.ApiLoader;
+import android.media.update.VideoView2Provider;
+import android.media.update.ViewProvider;
+import android.net.Uri;
+import android.util.AttributeSet;
+import android.view.KeyEvent;
+import android.view.MotionEvent;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.Map;
+
+/**
+ * TODO PUBLIC API
+ * @hide
+ */
+public class VideoView2 extends FrameLayout {
+    @IntDef({
+            VIEW_TYPE_TEXTUREVIEW,
+            VIEW_TYPE_SURFACEVIEW
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface ViewType {}
+    public static final int VIEW_TYPE_SURFACEVIEW = 1;
+    public static final int VIEW_TYPE_TEXTUREVIEW = 2;
+
+    private final VideoView2Provider mProvider;
+
+    /**
+     * @hide
+     */
+    public VideoView2(@NonNull Context context) {
+        this(context, null);
+    }
+
+    /**
+     * @hide
+     */
+    public VideoView2(@NonNull Context context, @Nullable AttributeSet attrs) {
+        this(context, attrs, 0);
+    }
+
+    /**
+     * @hide
+     */
+    public VideoView2(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
+        this(context, attrs, defStyleAttr, 0);
+    }
+
+    /**
+     * @hide
+     */
+    public VideoView2(
+            @NonNull Context context, @Nullable AttributeSet attrs,
+            int defStyleAttr, int defStyleRes) {
+        super(context, attrs, defStyleAttr, defStyleRes);
+
+        mProvider = ApiLoader.getProvider(context).createVideoView2(this, new SuperProvider());
+    }
+
+    /**
+     * @hide
+     */
+    public VideoView2Provider getProvider() {
+        return mProvider;
+    }
+
+    /**
+     * @hide
+     */
+    public void start() {
+        mProvider.start_impl();
+    }
+
+    /**
+     * @hide
+     */
+    public void pause() {
+        mProvider.pause_impl();
+    }
+
+    /**
+     * @hide
+     */
+    public int getDuration() {
+        return mProvider.getDuration_impl();
+    }
+
+    /**
+     * @hide
+     */
+    public int getCurrentPosition() {
+        return mProvider.getCurrentPosition_impl();
+    }
+
+    /**
+     * @hide
+     */
+    public void seekTo(int msec) {
+        mProvider.seekTo_impl(msec);
+    }
+
+    /**
+     * @hide
+     */
+    public boolean isPlaying() {
+        return mProvider.isPlaying_impl();
+    }
+
+    /**
+     * @hide
+     */
+    public int getBufferPercentage() {
+        return mProvider.getBufferPercentage_impl();
+    }
+
+    /**
+     * @hide
+     */
+    public int getAudioSessionId() {
+        return mProvider.getAudioSessionId_impl();
+    }
+
+    /**
+     * @hide
+     */
+    public void showSubtitle() {
+        mProvider.showSubtitle_impl();
+    }
+
+    /**
+     * @hide
+     */
+    public void hideSubtitle() {
+        mProvider.hideSubtitle_impl();
+    }
+
+    /**
+     * @hide
+     */
+    public void setAudioFocusRequest(int focusGain) {
+        mProvider.setAudioFocusRequest_impl(focusGain);
+    }
+
+    /**
+     * @hide
+     */
+    public void setAudioAttributes(@NonNull AudioAttributes attributes) {
+        mProvider.setAudioAttributes_impl(attributes);
+    }
+
+    /**
+     * @hide
+     */
+    public void setVideoPath(String path) {
+        mProvider.setVideoPath_impl(path);
+    }
+
+    /**
+     * @hide
+     */
+    public void setVideoURI(Uri uri) {
+        mProvider.setVideoURI_impl(uri);
+    }
+
+    /**
+     * @hide
+     */
+    public void setVideoURI(Uri uri, Map<String, String> headers) {
+        mProvider.setVideoURI_impl(uri, headers);
+    }
+
+    /**
+     * @hide
+     */
+    public void setMediaController2(MediaController2 controllerView) {
+        mProvider.setMediaController2_impl(controllerView);
+    }
+
+    /**
+     * @hide
+     */
+    public void setViewType(@ViewType int viewType) {
+        mProvider.setViewType_impl(viewType);
+    }
+
+    /**
+     * @hide
+     */
+    @ViewType
+    public int getViewType() {
+        return mProvider.getViewType_impl();
+    }
+
+    /**
+     * @hide
+     */
+    public void stopPlayback() {
+        mProvider.stopPlayback_impl();
+    }
+
+    /**
+     * @hide
+     */
+    public void setOnPreparedListener(MediaPlayer.OnPreparedListener l) {
+        mProvider.setOnPreparedListener_impl(l);
+    }
+
+    /**
+     * @hide
+     */
+    public void setOnCompletionListener(MediaPlayer.OnCompletionListener l) {
+        mProvider.setOnCompletionListener_impl(l);
+    }
+
+    /**
+     * @hide
+     */
+    public void setOnErrorListener(MediaPlayer.OnErrorListener l) {
+        mProvider.setOnErrorListener_impl(l);
+    }
+
+    /**
+     * @hide
+     */
+    public void setOnInfoListener(MediaPlayer.OnInfoListener l) {
+        mProvider.setOnInfoListener_impl(l);
+    }
+
+    /**
+     * @hide
+     */
+    public void setOnViewTypeChangedListener(OnViewTypeChangedListener l) {
+        mProvider.setOnViewTypeChangedListener_impl(l);
+    }
+
+    /**
+     * @hide
+     */
+    public interface OnViewTypeChangedListener {
+        /**
+         * @hide
+         */
+        void onViewTypeChanged(@ViewType int viewType);
+    }
+
+    @Override
+    public CharSequence getAccessibilityClassName() {
+        return mProvider.getAccessibilityClassName_impl();
+    }
+
+    @Override
+    public boolean onTouchEvent(MotionEvent ev) {
+        return mProvider.onTouchEvent_impl(ev);
+    }
+
+    @Override
+    public boolean onTrackballEvent(MotionEvent ev) {
+        return mProvider.onTrackballEvent_impl(ev);
+    }
+
+    @Override
+    public boolean onKeyDown(int keyCode, KeyEvent event) {
+        return mProvider.onKeyDown_impl(keyCode, event);
+    }
+
+    @Override
+    public void onFinishInflate() {
+        mProvider.onFinishInflate_impl();
+    }
+
+    @Override
+    public boolean dispatchKeyEvent(KeyEvent event) {
+        return mProvider.dispatchKeyEvent_impl(event);
+    }
+
+    @Override
+    public void setEnabled(boolean enabled) {
+        mProvider.setEnabled_impl(enabled);
+    }
+
+    private class SuperProvider implements ViewProvider {
+        @Override
+        public void onAttachedToWindow_impl() {
+            VideoView2.super.onAttachedToWindow();
+        }
+
+        @Override
+        public void onDetachedFromWindow_impl() {
+            VideoView2.super.onDetachedFromWindow();
+        }
+
+        @Override
+        public void onLayout_impl(boolean changed, int left, int top, int right, int bottom) {
+            VideoView2.super.onLayout(changed, left, top, right, bottom);
+        }
+
+        @Override
+        public void draw_impl(Canvas canvas) {
+            VideoView2.super.draw(canvas);
+        }
+
+        @Override
+        public CharSequence getAccessibilityClassName_impl() {
+            return VideoView2.super.getAccessibilityClassName();
+        }
+
+        @Override
+        public boolean onTouchEvent_impl(MotionEvent ev) {
+            return VideoView2.super.onTouchEvent(ev);
+        }
+
+        @Override
+        public boolean onTrackballEvent_impl(MotionEvent ev) {
+            return VideoView2.super.onTrackballEvent(ev);
+        }
+
+        @Override
+        public boolean onKeyDown_impl(int keyCode, KeyEvent event) {
+            return VideoView2.super.onKeyDown(keyCode, event);
+        }
+
+        @Override
+        public void onFinishInflate_impl() {
+            VideoView2.super.onFinishInflate();
+        }
+
+        @Override
+        public boolean dispatchKeyEvent_impl(KeyEvent event) {
+            return VideoView2.super.dispatchKeyEvent(event);
+        }
+
+        @Override
+        public void setEnabled_impl(boolean enabled) {
+            VideoView2.super.setEnabled(enabled);
+        }
+    }
+}
diff --git a/media/java/android/media/update/StaticProvider.java b/media/java/android/media/update/StaticProvider.java
index 19f01c2..a1e2404 100644
--- a/media/java/android/media/update/StaticProvider.java
+++ b/media/java/android/media/update/StaticProvider.java
@@ -18,6 +18,7 @@
 
 import android.annotation.SystemApi;
 import android.widget.MediaController2;
+import android.widget.VideoView2;
 
 /**
  * Interface for connecting the public API to an updatable implementation.
@@ -31,4 +32,5 @@
 public interface StaticProvider {
     MediaController2Provider createMediaController2(
             MediaController2 instance, ViewProvider superProvider);
+    VideoView2Provider createVideoView2(VideoView2 instance, ViewProvider superProvider);
 }
diff --git a/media/java/android/media/update/VideoView2Provider.java b/media/java/android/media/update/VideoView2Provider.java
new file mode 100644
index 0000000..6fc9bdc
--- /dev/null
+++ b/media/java/android/media/update/VideoView2Provider.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media.update;
+
+import android.media.AudioAttributes;
+import android.media.MediaPlayer;
+import android.net.Uri;
+import android.widget.MediaController2;
+import android.widget.VideoView2;
+
+import java.util.Map;
+
+/**
+ * Interface for connecting the public API to an updatable implementation.
+ *
+ * Each instance object is connected to one corresponding updatable object which implements the
+ * runtime behavior of that class. There should a corresponding provider method for all public
+ * methods.
+ *
+ * All methods behave as per their namesake in the public API.
+ *
+ * @see android.widget.VideoView2
+ *
+ * @hide
+ */
+// TODO @SystemApi
+public interface VideoView2Provider extends ViewProvider {
+    void start_impl();
+    void pause_impl();
+    int getDuration_impl();
+    int getCurrentPosition_impl();
+    void seekTo_impl(int msec);
+    boolean isPlaying_impl();
+    int getBufferPercentage_impl();
+    int getAudioSessionId_impl();
+    void showSubtitle_impl();
+    void hideSubtitle_impl();
+    void setAudioFocusRequest_impl(int focusGain);
+    void setAudioAttributes_impl(AudioAttributes attributes);
+    void setVideoPath_impl(String path);
+    void setVideoURI_impl(Uri uri);
+    void setVideoURI_impl(Uri uri, Map<String, String> headers);
+    void setMediaController2_impl(MediaController2 controllerView);
+    void setViewType_impl(int viewType);
+    int getViewType_impl();
+    void stopPlayback_impl();
+    void setOnPreparedListener_impl(MediaPlayer.OnPreparedListener l);
+    void setOnCompletionListener_impl(MediaPlayer.OnCompletionListener l);
+    void setOnErrorListener_impl(MediaPlayer.OnErrorListener l);
+    void setOnInfoListener_impl(MediaPlayer.OnInfoListener l);
+    void setOnViewTypeChangedListener_impl(VideoView2.OnViewTypeChangedListener l);
+}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/lifecycle/LifecycleTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/lifecycle/LifecycleTest.java
index adb4832..ae24c07 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/lifecycle/LifecycleTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/lifecycle/LifecycleTest.java
@@ -16,9 +16,9 @@
 package com.android.settingslib.core.lifecycle;
 
 import static android.arch.lifecycle.Lifecycle.Event.ON_START;
-
 import static com.google.common.truth.Truth.assertThat;
 
+import android.arch.lifecycle.LifecycleOwner;
 import android.content.Context;
 import android.view.Menu;
 import android.view.MenuInflater;
@@ -48,6 +48,7 @@
 @Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
 public class LifecycleTest {
 
+    private LifecycleOwner mLifecycleOwner;
     private Lifecycle mLifecycle;
 
     public static class TestDialogFragment extends ObservableDialogFragment {
@@ -146,7 +147,8 @@
 
     @Before
     public void setUp() {
-        mLifecycle = new Lifecycle(() -> mLifecycle);
+        mLifecycleOwner = () -> mLifecycle;
+        mLifecycle = new Lifecycle(mLifecycleOwner);
     }
 
     @Test
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/development/LogpersistPreferenceControllerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/development/LogpersistPreferenceControllerTest.java
index 5d5733e4..050877d 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/development/LogpersistPreferenceControllerTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/development/LogpersistPreferenceControllerTest.java
@@ -17,11 +17,11 @@
 package com.android.settingslib.development;
 
 import static com.google.common.truth.Truth.assertThat;
-
 import static org.mockito.Mockito.atLeastOnce;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.verify;
 
+import android.arch.lifecycle.LifecycleOwner;
 import android.os.SystemProperties;
 import android.support.v7.preference.ListPreference;
 import android.support.v7.preference.Preference;
@@ -44,6 +44,7 @@
         shadows = SystemPropertiesTestImpl.class)
 public class LogpersistPreferenceControllerTest {
 
+    private LifecycleOwner mLifecycleOwner;
     private Lifecycle mLifecycle;
 
     @Mock
@@ -57,7 +58,8 @@
     public void setUp() {
         MockitoAnnotations.initMocks(this);
         SystemProperties.set("ro.debuggable", "1");
-        mLifecycle = new Lifecycle(() -> mLifecycle);
+        mLifecycleOwner = () -> mLifecycle;
+        mLifecycle = new Lifecycle(mLifecycleOwner);
         mController = new AbstractLogpersistPreferenceController(RuntimeEnvironment.application,
                 mLifecycle) {
             @Override
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/FooterPreferenceMixinTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/FooterPreferenceMixinTest.java
index 75b6c5f..88c57b5 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/FooterPreferenceMixinTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/FooterPreferenceMixinTest.java
@@ -17,13 +17,13 @@
 package com.android.settingslib.widget;
 
 import static com.google.common.truth.Truth.assertThat;
-
 import static org.mockito.Matchers.any;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
+import android.arch.lifecycle.LifecycleOwner;
 import android.support.v14.preference.PreferenceFragment;
 import android.support.v7.preference.PreferenceManager;
 import android.support.v7.preference.PreferenceScreen;
@@ -49,13 +49,15 @@
     @Mock
     private PreferenceScreen mScreen;
 
+    private LifecycleOwner mLifecycleOwner;
     private Lifecycle mLifecycle;
     private FooterPreferenceMixin mMixin;
 
     @Before
     public void setUp() {
         MockitoAnnotations.initMocks(this);
-        mLifecycle = new Lifecycle(() -> mLifecycle);
+        mLifecycleOwner = () -> mLifecycle;
+        mLifecycle = new Lifecycle(mLifecycleOwner);
         when(mFragment.getPreferenceManager()).thenReturn(mock(PreferenceManager.class));
         when(mFragment.getPreferenceManager().getContext())
                 .thenReturn(ShadowApplication.getInstance().getApplicationContext());
diff --git a/packages/SettingsProvider/res/values/defaults.xml b/packages/SettingsProvider/res/values/defaults.xml
index 1be0645..48a3a30 100644
--- a/packages/SettingsProvider/res/values/defaults.xml
+++ b/packages/SettingsProvider/res/values/defaults.xml
@@ -28,7 +28,7 @@
     <string name="def_bluetooth_disabled_profiles" translatable="false">0</string>
     <bool name="def_auto_time">true</bool>
     <bool name="def_auto_time_zone">true</bool>
-    <bool name="def_accelerometer_rotation">true</bool>
+    <bool name="def_accelerometer_rotation">false</bool>
     <!-- Default screen brightness, from 0 to 255.  102 is 40%. -->
     <integer name="def_screen_brightness">102</integer>
     <bool name="def_screen_brightness_automatic_mode">false</bool>
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index a78e176..175cff6 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -2945,7 +2945,7 @@
         }
 
         private final class UpgradeController {
-            private static final int SETTINGS_VERSION = 150;
+            private static final int SETTINGS_VERSION = 151;
 
             private final int mUserId;
 
@@ -3538,6 +3538,18 @@
                     currentVersion = 150;
                 }
 
+                if (currentVersion == 150) {
+                    // Version 151: Reset rotate locked setting for upgrading users
+                    final SettingsState systemSettings = getSystemSettingsLocked(userId);
+                    systemSettings.insertSettingLocked(
+                            Settings.System.ACCELEROMETER_ROTATION,
+                            getContext().getResources().getBoolean(
+                                    R.bool.def_accelerometer_rotation) ? "1" : "0",
+                            null, true, SettingsState.SYSTEM_PACKAGE_NAME);
+
+                    currentVersion = 151;
+                }
+
                 // vXXX: Add new settings above this point.
 
                 if (currentVersion != newVersion) {
diff --git a/services/core/java/com/android/server/policy/WindowOrientationListener.java b/services/core/java/com/android/server/policy/WindowOrientationListener.java
index 1b5a521..48a196d 100644
--- a/services/core/java/com/android/server/policy/WindowOrientationListener.java
+++ b/services/core/java/com/android/server/policy/WindowOrientationListener.java
@@ -32,6 +32,7 @@
 import android.view.Surface;
 
 import java.io.PrintWriter;
+import java.util.List;
 
 /**
  * A special helper class used by the WindowManager
@@ -90,7 +91,28 @@
         mHandler = handler;
         mSensorManager = (SensorManager)context.getSystemService(Context.SENSOR_SERVICE);
         mRate = rate;
-        mSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_DEVICE_ORIENTATION);
+        List<Sensor> l = mSensorManager.getSensorList(Sensor.TYPE_DEVICE_ORIENTATION);
+        Sensor wakeUpDeviceOrientationSensor = null;
+        Sensor nonWakeUpDeviceOrientationSensor = null;
+        /**
+         *  Prefer the wakeup form of the sensor if implemented.
+         *  It's OK to look for just two types of this sensor and use
+         *  the last found. Typical devices will only have one sensor of
+         *  this type.
+         */
+        for (Sensor s : l) {
+            if (s.isWakeUpSensor()) {
+                wakeUpDeviceOrientationSensor = s;
+            } else {
+                nonWakeUpDeviceOrientationSensor = s;
+            }
+        }
+
+        if (wakeUpDeviceOrientationSensor != null) {
+            mSensor = wakeUpDeviceOrientationSensor;
+        } else {
+            mSensor = nonWakeUpDeviceOrientationSensor;
+        }
 
         if (mSensor != null) {
             mOrientationJudge = new OrientationSensorJudge();
diff --git a/services/core/java/com/android/server/wm/DragDropController.java b/services/core/java/com/android/server/wm/DragDropController.java
index 28b4c1d..0171b56 100644
--- a/services/core/java/com/android/server/wm/DragDropController.java
+++ b/services/core/java/com/android/server/wm/DragDropController.java
@@ -136,7 +136,7 @@
             outSurface.copyFrom(surface);
             final IBinder winBinder = window.asBinder();
             IBinder token = new Binder();
-            mDragState = new DragState(mService, token, surface, flags, winBinder);
+            mDragState = new DragState(mService, this, token, surface, flags, winBinder);
             mDragState.mPid = callerPid;
             mDragState.mUid = callerUid;
             mDragState.mOriginalAlpha = alpha;
diff --git a/services/core/java/com/android/server/wm/DragState.java b/services/core/java/com/android/server/wm/DragState.java
index b9f437a..1ac9b88 100644
--- a/services/core/java/com/android/server/wm/DragState.java
+++ b/services/core/java/com/android/server/wm/DragState.java
@@ -42,6 +42,7 @@
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.os.IUserManager;
+import android.os.UserManagerInternal;
 import android.util.Slog;
 import android.view.Display;
 import android.view.DragEvent;
@@ -55,6 +56,7 @@
 import android.view.animation.Interpolator;
 
 import com.android.internal.view.IDragAndDropPermissions;
+import com.android.server.LocalServices;
 import com.android.server.input.InputApplicationHandle;
 import com.android.server.input.InputWindowHandle;
 
@@ -116,10 +118,10 @@
     private final Interpolator mCubicEaseOutInterpolator = new DecelerateInterpolator(1.5f);
     private Point mDisplaySize = new Point();
 
-    DragState(WindowManagerService service, IBinder token, SurfaceControl surface,
-            int flags, IBinder localWin) {
+    DragState(WindowManagerService service, DragDropController controller, IBinder token,
+            SurfaceControl surface, int flags, IBinder localWin) {
         mService = service;
-        mDragDropController = service.mDragDropController;
+        mDragDropController = controller;
         mToken = token;
         mSurfaceControl = surface;
         mFlags = flags;
@@ -318,15 +320,9 @@
 
         mSourceUserId = UserHandle.getUserId(mUid);
 
-        final IUserManager userManager =
-                (IUserManager) ServiceManager.getService(Context.USER_SERVICE);
-        try {
-            mCrossProfileCopyAllowed = !userManager.getUserRestrictions(mSourceUserId).getBoolean(
-                    UserManager.DISALLOW_CROSS_PROFILE_COPY_PASTE);
-        } catch (RemoteException e) {
-            Slog.e(TAG_WM, "Remote Exception calling UserManager: " + e);
-            mCrossProfileCopyAllowed = false;
-        }
+        final UserManagerInternal userManager = LocalServices.getService(UserManagerInternal.class);
+        mCrossProfileCopyAllowed = !userManager.getUserRestriction(
+                mSourceUserId, UserManager.DISALLOW_CROSS_PROFILE_COPY_PASTE);
 
         if (DEBUG_DRAG) {
             Slog.d(TAG_WM, "broadcasting DRAG_STARTED at (" + touchX + ", " + touchY + ")");
@@ -534,7 +530,8 @@
         final int targetUserId = UserHandle.getUserId(touchedWin.getOwningUid());
 
         final DragAndDropPermissionsHandler dragAndDropPermissions;
-        if ((mFlags & View.DRAG_FLAG_GLOBAL) != 0 && (mFlags & DRAG_FLAGS_URI_ACCESS) != 0) {
+        if ((mFlags & View.DRAG_FLAG_GLOBAL) != 0 && (mFlags & DRAG_FLAGS_URI_ACCESS) != 0
+                && mData != null) {
             dragAndDropPermissions = new DragAndDropPermissionsHandler(
                     mData,
                     mUid,
@@ -546,7 +543,9 @@
             dragAndDropPermissions = null;
         }
         if (mSourceUserId != targetUserId){
-            mData.fixUris(mSourceUserId);
+            if (mData != null) {
+                mData.fixUris(mSourceUserId);
+            }
         }
         final int myPid = Process.myPid();
         final IBinder token = touchedWin.mClient.asBinder();
diff --git a/services/tests/servicestests/src/com/android/server/wm/DragDropControllerTests.java b/services/tests/servicestests/src/com/android/server/wm/DragDropControllerTests.java
index ce76a22..ac29163 100644
--- a/services/tests/servicestests/src/com/android/server/wm/DragDropControllerTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/DragDropControllerTests.java
@@ -16,27 +16,38 @@
 
 package com.android.server.wm;
 
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
+import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
 import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
-import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
-import static org.mockito.Matchers.anyInt;
 import static org.mockito.Mockito.any;
 import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.when;
 
+import android.content.ClipData;
 import android.os.IBinder;
+import android.os.Looper;
+import android.os.UserHandle;
+import android.os.UserManagerInternal;
 import android.platform.test.annotations.Presubmit;
 import android.support.test.filters.SmallTest;
 import android.support.test.runner.AndroidJUnit4;
 import android.view.InputChannel;
 import android.view.Surface;
 import android.view.SurfaceSession;
+import android.view.View;
+import com.android.internal.annotations.GuardedBy;
+import com.android.server.LocalServices;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
+
 /**
  * Tests for the {@link DragDropController} class.
  *
@@ -46,36 +57,92 @@
 @RunWith(AndroidJUnit4.class)
 @Presubmit
 public class DragDropControllerTests extends WindowTestsBase {
-    private static final int TIMEOUT_MS = 1000;
-    private DragDropController mTarget;
+    private static final int TIMEOUT_MS = 3000;
+    private TestDragDropController mTarget;
     private WindowState mWindow;
     private IBinder mToken;
 
+    static class TestDragDropController extends DragDropController {
+        @GuardedBy("sWm.mWindowMap")
+        private Runnable mCloseCallback;
+
+        TestDragDropController(WindowManagerService service, Looper looper) {
+            super(service, looper);
+        }
+
+        void setOnClosedCallbackLocked(Runnable runnable) {
+            assertTrue(dragDropActiveLocked());
+            mCloseCallback = runnable;
+        }
+
+        @Override
+        void onDragStateClosedLocked(DragState dragState) {
+            super.onDragStateClosedLocked(dragState);
+            if (mCloseCallback != null) {
+                mCloseCallback.run();
+                mCloseCallback = null;
+            }
+        }
+    }
+
+    /**
+     * Creates a window state which can be used as a drop target.
+     */
+    private WindowState createDropTargetWindow(String name, int ownerId) {
+        final WindowTestUtils.TestAppWindowToken token = new WindowTestUtils.TestAppWindowToken(
+                mDisplayContent);
+        final TaskStack stack = createStackControllerOnStackOnDisplay(
+                WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, mDisplayContent).mContainer;
+        final Task task = createTaskInStack(stack, ownerId);
+        task.addChild(token, 0);
+
+        final WindowState window = createWindow(
+                null, TYPE_BASE_APPLICATION, token, name, ownerId, false);
+        window.mInputChannel = new InputChannel();
+        window.mHasSurface = true;
+        return window;
+    }
+
     @Before
     public void setUp() throws Exception {
+        final UserManagerInternal userManager = mock(UserManagerInternal.class);
+        LocalServices.addService(UserManagerInternal.class, userManager);
+
         super.setUp();
-        assertNotNull(sWm.mDragDropController);
-        mTarget = sWm.mDragDropController;
-        mWindow = createWindow(null, TYPE_BASE_APPLICATION, "window");
+
+        mTarget = new TestDragDropController(sWm, sWm.mH.getLooper());
+        mDisplayContent = spy(mDisplayContent);
+        mWindow = createDropTargetWindow("Drag test window", 0);
+        when(mDisplayContent.getTouchableWinAtPointLocked(0, 0)).thenReturn(mWindow);
+        when(sWm.mInputManager.transferTouchFocus(any(), any())).thenReturn(true);
+
         synchronized (sWm.mWindowMap) {
-            // Because sWm is a static object, the previous operation may remain.
-            assertFalse(mTarget.dragDropActiveLocked());
+            sWm.mWindowMap.put(mWindow.mClient.asBinder(), mWindow);
         }
     }
 
     @After
-    public void tearDown() {
-        if (mToken != null) {
-            mTarget.cancelDragAndDrop(mToken);
+    public void tearDown() throws Exception {
+        LocalServices.removeServiceForTest(UserManagerInternal.class);
+        final CountDownLatch latch;
+        synchronized (sWm.mWindowMap) {
+            if (!mTarget.dragDropActiveLocked()) {
+                return;
+            }
+            if (mToken != null) {
+                mTarget.cancelDragAndDrop(mToken);
+            }
+            latch = new CountDownLatch(1);
+            mTarget.setOnClosedCallbackLocked(() -> {
+                latch.countDown();
+            });
         }
+        assertTrue(latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
     }
 
     @Test
-    public void testPrepareDrag() throws Exception {
-        final Surface surface = new Surface();
-        mToken = mTarget.prepareDrag(
-                new SurfaceSession(), 0, 0, mWindow.mClient, 0, 100, 100, surface);
-        assertNotNull(mToken);
+    public void testDragFlow() throws Exception {
+        dragFlow(0, ClipData.newPlainText("label", "Test"), 0, 0);
     }
 
     @Test
@@ -85,4 +152,33 @@
                 new SurfaceSession(), 0, 0, mWindow.mClient, 0, 0, 0, surface);
         assertNull(mToken);
     }
+
+    @Test
+    public void testPerformDrag_NullDataWithGrantUri() throws Exception {
+        dragFlow(View.DRAG_FLAG_GLOBAL | View.DRAG_FLAG_GLOBAL_URI_READ, null, 0, 0);
+    }
+
+    @Test
+    public void testPerformDrag_NullDataToOtherUser() throws Exception {
+        final WindowState otherUsersWindow =
+                createDropTargetWindow("Other user's window", 1 * UserHandle.PER_USER_RANGE);
+        when(mDisplayContent.getTouchableWinAtPointLocked(10, 10))
+                .thenReturn(otherUsersWindow);
+
+        dragFlow(0, null, 10, 10);
+    }
+
+    private void dragFlow(int flag, ClipData data, float dropX, float dropY) {
+        final Surface surface = new Surface();
+        mToken = mTarget.prepareDrag(
+                new SurfaceSession(), 0, 0, mWindow.mClient, flag, 100, 100, surface);
+        assertNotNull(mToken);
+
+        assertTrue(sWm.mInputManager.transferTouchFocus(null, null));
+        assertTrue(mTarget.performDrag(
+                mWindow.mClient, mToken, 0, 0, 0, 0, 0, data));
+
+        mTarget.handleMotionEvent(false, dropX, dropY);
+        mToken = mWindow.mClient.asBinder();
+    }
 }
diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java b/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java
index c699a94..69b1378 100644
--- a/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java
+++ b/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java
@@ -230,20 +230,22 @@
             boolean ownerCanAddInternalSystemWindow) {
         final WindowToken token = createWindowToken(
                 dc, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, type);
-        return createWindow(parent, type, token, name, ownerCanAddInternalSystemWindow);
+        return createWindow(parent, type, token, name, 0 /* ownerId */,
+                ownerCanAddInternalSystemWindow);
     }
 
     static WindowState createWindow(WindowState parent, int type, WindowToken token, String name) {
-        return createWindow(parent, type, token, name, false /* ownerCanAddInternalSystemWindow */);
+        return createWindow(parent, type, token, name, 0 /* ownerId */,
+                false /* ownerCanAddInternalSystemWindow */);
     }
 
     static WindowState createWindow(WindowState parent, int type, WindowToken token, String name,
-            boolean ownerCanAddInternalSystemWindow) {
+            int ownerId, boolean ownerCanAddInternalSystemWindow) {
         final WindowManager.LayoutParams attrs = new WindowManager.LayoutParams(type);
         attrs.setTitle(name);
 
         final WindowState w = new WindowState(sWm, sMockSession, sIWindow, token, parent, OP_NONE,
-                0, attrs, VISIBLE, 0, ownerCanAddInternalSystemWindow);
+                0, attrs, VISIBLE, ownerId, ownerCanAddInternalSystemWindow);
         // TODO: Probably better to make this call in the WindowState ctor to avoid errors with
         // adding it to the token...
         token.addWindow(w);