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);