Merge "Integration into other unlock mechanisms"
diff --git a/cmds/am/src/com/android/commands/am/Am.java b/cmds/am/src/com/android/commands/am/Am.java
index 20ac8d8..5c9fd51 100644
--- a/cmds/am/src/com/android/commands/am/Am.java
+++ b/cmds/am/src/com/android/commands/am/Am.java
@@ -163,6 +163,7 @@
" am task drag-task-test <TASK_ID> <STEP_SIZE> [DELAY_MS] \n" +
" am task size-task-test <TASK_ID> <STEP_SIZE> [DELAY_MS] \n" +
" am get-config\n" +
+ " am suppress-resize-config-changes <true|false>\n" +
" am set-inactive [--user <USER_ID>] <PACKAGE> true|false\n" +
" am get-inactive [--user <USER_ID>] <PACKAGE>\n" +
" am send-trim-memory [--user <USER_ID>] <PROCESS>\n" +
@@ -326,6 +327,8 @@
"\n" +
"am get-config: retrieve the configuration and any recent configurations\n" +
" of the device.\n" +
+ "am suppress-resize-config-changes: suppresses configuration changes due to\n" +
+ " user resizing an activity/task.\n" +
"\n" +
"am set-inactive: sets the inactive state of an app.\n" +
"\n" +
@@ -453,6 +456,8 @@
runTask();
} else if (op.equals("get-config")) {
runGetConfig();
+ } else if (op.equals("suppress-resize-config-changes")) {
+ runSuppressResizeConfigChanges();
} else if (op.equals("set-inactive")) {
runSetInactive();
} else if (op.equals("get-inactive")) {
@@ -2606,6 +2611,16 @@
}
}
+ private void runSuppressResizeConfigChanges() throws Exception {
+ boolean suppress = Boolean.valueOf(nextArgRequired());
+
+ try {
+ mAm.suppressResizeConfigChanges(suppress);
+ } catch (RemoteException e) {
+ System.err.println("Error suppressing resize config changes: " + e);
+ }
+ }
+
private void runSetInactive() throws Exception {
int userId = UserHandle.USER_CURRENT;
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index 3864a4b..cb1a89f 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -2682,6 +2682,13 @@
reportSizeConfigurations(token, horizontal, vertical);
return true;
}
+ case SUPPRESS_RESIZE_CONFIG_CHANGES_TRANSACTION: {
+ data.enforceInterface(IActivityManager.descriptor);
+ final boolean suppress = data.readInt() == 1;
+ suppressResizeConfigChanges(suppress);
+ reply.writeNoException();
+ return true;
+ }
}
return super.onTransact(code, data, reply, flags);
@@ -6216,5 +6223,17 @@
reply.recycle();
}
+ @Override
+ public void suppressResizeConfigChanges(boolean suppress) throws RemoteException {
+ Parcel data = Parcel.obtain();
+ Parcel reply = Parcel.obtain();
+ data.writeInterfaceToken(IActivityManager.descriptor);
+ data.writeInt(suppress ? 1 : 0);
+ mRemote.transact(SUPPRESS_RESIZE_CONFIG_CHANGES_TRANSACTION, data, reply, 0);
+ reply.readException();
+ data.recycle();
+ reply.recycle();
+ }
+
private IBinder mRemote;
}
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index 2180bcc..478fdd1 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -535,6 +535,8 @@
public int getActivityStackId(IBinder token) throws RemoteException;
public void moveActivityToStack(IBinder token, int stackId) throws RemoteException;
+ public void suppressResizeConfigChanges(boolean suppress) throws RemoteException;
+
/*
* Private non-Binder interfaces
*/
@@ -891,4 +893,5 @@
int MOVE_ACTIVITY_TO_STACK_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 344;
int REPORT_SIZE_CONFIGURATIONS = IBinder.FIRST_CALL_TRANSACTION + 345;
int MOVE_TASK_TO_DOCKED_STACK_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 346;
+ int SUPPRESS_RESIZE_CONFIG_CHANGES_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 347;
}
diff --git a/core/java/android/app/StatusBarManager.java b/core/java/android/app/StatusBarManager.java
index 31d1ab7..5e8ad68 100644
--- a/core/java/android/app/StatusBarManager.java
+++ b/core/java/android/app/StatusBarManager.java
@@ -90,6 +90,9 @@
public static final int WINDOW_STATE_HIDING = 1;
public static final int WINDOW_STATE_HIDDEN = 2;
+ public static final int CAMERA_LAUNCH_SOURCE_WIGGLE = 0;
+ public static final int CAMERA_LAUNCH_SOURCE_POWER_DOUBLE_TAP = 1;
+
private Context mContext;
private IStatusBarService mService;
private IBinder mToken = new Binder();
diff --git a/core/java/android/view/BatchedInputEventReceiver.java b/core/java/android/view/BatchedInputEventReceiver.java
new file mode 100644
index 0000000..b1d28e0
--- /dev/null
+++ b/core/java/android/view/BatchedInputEventReceiver.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2015 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.view;
+
+import android.os.Looper;
+
+/**
+ * Similar to {@link InputEventReceiver}, but batches events to vsync boundaries when possible.
+ * @hide
+ */
+public class BatchedInputEventReceiver extends InputEventReceiver {
+ Choreographer mChoreographer;
+ private boolean mBatchedInputScheduled;
+
+ public BatchedInputEventReceiver(
+ InputChannel inputChannel, Looper looper, Choreographer choreographer) {
+ super(inputChannel, looper);
+ mChoreographer = choreographer;
+ }
+
+ @Override
+ public void onBatchedInputEventPending() {
+ scheduleBatchedInput();
+ }
+
+ @Override
+ public void dispose() {
+ unscheduleBatchedInput();
+ super.dispose();
+ }
+
+ void doConsumeBatchedInput(long frameTimeNanos) {
+ if (mBatchedInputScheduled) {
+ mBatchedInputScheduled = false;
+ if (consumeBatchedInputEvents(frameTimeNanos) && frameTimeNanos != -1) {
+ // If we consumed a batch here, we want to go ahead and schedule the
+ // consumption of batched input events on the next frame. Otherwise, we would
+ // wait until we have more input events pending and might get starved by other
+ // things occurring in the process. If the frame time is -1, however, then
+ // we're in a non-batching mode, so there's no need to schedule this.
+ scheduleBatchedInput();
+ }
+ }
+ }
+
+ private void scheduleBatchedInput() {
+ if (!mBatchedInputScheduled) {
+ mBatchedInputScheduled = true;
+ mChoreographer.postCallback(Choreographer.CALLBACK_INPUT, mBatchedInputRunnable, null);
+ }
+ }
+
+ private void unscheduleBatchedInput() {
+ if (mBatchedInputScheduled) {
+ mBatchedInputScheduled = false;
+ mChoreographer.removeCallbacks(
+ Choreographer.CALLBACK_INPUT, mBatchedInputRunnable, null);
+ }
+ }
+
+ private final class BatchedInputRunnable implements Runnable {
+ @Override
+ public void run() {
+ doConsumeBatchedInput(mChoreographer.getFrameTimeNanos());
+ }
+ }
+ private final BatchedInputRunnable mBatchedInputRunnable = new BatchedInputRunnable();
+}
diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java
index 7ca3339..ca1b211 100644
--- a/core/java/android/widget/RemoteViews.java
+++ b/core/java/android/widget/RemoteViews.java
@@ -31,6 +31,7 @@
import android.content.res.ColorStateList;
import android.content.res.Configuration;
import android.content.res.Resources;
+import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.PorterDuff;
import android.graphics.Rect;
@@ -55,6 +56,8 @@
import android.widget.AdapterView.OnItemClickListener;
import libcore.util.Objects;
+import com.android.internal.R;
+
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -206,14 +209,22 @@
/** @hide */
public static class OnClickHandler {
+
+ private int mEnterAnimationId;
+
public boolean onClickHandler(View view, PendingIntent pendingIntent,
Intent fillInIntent) {
try {
// TODO: Unregister this handler if PendingIntent.FLAG_ONE_SHOT?
Context context = view.getContext();
- ActivityOptions opts = ActivityOptions.makeScaleUpAnimation(view,
- 0, 0,
- view.getMeasuredWidth(), view.getMeasuredHeight());
+ ActivityOptions opts;
+ if (mEnterAnimationId != 0) {
+ opts = ActivityOptions.makeCustomAnimation(context, mEnterAnimationId, 0);
+ } else {
+ opts = ActivityOptions.makeScaleUpAnimation(view,
+ 0, 0,
+ view.getMeasuredWidth(), view.getMeasuredHeight());
+ }
context.startIntentSender(
pendingIntent.getIntentSender(), fillInIntent,
Intent.FLAG_ACTIVITY_NEW_TASK,
@@ -228,6 +239,10 @@
}
return true;
}
+
+ public void setEnterAnimationId(int enterAnimationId) {
+ mEnterAnimationId = enterAnimationId;
+ }
}
/**
@@ -2761,11 +2776,31 @@
inflater.setFilter(this);
result = inflater.inflate(rvToApply.getLayoutId(), parent, false);
+ loadTransitionOverride(context, handler);
+
rvToApply.performApply(result, parent, handler);
return result;
}
+ private static void loadTransitionOverride(Context context,
+ RemoteViews.OnClickHandler handler) {
+ if (handler != null && context.getResources().getBoolean(
+ com.android.internal.R.bool.config_overrideRemoteViewsActivityTransition)) {
+ TypedArray windowStyle = context.getTheme().obtainStyledAttributes(
+ com.android.internal.R.styleable.Window);
+ int windowAnimations = windowStyle.getResourceId(
+ com.android.internal.R.styleable.Window_windowAnimationStyle, 0);
+ TypedArray windowAnimationStyle = context.obtainStyledAttributes(
+ windowAnimations, com.android.internal.R.styleable.WindowAnimation);
+ handler.setEnterAnimationId(windowAnimationStyle.getResourceId(
+ com.android.internal.R.styleable.
+ WindowAnimation_activityOpenRemoteViewsEnterAnimation, 0));
+ windowStyle.recycle();
+ windowAnimationStyle.recycle();
+ }
+ }
+
/**
* Applies all of the actions to the provided view.
*
diff --git a/core/java/com/android/internal/policy/PhoneWindow.java b/core/java/com/android/internal/policy/PhoneWindow.java
index ec41447..3353d16 100644
--- a/core/java/com/android/internal/policy/PhoneWindow.java
+++ b/core/java/com/android/internal/policy/PhoneWindow.java
@@ -2292,7 +2292,7 @@
}
}
- private static final class DecorView extends FrameLayout implements RootViewSurfaceTaker {
+ private final class DecorView extends FrameLayout implements RootViewSurfaceTaker {
/* package */int mDefaultOpacity = PixelFormat.OPAQUE;
@@ -2362,8 +2362,6 @@
private int mRootScrollY = 0;
- private PhoneWindow mWindow;
-
public DecorView(Context context, int featureId) {
super(context);
mFeatureId = featureId;
@@ -2385,7 +2383,7 @@
@Override
public void onDraw(Canvas c) {
super.onDraw(c);
- mBackgroundFallback.draw(mWindow.mContentRoot, c, mWindow.mContentParent);
+ mBackgroundFallback.draw(mContentRoot, c, mContentParent);
}
@Override
@@ -2397,7 +2395,7 @@
if (isDown && (event.getRepeatCount() == 0)) {
// First handle chording of panel key: if a panel key is held
// but not released, try to execute a shortcut in it.
- if ((mWindow.mPanelChordingKey > 0) && (mWindow.mPanelChordingKey != keyCode)) {
+ if ((mPanelChordingKey > 0) && (mPanelChordingKey != keyCode)) {
boolean handled = dispatchKeyShortcutEvent(event);
if (handled) {
return true;
@@ -2406,15 +2404,15 @@
// If a panel is open, perform a shortcut on it without the
// chorded panel key
- if ((mWindow.mPreparedPanel != null) && mWindow.mPreparedPanel.isOpen) {
- if (mWindow.performPanelShortcut(mWindow.mPreparedPanel, keyCode, event, 0)) {
+ if ((mPreparedPanel != null) && mPreparedPanel.isOpen) {
+ if (performPanelShortcut(mPreparedPanel, keyCode, event, 0)) {
return true;
}
}
}
- if (!mWindow.isDestroyed()) {
- final Callback cb = mWindow.getCallback();
+ if (!isDestroyed()) {
+ final Callback cb = getCallback();
final boolean handled = cb != null && mFeatureId < 0 ? cb.dispatchKeyEvent(event)
: super.dispatchKeyEvent(event);
if (handled) {
@@ -2422,28 +2420,28 @@
}
}
- return isDown ? mWindow.onKeyDown(mFeatureId, event.getKeyCode(), event)
- : mWindow.onKeyUp(mFeatureId, event.getKeyCode(), event);
+ return isDown ? PhoneWindow.this.onKeyDown(mFeatureId, event.getKeyCode(), event)
+ : PhoneWindow.this.onKeyUp(mFeatureId, event.getKeyCode(), event);
}
@Override
public boolean dispatchKeyShortcutEvent(KeyEvent ev) {
// If the panel is already prepared, then perform the shortcut using it.
boolean handled;
- if (mWindow.mPreparedPanel != null) {
- handled = mWindow.performPanelShortcut(mWindow.mPreparedPanel, ev.getKeyCode(), ev,
+ if (mPreparedPanel != null) {
+ handled = performPanelShortcut(mPreparedPanel, ev.getKeyCode(), ev,
Menu.FLAG_PERFORM_NO_CLOSE);
if (handled) {
- if (mWindow.mPreparedPanel != null) {
- mWindow.mPreparedPanel.isHandled = true;
+ if (mPreparedPanel != null) {
+ mPreparedPanel.isHandled = true;
}
return true;
}
}
// Shortcut not handled by the panel. Dispatch to the view hierarchy.
- final Callback cb = mWindow.getCallback();
- handled = cb != null && !mWindow.isDestroyed() && mFeatureId < 0
+ final Callback cb = getCallback();
+ handled = cb != null && !isDestroyed() && mFeatureId < 0
? cb.dispatchKeyShortcutEvent(ev) : super.dispatchKeyShortcutEvent(ev);
if (handled) {
return true;
@@ -2453,10 +2451,10 @@
// combination such as Control+C. Temporarily prepare the panel then mark it
// unprepared again when finished to ensure that the panel will again be prepared
// the next time it is shown for real.
- PanelFeatureState st = mWindow.getPanelState(FEATURE_OPTIONS_PANEL, false);
- if (st != null && mWindow.mPreparedPanel == null) {
- mWindow.preparePanel(st, ev);
- handled = mWindow.performPanelShortcut(st, ev.getKeyCode(), ev,
+ PanelFeatureState st = getPanelState(FEATURE_OPTIONS_PANEL, false);
+ if (st != null && mPreparedPanel == null) {
+ preparePanel(st, ev);
+ handled = performPanelShortcut(st, ev.getKeyCode(), ev,
Menu.FLAG_PERFORM_NO_CLOSE);
st.isPrepared = false;
if (handled) {
@@ -2468,23 +2466,23 @@
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
- final Callback cb = mWindow.getCallback();
- return cb != null && !mWindow.isDestroyed() && mFeatureId < 0
- ? cb.dispatchTouchEvent(ev) : super.dispatchTouchEvent(ev);
+ final Callback cb = getCallback();
+ return cb != null && !isDestroyed() && mFeatureId < 0 ? cb.dispatchTouchEvent(ev)
+ : super.dispatchTouchEvent(ev);
}
@Override
public boolean dispatchTrackballEvent(MotionEvent ev) {
- final Callback cb = mWindow.getCallback();
- return cb != null && !mWindow.isDestroyed() && mFeatureId < 0
- ? cb.dispatchTrackballEvent(ev) : super.dispatchTrackballEvent(ev);
+ final Callback cb = getCallback();
+ return cb != null && !isDestroyed() && mFeatureId < 0 ? cb.dispatchTrackballEvent(ev)
+ : super.dispatchTrackballEvent(ev);
}
@Override
public boolean dispatchGenericMotionEvent(MotionEvent ev) {
- final Callback cb = mWindow.getCallback();
- return cb != null && !mWindow.isDestroyed() && mFeatureId < 0
- ? cb.dispatchGenericMotionEvent(ev) : super.dispatchGenericMotionEvent(ev);
+ final Callback cb = getCallback();
+ return cb != null && !isDestroyed() && mFeatureId < 0 ? cb.dispatchGenericMotionEvent(ev)
+ : super.dispatchGenericMotionEvent(ev);
}
public boolean superDispatchKeyEvent(KeyEvent event) {
@@ -2536,7 +2534,7 @@
@Override
public boolean onInterceptTouchEvent(MotionEvent event) {
int action = event.getAction();
- if (mHasNonClientDecor && mWindow.mNonClientDecorView.mVisible) {
+ if (mHasNonClientDecor && mNonClientDecorView.mVisible) {
// Don't dispatch ACTION_DOWN to the non client decor if the window is
// resizable and the event was (starting) outside the window.
// Window resizing events should be handled by WindowManager.
@@ -2559,7 +2557,7 @@
int x = (int)event.getX();
int y = (int)event.getY();
if (isOutOfBounds(x, y)) {
- mWindow.closePanel(mFeatureId);
+ closePanel(mFeatureId);
return true;
}
}
@@ -2585,7 +2583,7 @@
if (action == MotionEvent.ACTION_MOVE) {
if (y > (mDownY+30)) {
Log.i(TAG, "Closing!");
- mWindow.closePanel(mFeatureId);
+ closePanel(mFeatureId);
mWatchingForMenu = false;
return true;
}
@@ -2601,7 +2599,7 @@
if (action == MotionEvent.ACTION_DOWN) {
int y = (int)event.getY();
- if (y >= (getHeight()-5) && !mWindow.hasChildren()) {
+ if (y >= (getHeight()-5) && !hasChildren()) {
Log.i(TAG, "Watchiing!");
mWatchingForMenu = true;
}
@@ -2616,7 +2614,7 @@
if (action == MotionEvent.ACTION_MOVE) {
if (y < (getHeight()-30)) {
Log.i(TAG, "Opening!");
- mWindow.openPanel(FEATURE_OPTIONS_PANEL, new KeyEvent(
+ openPanel(FEATURE_OPTIONS_PANEL, new KeyEvent(
KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_MENU));
mWatchingForMenu = false;
return true;
@@ -2650,8 +2648,8 @@
@Override
public boolean dispatchPopulateAccessibilityEventInternal(AccessibilityEvent event) {
- final Callback cb = mWindow.getCallback();
- if (cb != null && !mWindow.isDestroyed()) {
+ final Callback cb = getCallback();
+ if (cb != null && !isDestroyed()) {
if (cb.dispatchPopulateAccessibilityEvent(event)) {
return true;
}
@@ -2688,7 +2686,7 @@
if (SWEEP_OPEN_MENU) {
if (mMenuBackground == null && mFeatureId < 0
- && mWindow.getAttributes().height
+ && getAttributes().height
== WindowManager.LayoutParams.MATCH_PARENT) {
mMenuBackground = getContext().getDrawable(
R.drawable.menu_background);
@@ -2713,8 +2711,7 @@
boolean fixedWidth = false;
if (widthMode == AT_MOST) {
- final TypedValue tvw = isPortrait ? mWindow.mFixedWidthMinor
- : mWindow.mFixedWidthMajor;
+ final TypedValue tvw = isPortrait ? mFixedWidthMinor : mFixedWidthMajor;
if (tvw != null && tvw.type != TypedValue.TYPE_NULL) {
final int w;
if (tvw.type == TypedValue.TYPE_DIMENSION) {
@@ -2735,8 +2732,7 @@
}
if (heightMode == AT_MOST) {
- final TypedValue tvh = isPortrait ? mWindow.mFixedHeightMajor
- : mWindow.mFixedHeightMinor;
+ final TypedValue tvh = isPortrait ? mFixedHeightMajor : mFixedHeightMinor;
if (tvh != null && tvh.type != TypedValue.TYPE_NULL) {
final int h;
if (tvh.type == TypedValue.TYPE_DIMENSION) {
@@ -2754,21 +2750,21 @@
}
}
- getOutsets(mWindow.mOutsets);
- if (mWindow.mOutsets.top > 0 || mWindow.mOutsets.bottom > 0) {
+ getOutsets(mOutsets);
+ if (mOutsets.top > 0 || mOutsets.bottom > 0) {
int mode = MeasureSpec.getMode(heightMeasureSpec);
if (mode != MeasureSpec.UNSPECIFIED) {
int height = MeasureSpec.getSize(heightMeasureSpec);
heightMeasureSpec = MeasureSpec.makeMeasureSpec(
- height + mWindow.mOutsets.top + mWindow.mOutsets.bottom, mode);
+ height + mOutsets.top + mOutsets.bottom, mode);
}
}
- if (mWindow.mOutsets.left > 0 || mWindow.mOutsets.right > 0) {
+ if (mOutsets.left > 0 || mOutsets.right > 0) {
int mode = MeasureSpec.getMode(widthMeasureSpec);
if (mode != MeasureSpec.UNSPECIFIED) {
int width = MeasureSpec.getSize(widthMeasureSpec);
widthMeasureSpec = MeasureSpec.makeMeasureSpec(
- width + mWindow.mOutsets.left + mWindow.mOutsets.right, mode);
+ width + mOutsets.left + mOutsets.right, mode);
}
}
@@ -2780,7 +2776,7 @@
widthMeasureSpec = MeasureSpec.makeMeasureSpec(width, EXACTLY);
if (!fixedWidth && widthMode == AT_MOST) {
- final TypedValue tv = isPortrait ? mWindow.mMinWidthMinor : mWindow.mMinWidthMajor;
+ final TypedValue tv = isPortrait ? mMinWidthMinor : mMinWidthMajor;
if (tv.type != TypedValue.TYPE_NULL) {
final int min;
if (tv.type == TypedValue.TYPE_DIMENSION) {
@@ -2808,12 +2804,12 @@
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
- getOutsets(mWindow.mOutsets);
- if (mWindow.mOutsets.left > 0) {
- offsetLeftAndRight(-mWindow.mOutsets.left);
+ getOutsets(mOutsets);
+ if (mOutsets.left > 0) {
+ offsetLeftAndRight(-mOutsets.left);
}
- if (mWindow.mOutsets.top > 0) {
- offsetTopAndBottom(-mWindow.mOutsets.top);
+ if (mOutsets.top > 0) {
+ offsetTopAndBottom(-mOutsets.top);
}
}
@@ -2829,23 +2825,23 @@
@Override
public boolean showContextMenuForChild(View originalView) {
// Reuse the context menu builder
- if (mWindow.mContextMenu == null) {
- mWindow.mContextMenu = new ContextMenuBuilder(getContext());
- mWindow.mContextMenu.setCallback(mWindow.mContextMenuCallback);
+ if (mContextMenu == null) {
+ mContextMenu = new ContextMenuBuilder(getContext());
+ mContextMenu.setCallback(mContextMenuCallback);
} else {
- mWindow.mContextMenu.clearAll();
+ mContextMenu.clearAll();
}
- final MenuDialogHelper helper = mWindow.mContextMenu.show(originalView,
+ final MenuDialogHelper helper = mContextMenu.show(originalView,
originalView.getWindowToken());
if (helper != null) {
- helper.setPresenterCallback(mWindow.mContextMenuCallback);
- } else if (mWindow.mContextMenuHelper != null) {
+ helper.setPresenterCallback(mContextMenuCallback);
+ } else if (mContextMenuHelper != null) {
// No menu to show, but if we have a menu currently showing it just became blank.
// Close it.
- mWindow.mContextMenuHelper.dismiss();
+ mContextMenuHelper.dismiss();
}
- mWindow.mContextMenuHelper = helper;
+ mContextMenuHelper = helper;
return helper != null;
}
@@ -2875,15 +2871,14 @@
View originatingView, ActionMode.Callback callback, int type) {
ActionMode.Callback2 wrappedCallback = new ActionModeCallback2Wrapper(callback);
ActionMode mode = null;
- if (mWindow.getCallback() != null && !mWindow.isDestroyed()) {
+ if (getCallback() != null && !isDestroyed()) {
try {
- mode = mWindow.getCallback().onWindowStartingActionMode(wrappedCallback, type);
+ mode = getCallback().onWindowStartingActionMode(wrappedCallback, type);
} catch (AbstractMethodError ame) {
// Older apps might not implement the typed version of this method.
if (type == ActionMode.TYPE_PRIMARY) {
try {
- mode = mWindow.getCallback().onWindowStartingActionMode(
- wrappedCallback);
+ mode = getCallback().onWindowStartingActionMode(wrappedCallback);
} catch (AbstractMethodError ame2) {
// Older apps might not implement this callback method at all.
}
@@ -2908,9 +2903,9 @@
mode = null;
}
}
- if (mode != null && mWindow.getCallback() != null && !mWindow.isDestroyed()) {
+ if (mode != null && getCallback() != null && !isDestroyed()) {
try {
- mWindow.getCallback().onActionModeStarted(mode);
+ getCallback().onActionModeStarted(mode);
} catch (AbstractMethodError ame) {
// Older apps might not implement this callback method.
}
@@ -2999,10 +2994,10 @@
}
private WindowInsets updateColorViews(WindowInsets insets, boolean animate) {
- WindowManager.LayoutParams attrs = mWindow.getAttributes();
+ WindowManager.LayoutParams attrs = getAttributes();
int sysUiVisibility = attrs.systemUiVisibility | getWindowSystemUiVisibility();
- if (!mWindow.mIsFloating && ActivityManager.isHighEndGfx()) {
+ if (!mIsFloating && ActivityManager.isHighEndGfx()) {
boolean disallowAnimate = !isLaidOut();
disallowAnimate |= ((mLastWindowFlags ^ attrs.flags)
& FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) != 0;
@@ -3034,14 +3029,14 @@
boolean navBarToRightEdge = mLastBottomInset == 0 && mLastRightInset > 0;
int navBarSize = navBarToRightEdge ? mLastRightInset : mLastBottomInset;
- updateColorViewInt(mNavigationColorViewState, sysUiVisibility,
- mWindow.mNavigationBarColor, navBarSize, navBarToRightEdge,
- 0 /* rightInset */, animate && !disallowAnimate);
+ updateColorViewInt(mNavigationColorViewState, sysUiVisibility, mNavigationBarColor,
+ navBarSize, navBarToRightEdge, 0 /* rightInset */,
+ animate && !disallowAnimate);
boolean statusBarNeedsRightInset = navBarToRightEdge
&& mNavigationColorViewState.present;
int statusBarRightInset = statusBarNeedsRightInset ? mLastRightInset : 0;
- updateColorViewInt(mStatusColorViewState, sysUiVisibility, mWindow.mStatusBarColor,
+ updateColorViewInt(mStatusColorViewState, sysUiVisibility, mStatusBarColor,
mLastTopInset, false /* matchVertical */, statusBarRightInset,
animate && !disallowAnimate);
}
@@ -3058,13 +3053,13 @@
int consumedRight = consumingNavBar ? mLastRightInset : 0;
int consumedBottom = consumingNavBar ? mLastBottomInset : 0;
- if (mWindow.mContentRoot != null
- && mWindow.mContentRoot.getLayoutParams() instanceof MarginLayoutParams) {
- MarginLayoutParams lp = (MarginLayoutParams) mWindow.mContentRoot.getLayoutParams();
+ if (mContentRoot != null
+ && mContentRoot.getLayoutParams() instanceof MarginLayoutParams) {
+ MarginLayoutParams lp = (MarginLayoutParams) mContentRoot.getLayoutParams();
if (lp.rightMargin != consumedRight || lp.bottomMargin != consumedBottom) {
lp.rightMargin = consumedRight;
lp.bottomMargin = consumedBottom;
- mWindow.mContentRoot.setLayoutParams(lp);
+ mContentRoot.setLayoutParams(lp);
if (insets == null) {
// The insets have changed, but we're not currently in the process
@@ -3102,11 +3097,11 @@
private void updateColorViewInt(final ColorViewState state, int sysUiVis, int color,
int size, boolean verticalBar, int rightMargin, boolean animate) {
state.present = size > 0 && (sysUiVis & state.systemUiHideFlag) == 0
- && (mWindow.getAttributes().flags & state.hideWindowFlag) == 0
- && (mWindow.getAttributes().flags & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) != 0;
+ && (getAttributes().flags & state.hideWindowFlag) == 0
+ && (getAttributes().flags & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) != 0;
boolean show = state.present
&& (color & Color.BLACK) != 0
- && (mWindow.getAttributes().flags & state.translucentFlag) == 0;
+ && (getAttributes().flags & state.translucentFlag) == 0;
boolean visibilityChanged = false;
View view = state.view;
@@ -3198,14 +3193,14 @@
mPrimaryActionModeView.getLayoutParams();
boolean mlpChanged = false;
if (mPrimaryActionModeView.isShown()) {
- if (mWindow.mTempRect == null) {
- mWindow.mTempRect = new Rect();
+ if (mTempRect == null) {
+ mTempRect = new Rect();
}
- final Rect rect = mWindow.mTempRect;
+ final Rect rect = mTempRect;
// If the parent doesn't consume the insets, manually
// apply the default system window insets.
- mWindow.mContentParent.computeSystemWindowInsets(insets, rect);
+ mContentParent.computeSystemWindowInsets(insets, rect);
final int newMargin = rect.top == 0 ? insets.getSystemWindowInsetTop() : 0;
if (mlp.topMargin != newMargin) {
mlpChanged = true;
@@ -3236,7 +3231,7 @@
// mode is overlaid on the app content (e.g. it's
// sitting in a FrameLayout, see
// screen_simple_overlay_action_mode.xml).
- final boolean nonOverlay = (mWindow.getLocalFeatures()
+ final boolean nonOverlay = (getLocalFeatures()
& (1 << FEATURE_ACTION_MODE_OVERLAY)) == 0;
insets = insets.consumeSystemWindowInsets(
false, nonOverlay && showStatusGuard /* top */, false, false);
@@ -3260,14 +3255,14 @@
private void updateNavigationGuard(WindowInsets insets) {
// IMEs lay out below the nav bar, but the content view must not (for back compat)
- if (mWindow.getAttributes().type == WindowManager.LayoutParams.TYPE_INPUT_METHOD) {
+ if (getAttributes().type == WindowManager.LayoutParams.TYPE_INPUT_METHOD) {
// prevent the content view from including the nav bar height
- if (mWindow.mContentParent != null) {
- if (mWindow.mContentParent.getLayoutParams() instanceof MarginLayoutParams) {
+ if (mContentParent != null) {
+ if (mContentParent.getLayoutParams() instanceof MarginLayoutParams) {
MarginLayoutParams mlp =
- (MarginLayoutParams) mWindow.mContentParent.getLayoutParams();
+ (MarginLayoutParams) mContentParent.getLayoutParams();
mlp.bottomMargin = insets.getSystemWindowInsetBottom();
- mWindow.mContentParent.setLayoutParams(mlp);
+ mContentParent.setLayoutParams(mlp);
}
}
// position the navigation guard view, creating it if necessary
@@ -3349,7 +3344,7 @@
mDefaultOpacity = opacity;
if (mFeatureId < 0) {
- mWindow.setDefaultWindowFormat(opacity);
+ setDefaultWindowFormat(opacity);
}
}
@@ -3359,13 +3354,12 @@
// If the user is chording a menu shortcut, release the chord since
// this window lost focus
- if (mWindow.hasFeature(FEATURE_OPTIONS_PANEL) && !hasWindowFocus
- && mWindow.mPanelChordingKey != 0) {
- mWindow.closePanel(FEATURE_OPTIONS_PANEL);
+ if (hasFeature(FEATURE_OPTIONS_PANEL) && !hasWindowFocus && mPanelChordingKey != 0) {
+ closePanel(FEATURE_OPTIONS_PANEL);
}
- final Callback cb = mWindow.getCallback();
- if (cb != null && !mWindow.isDestroyed() && mFeatureId < 0) {
+ final Callback cb = getCallback();
+ if (cb != null && !isDestroyed() && mFeatureId < 0) {
cb.onWindowFocusChanged(hasWindowFocus);
}
@@ -3381,8 +3375,8 @@
protected void onAttachedToWindow() {
super.onAttachedToWindow();
- final Callback cb = mWindow.getCallback();
- if (cb != null && !mWindow.isDestroyed() && mFeatureId < 0) {
+ final Callback cb = getCallback();
+ if (cb != null && !isDestroyed() && mFeatureId < 0) {
cb.onAttachedToWindow();
}
@@ -3394,7 +3388,7 @@
* menu was open. When the activity is recreated, the menu
* should be shown again.
*/
- mWindow.openPanelsAfterRestore();
+ openPanelsAfterRestore();
}
}
@@ -3402,13 +3396,13 @@
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
- final Callback cb = mWindow.getCallback();
+ final Callback cb = getCallback();
if (cb != null && mFeatureId < 0) {
cb.onDetachedFromWindow();
}
- if (mWindow.mDecorContentParent != null) {
- mWindow.mDecorContentParent.dismissPopups();
+ if (mDecorContentParent != null) {
+ mDecorContentParent.dismissPopups();
}
if (mPrimaryActionModePopup != null) {
@@ -3423,7 +3417,7 @@
mFloatingToolbar = null;
}
- PanelFeatureState st = mWindow.getPanelState(FEATURE_OPTIONS_PANEL, false);
+ PanelFeatureState st = getPanelState(FEATURE_OPTIONS_PANEL, false);
if (st != null && st.menu != null && mFeatureId < 0) {
st.menu.close();
}
@@ -3432,29 +3426,29 @@
@Override
public void onCloseSystemDialogs(String reason) {
if (mFeatureId >= 0) {
- mWindow.closeAllPanels();
+ closeAllPanels();
}
}
public android.view.SurfaceHolder.Callback2 willYouTakeTheSurface() {
- return mFeatureId < 0 ? mWindow.mTakeSurfaceCallback : null;
+ return mFeatureId < 0 ? mTakeSurfaceCallback : null;
}
public InputQueue.Callback willYouTakeTheInputQueue() {
- return mFeatureId < 0 ? mWindow.mTakeInputQueueCallback : null;
+ return mFeatureId < 0 ? mTakeInputQueueCallback : null;
}
public void setSurfaceType(int type) {
- mWindow.setType(type);
+ PhoneWindow.this.setType(type);
}
public void setSurfaceFormat(int format) {
- mWindow.setFormat(format);
+ PhoneWindow.this.setFormat(format);
}
public void setSurfaceKeepScreenOn(boolean keepOn) {
- if (keepOn) mWindow.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
- else mWindow.clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
+ if (keepOn) PhoneWindow.this.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
+ else PhoneWindow.this.clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
}
@Override
@@ -3486,7 +3480,7 @@
endOnGoingFadeAnimation();
cleanupPrimaryActionMode();
if (mPrimaryActionModeView == null) {
- if (mWindow.isFloating()) {
+ if (isFloating()) {
// Use the action bar theme.
final TypedValue outValue = new TypedValue();
final Theme baseTheme = mContext.getTheme();
@@ -3633,7 +3627,7 @@
private void setHandledFloatingActionMode(ActionMode mode) {
mFloatingActionMode = mode;
- mFloatingToolbar = new FloatingToolbar(mContext, mWindow);
+ mFloatingToolbar = new FloatingToolbar(mContext, PhoneWindow.this);
((FloatingActionMode) mFloatingActionMode).setFloatingToolbar(mFloatingToolbar);
mFloatingActionMode.invalidate(); // Will show the floating toolbar if necessary.
mFloatingActionModeOriginatingView.getViewTreeObserver()
@@ -3672,10 +3666,6 @@
return windowHasNonClientDecor() && getElevation() > 0;
}
- void setWindow(PhoneWindow phoneWindow) {
- mWindow = phoneWindow;
- }
-
/**
* Clears out internal references when the action mode is destroyed.
*/
@@ -3764,9 +3754,9 @@
cleanupFloatingActionModeViews();
mFloatingActionMode = null;
}
- if (mWindow.getCallback() != null && !mWindow.isDestroyed()) {
+ if (getCallback() != null && !isDestroyed()) {
try {
- mWindow.getCallback().onActionModeFinished(mode);
+ getCallback().onActionModeFinished(mode);
} catch (AbstractMethodError ame) {
// Older apps might not implement this callback method.
}
@@ -3786,14 +3776,7 @@
}
protected DecorView generateDecor(int featureId) {
- // System process doesn't have application context and in that case we need to directly use
- // the context we have. Otherwise we want the application context, so we don't cling to the
- // activity.
- Context context = getContext().getApplicationContext();
- if (context == null) {
- context = getContext();
- }
- return new DecorView(context, featureId);
+ return new DecorView(getContext(), featureId);
}
protected void setFeatureFromAttrs(int featureId, TypedArray attrs,
@@ -4164,17 +4147,11 @@
if (nonClientDecorView == null) {
TypedValue value = new TypedValue();
getContext().getTheme().resolveAttribute(R.attr.colorPrimary, value, true);
- // We can't use the application context inside the general inflater, because some
- // views might depend on the fact that they get Activity or even specific activity.
- // We control the NonClientDecor, so we know that application context should be
- // safe enough.
- LayoutInflater inflater =
- mLayoutInflater.cloneInContext(getContext().getApplicationContext());
if (Color.luminance(value.data) < 0.5) {
- nonClientDecorView = (NonClientDecorView) inflater.inflate(
+ nonClientDecorView = (NonClientDecorView) mLayoutInflater.inflate(
R.layout.non_client_decor_dark, null);
} else {
- nonClientDecorView = (NonClientDecorView) inflater.inflate(
+ nonClientDecorView = (NonClientDecorView) mLayoutInflater.inflate(
R.layout.non_client_decor_light, null);
}
}
@@ -4196,14 +4173,12 @@
mForceDecorInstall = false;
if (mDecor == null) {
mDecor = generateDecor(-1);
- mDecor.setWindow(this);
mDecor.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);
mDecor.setIsRootNamespace(true);
if (!mInvalidatePanelMenuPosted && mInvalidatePanelMenuFeatures != 0) {
mDecor.postOnAnimation(mInvalidatePanelMenuRunnable);
}
}
- mDecor.setWindow(this);
if (mContentParent == null) {
mContentParent = generateLayout(mDecor);
diff --git a/core/java/com/android/internal/statusbar/IStatusBar.aidl b/core/java/com/android/internal/statusbar/IStatusBar.aidl
index ab3ec98..11ef18b 100644
--- a/core/java/com/android/internal/statusbar/IStatusBar.aidl
+++ b/core/java/com/android/internal/statusbar/IStatusBar.aidl
@@ -74,7 +74,9 @@
/**
* Notifies the status bar that a camera launch gesture has been detected.
+ *
+ * @param source the identifier for the gesture, see {@link StatusBarManager}
*/
- void onCameraLaunchGestureDetected();
+ void onCameraLaunchGestureDetected(int source);
}
diff --git a/core/res/res/values-watch/config.xml b/core/res/res/values-watch/config.xml
index 41b05ea..919519e 100644
--- a/core/res/res/values-watch/config.xml
+++ b/core/res/res/values-watch/config.xml
@@ -54,4 +54,7 @@
<!-- Do not show the message saying USB is connected in charging mode. -->
<bool name="config_usbChargingMessage">false</bool>
+
+ <!-- Use a custom transition for RemoteViews. -->
+ <bool name="config_overrideRemoteViewsActivityTransition">true</bool>
</resources>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index dc96df4..83d9a3c 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -2150,6 +2150,13 @@
(which is exiting the screen). The wallpaper remains
static behind the animation. -->
<attr name="wallpaperIntraCloseExitAnimation" format="reference" />
+
+ <!-- When opening a new activity from a RemoteViews, this is the
+ animation that is run on the next activity (which is entering the
+ screen). Requires config_overrideRemoteViewsActivityTransition to
+ be true. -->
+ <attr name="activityOpenRemoteViewsEnterAnimation" format="reference" />
+
</declare-styleable>
<!-- ============================= -->
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 9b1a613..24d760f 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -2214,6 +2214,10 @@
<bool name="config_defaultWindowFeatureOptionsPanel">true</bool>
<bool name="config_defaultWindowFeatureContextMenu">true</bool>
+ <!-- If true, the transition for a RemoteViews is read from a resource instead of using the
+ default scale-up transition. -->
+ <bool name="config_overrideRemoteViewsActivityTransition">false</bool>
+
<!-- This config is used to check if the carrier requires converting destination
number before sending out a SMS.
Formats for this configuration as below:
diff --git a/core/res/res/values/styles_micro.xml b/core/res/res/values/styles_micro.xml
index c6052ff..05835e7 100644
--- a/core/res/res/values/styles_micro.xml
+++ b/core/res/res/values/styles_micro.xml
@@ -18,6 +18,7 @@
<style name="Animation.Micro.Activity" parent="Animation.Material.Activity">
<item name="activityOpenEnterAnimation">@anim/slide_in_micro</item>
+ <item name="activityOpenRemoteViewsEnterAnimation">@anim/slide_in_micro</item>
<item name="activityOpenExitAnimation">@null</item>
<item name="activityCloseEnterAnimation">@null</item>
<item name="activityCloseExitAnimation">@anim/slide_out_micro</item>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index b5efbfd..028b95d 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -2191,6 +2191,7 @@
<java-symbol type="bool" name="config_sms_force_7bit_encoding" />
<java-symbol type="bool" name="config_defaultWindowFeatureOptionsPanel" />
<java-symbol type="bool" name="config_defaultWindowFeatureContextMenu" />
+ <java-symbol type="bool" name="config_overrideRemoteViewsActivityTransition" />
<java-symbol type="layout" name="simple_account_item" />
<java-symbol type="array" name="config_sms_convert_destination_number_support" />
diff --git a/core/tests/coretests/src/android/widget/TextViewActivityTest.java b/core/tests/coretests/src/android/widget/TextViewActivityTest.java
index b37688f..ce9ae02 100644
--- a/core/tests/coretests/src/android/widget/TextViewActivityTest.java
+++ b/core/tests/coretests/src/android/widget/TextViewActivityTest.java
@@ -17,6 +17,9 @@
package android.widget;
import static android.widget.espresso.TextViewActions.clickOnTextAtIndex;
+import static android.widget.espresso.TextViewActions.doubleTapAndDragOnText;
+import static android.widget.espresso.TextViewActions.longPressAndDragOnText;
+import static android.widget.espresso.TextViewAssertions.hasSelection;
import static android.support.test.espresso.Espresso.onView;
import static android.support.test.espresso.action.ViewActions.click;
import static android.support.test.espresso.action.ViewActions.pressKey;
@@ -63,4 +66,28 @@
onView(withId(R.id.textview)).perform(pressKey(KeyEvent.KEYCODE_FORWARD_DEL));
onView(withId(R.id.textview)).check(matches(withText("Hello orld!")));
}
+
+ @SmallTest
+ public void testLongPressAndDragToSelect() throws Exception {
+ getActivity();
+
+ final String helloWorld = "Hello little handsome boy!";
+ onView(withId(R.id.textview)).perform(typeTextIntoFocusedView(helloWorld));
+ onView(withId(R.id.textview)).perform(
+ longPressAndDragOnText(helloWorld.indexOf("little"), helloWorld.indexOf(" boy!")));
+
+ onView(withId(R.id.textview)).check(hasSelection("little handsome"));
+ }
+
+ @SmallTest
+ public void testDoubleTapAndDragToSelect() throws Exception {
+ getActivity();
+
+ final String helloWorld = "Hello young beautiful girl!";
+ onView(withId(R.id.textview)).perform(typeTextIntoFocusedView(helloWorld));
+ onView(withId(R.id.textview)).perform(
+ doubleTapAndDragOnText(helloWorld.indexOf("young"), helloWorld.indexOf(" girl!")));
+
+ onView(withId(R.id.textview)).check(hasSelection("young beautiful"));
+ }
}
diff --git a/core/tests/coretests/src/android/widget/espresso/DragOnTextViewActions.java b/core/tests/coretests/src/android/widget/espresso/DragOnTextViewActions.java
new file mode 100644
index 0000000..a0cd848
--- /dev/null
+++ b/core/tests/coretests/src/android/widget/espresso/DragOnTextViewActions.java
@@ -0,0 +1,281 @@
+/*
+ * Copyright (C) 2015 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.espresso;
+
+import static android.support.test.espresso.matcher.ViewMatchers.isAssignableFrom;
+import static android.support.test.espresso.matcher.ViewMatchers.isCompletelyDisplayed;
+import static com.android.internal.util.Preconditions.checkNotNull;
+import static org.hamcrest.Matchers.allOf;
+
+import android.annotation.Nullable;
+import android.os.SystemClock;
+import android.support.test.espresso.UiController;
+import android.support.test.espresso.PerformException;
+import android.support.test.espresso.ViewAction;
+import android.support.test.espresso.action.CoordinatesProvider;
+import android.support.test.espresso.action.GeneralClickAction;
+import android.support.test.espresso.action.MotionEvents;
+import android.support.test.espresso.action.PrecisionDescriber;
+import android.support.test.espresso.action.Press;
+import android.support.test.espresso.action.Swiper;
+import android.support.test.espresso.action.Tap;
+import android.support.test.espresso.util.HumanReadables;
+import android.util.Log;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewConfiguration;
+import android.widget.TextView;
+import org.hamcrest.Matcher;
+
+
+/**
+ * Drags on text in a TextView using touch events.<br>
+ * <br>
+ * View constraints:
+ * <ul>
+ * <li>must be a TextView displayed on screen
+ * <ul>
+ */
+public final class DragOnTextViewActions implements ViewAction {
+
+ /**
+ * Executes different "drag on text" types to given positions.
+ */
+ public enum Drag implements Swiper {
+
+ /**
+ * Starts a drag with a long-press.
+ */
+ LONG_PRESS {
+ private DownMotionPerformer downMotion = new DownMotionPerformer() {
+ @Override
+ public MotionEvent perform(
+ UiController uiController, float[] coordinates, float[] precision) {
+ MotionEvent downEvent = MotionEvents.sendDown(
+ uiController, coordinates, precision)
+ .down;
+ // Duration before a press turns into a long press.
+ // Factor 1.5 is needed, otherwise a long press is not safely detected.
+ // See android.test.TouchUtils longClickView
+ long longPressTimeout = (long) (ViewConfiguration.getLongPressTimeout() * 1.5f);
+ uiController.loopMainThreadForAtLeast(longPressTimeout);
+ return downEvent;
+ }
+ };
+
+ @Override
+ public Status sendSwipe(
+ UiController uiController,
+ float[] startCoordinates, float[] endCoordinates, float[] precision) {
+ return sendLinearDrag(
+ uiController, downMotion, startCoordinates, endCoordinates, precision);
+ }
+
+ @Override
+ public String toString() {
+ return "long press and drag to select";
+ }
+ },
+
+ /**
+ * Starts a drag with a double-tap.
+ */
+ DOUBLE_TAP {
+ private DownMotionPerformer downMotion = new DownMotionPerformer() {
+ @Override
+ @Nullable
+ public MotionEvent perform(
+ UiController uiController, float[] coordinates, float[] precision) {
+ MotionEvent downEvent = MotionEvents.sendDown(
+ uiController, coordinates, precision)
+ .down;
+ try {
+ if (!MotionEvents.sendUp(uiController, downEvent)) {
+ String logMessage = "Injection of up event as part of the double tap " +
+ "failed. Sending cancel event.";
+ Log.d(TAG, logMessage);
+ MotionEvents.sendCancel(uiController, downEvent);
+ return null;
+ }
+
+ long doubleTapMinimumTimeout = ViewConfiguration.getDoubleTapMinTime();
+ uiController.loopMainThreadForAtLeast(doubleTapMinimumTimeout);
+
+ return MotionEvents.sendDown(uiController, coordinates, precision).down;
+ } finally {
+ downEvent.recycle();
+ }
+ }
+ };
+
+ @Override
+ public Status sendSwipe(
+ UiController uiController,
+ float[] startCoordinates, float[] endCoordinates, float[] precision) {
+ return sendLinearDrag(
+ uiController, downMotion, startCoordinates, endCoordinates, precision);
+ }
+
+ @Override
+ public String toString() {
+ return "double-tap and drag to select";
+ }
+ };
+
+ private static final String TAG = Drag.class.getSimpleName();
+
+ /** The number of move events to send for each drag. */
+ private static final int DRAG_STEP_COUNT = 10;
+
+ /** Length of time a drag should last for, in milliseconds. */
+ private static final int DRAG_DURATION = 1500;
+
+ private static Status sendLinearDrag(
+ UiController uiController, DownMotionPerformer downMotion,
+ float[] startCoordinates, float[] endCoordinates, float[] precision) {
+ float[][] steps = interpolate(startCoordinates, endCoordinates);
+ final int delayBetweenMovements = DRAG_DURATION / steps.length;
+
+ MotionEvent downEvent = downMotion.perform(uiController, startCoordinates, precision);
+ if (downEvent == null) {
+ return Status.FAILURE;
+ }
+
+ try {
+ for (int i = 0; i < steps.length; i++) {
+ if (!MotionEvents.sendMovement(uiController, downEvent, steps[i])) {
+ String logMessage = "Injection of move event as part of the drag failed. " +
+ "Sending cancel event.";
+ Log.e(TAG, logMessage);
+ MotionEvents.sendCancel(uiController, downEvent);
+ return Status.FAILURE;
+ }
+
+ long desiredTime = downEvent.getDownTime() + delayBetweenMovements * i;
+ long timeUntilDesired = desiredTime - SystemClock.uptimeMillis();
+ if (timeUntilDesired > 10) {
+ // If the wait time until the next event isn't long enough, skip the wait
+ // and execute the next event.
+ uiController.loopMainThreadForAtLeast(timeUntilDesired);
+ }
+ }
+
+ if (!MotionEvents.sendUp(uiController, downEvent, endCoordinates)) {
+ String logMessage = "Injection of up event as part of the drag failed. " +
+ "Sending cancel event.";
+ Log.e(TAG, logMessage);
+ MotionEvents.sendCancel(uiController, downEvent);
+ return Status.FAILURE;
+ }
+ } finally {
+ downEvent.recycle();
+ }
+ return Status.SUCCESS;
+ }
+
+ private static float[][] interpolate(float[] start, float[] end) {
+ float[][] res = new float[DRAG_STEP_COUNT][2];
+
+ for (int i = 1; i < DRAG_STEP_COUNT + 1; i++) {
+ res[i - 1][0] = start[0] + (end[0] - start[0]) * i / (DRAG_STEP_COUNT + 2f);
+ res[i - 1][1] = start[1] + (end[1] - start[1]) * i / (DRAG_STEP_COUNT + 2f);
+ }
+
+ return res;
+ }
+ }
+
+ /**
+ * Interface to implement different "down motion" types.
+ */
+ private interface DownMotionPerformer {
+ /**
+ * Performs and returns a down motion.
+ *
+ * @param uiController a UiController to use to send MotionEvents to the screen.
+ * @param coordinates a float[] with x and y values of center of the tap.
+ * @param precision a float[] with x and y values of precision of the tap.
+ * @return the down motion event or null if the down motion event failed.
+ */
+ @Nullable
+ MotionEvent perform(UiController uiController, float[] coordinates, float[] precision);
+ }
+
+ private final Swiper mDragger;
+ private final CoordinatesProvider mStartCoordinatesProvider;
+ private final CoordinatesProvider mEndCoordinatesProvider;
+ private final PrecisionDescriber mPrecisionDescriber;
+
+ public DragOnTextViewActions(
+ Swiper dragger,
+ CoordinatesProvider startCoordinatesProvider,
+ CoordinatesProvider endCoordinatesProvider,
+ PrecisionDescriber precisionDescriber) {
+ mDragger = checkNotNull(dragger);
+ mStartCoordinatesProvider = checkNotNull(startCoordinatesProvider);
+ mEndCoordinatesProvider = checkNotNull(endCoordinatesProvider);
+ mPrecisionDescriber = checkNotNull(precisionDescriber);
+ }
+
+ @Override
+ @SuppressWarnings("unchecked")
+ public Matcher<View> getConstraints() {
+ return allOf(isCompletelyDisplayed(), isAssignableFrom(TextView.class));
+ }
+
+ @Override
+ public void perform(UiController uiController, View view) {
+ checkNotNull(uiController);
+ checkNotNull(view);
+
+ float[] startCoordinates = mStartCoordinatesProvider.calculateCoordinates(view);
+ float[] endCoordinates = mEndCoordinatesProvider.calculateCoordinates(view);
+ float[] precision = mPrecisionDescriber.describePrecision();
+
+ Swiper.Status status;
+
+ try {
+ status = mDragger.sendSwipe(
+ uiController, startCoordinates, endCoordinates, precision);
+ } catch (RuntimeException re) {
+ throw new PerformException.Builder()
+ .withActionDescription(this.getDescription())
+ .withViewDescription(HumanReadables.describe(view))
+ .withCause(re)
+ .build();
+ }
+
+ int duration = ViewConfiguration.getPressedStateDuration();
+ // ensures that all work enqueued to process the swipe has been run.
+ if (duration > 0) {
+ uiController.loopMainThreadForAtLeast(duration);
+ }
+
+ if (status == Swiper.Status.FAILURE) {
+ throw new PerformException.Builder()
+ .withActionDescription(getDescription())
+ .withViewDescription(HumanReadables.describe(view))
+ .withCause(new RuntimeException(getDescription() + " failed"))
+ .build();
+ }
+ }
+
+ @Override
+ public String getDescription() {
+ return mDragger.toString();
+ }
+}
diff --git a/core/tests/coretests/src/android/widget/espresso/TextViewActions.java b/core/tests/coretests/src/android/widget/espresso/TextViewActions.java
index 425dccd..7e4735b 100644
--- a/core/tests/coretests/src/android/widget/espresso/TextViewActions.java
+++ b/core/tests/coretests/src/android/widget/espresso/TextViewActions.java
@@ -18,7 +18,6 @@
import static android.support.test.espresso.action.ViewActions.actionWithAssertions;
-import android.content.res.Resources;
import android.support.test.espresso.PerformException;
import android.support.test.espresso.ViewAction;
import android.support.test.espresso.action.CoordinatesProvider;
@@ -27,8 +26,6 @@
import android.support.test.espresso.action.Tap;
import android.support.test.espresso.util.HumanReadables;
import android.text.Layout;
-import android.util.DisplayMetrics;
-import android.util.TypedValue;
import android.view.View;
import android.widget.TextView;
@@ -40,12 +37,14 @@
private TextViewActions() {}
/**
- * Returns an action that clicks on text at an index on the text view.<br>
+ * Returns an action that clicks on text at an index on the TextView.<br>
* <br>
* View constraints:
* <ul>
- * <li>must be a text view displayed on screen
+ * <li>must be a TextView displayed on screen
* <ul>
+ *
+ * @param index The index of the TextView's text to click on.
*/
public static ViewAction clickOnTextAtIndex(int index) {
return actionWithAssertions(
@@ -53,6 +52,48 @@
}
/**
+ * Returns an action that long presses then drags on text from startIndex to endIndex on the
+ * TextView.<br>
+ * <br>
+ * View constraints:
+ * <ul>
+ * <li>must be a TextView displayed on screen
+ * <ul>
+ *
+ * @param startIndex The index of the TextView's text to start a drag from
+ * @param endIndex The index of the TextView's text to end the drag at
+ */
+ public static ViewAction longPressAndDragOnText(int startIndex, int endIndex) {
+ return actionWithAssertions(
+ new DragOnTextViewActions(
+ DragOnTextViewActions.Drag.LONG_PRESS,
+ new TextCoordinates(startIndex),
+ new TextCoordinates(endIndex),
+ Press.FINGER));
+ }
+
+ /**
+ * Returns an action that double taps then drags on text from startIndex to endIndex on the
+ * TextView.<br>
+ * <br>
+ * View constraints:
+ * <ul>
+ * <li>must be a TextView displayed on screen
+ * <ul>
+ *
+ * @param startIndex The index of the TextView's text to start a drag from
+ * @param endIndex The index of the TextView's text to end the drag at
+ */
+ public static ViewAction doubleTapAndDragOnText(int startIndex, int endIndex) {
+ return actionWithAssertions(
+ new DragOnTextViewActions(
+ DragOnTextViewActions.Drag.DOUBLE_TAP,
+ new TextCoordinates(startIndex),
+ new TextCoordinates(endIndex),
+ Press.FINGER));
+ }
+
+ /**
* A provider of the x, y coordinates of the text at the specified index in a text view.
*/
private static final class TextCoordinates implements CoordinatesProvider {
diff --git a/core/tests/coretests/src/android/widget/espresso/TextViewAssertions.java b/core/tests/coretests/src/android/widget/espresso/TextViewAssertions.java
new file mode 100644
index 0000000..dce3182
--- /dev/null
+++ b/core/tests/coretests/src/android/widget/espresso/TextViewAssertions.java
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2015 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.espresso;
+
+import static android.support.test.espresso.matcher.ViewMatchers.assertThat;
+import static com.android.internal.util.Preconditions.checkNotNull;
+import static org.hamcrest.Matchers.is;
+
+import android.support.test.espresso.NoMatchingViewException;
+import android.support.test.espresso.ViewAssertion;
+import android.view.View;
+import android.widget.TextView;
+
+import junit.framework.AssertionFailedError;
+import org.hamcrest.Matcher;
+
+/**
+ * A collection of assertions on a {@link android.widget.TextView}.
+ */
+public final class TextViewAssertions {
+
+ private TextViewAssertions() {}
+
+ /**
+ * Returns a {@link ViewAssertion} that asserts that the text view has a specified
+ * selection.<br>
+ * <br>
+ * View constraints:
+ * <ul>
+ * <li>must be a text view displayed on screen
+ * <ul>
+ *
+ * @param selection The expected selection.
+ */
+ public static ViewAssertion hasSelection(String selection) {
+ return new TextSelectionAssertion(is(selection));
+ }
+
+ /**
+ * Returns a {@link ViewAssertion} that asserts that the text view has a specified
+ * selection.<br>
+ * <br>
+ * View constraints:
+ * <ul>
+ * <li>must be a text view displayed on screen
+ * <ul>
+ *
+ * @param selection A matcher representing the expected selection.
+ */
+ public static ViewAssertion hasSelection(Matcher<String> selection) {
+ return new TextSelectionAssertion(selection);
+ }
+
+ /**
+ * A {@link ViewAssertion} to check the selected text in a {@link TextView}.
+ */
+ private static final class TextSelectionAssertion implements ViewAssertion {
+
+ private final Matcher<String> mSelection;
+
+ public TextSelectionAssertion(Matcher<String> selection) {
+ mSelection = checkNotNull(selection);
+ }
+
+ @Override
+ public void check(View view, NoMatchingViewException exception) {
+ if (view instanceof TextView) {
+ TextView textView = (TextView) view;
+ int selectionStart = textView.getSelectionStart();
+ int selectionEnd = textView.getSelectionEnd();
+ try {
+ String selectedText = textView.getText()
+ .subSequence(selectionStart, selectionEnd)
+ .toString();
+ assertThat(selectedText, mSelection);
+ } catch (IndexOutOfBoundsException e) {
+ throw new AssertionFailedError(e.getMessage());
+ }
+ } else {
+ throw new AssertionFailedError("TextView not found");
+ }
+ }
+ }
+}
diff --git a/packages/DocumentsUI/res/layout/fragment_directory.xml b/packages/DocumentsUI/res/layout/fragment_directory.xml
index b02349a..45cb34d 100644
--- a/packages/DocumentsUI/res/layout/fragment_directory.xml
+++ b/packages/DocumentsUI/res/layout/fragment_directory.xml
@@ -17,61 +17,70 @@
<com.android.documentsui.DirectoryView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:background="@color/material_grey_50">
+ android:background="@color/material_grey_50"
+ android:orientation="vertical"
+ android:animateLayoutChanges="true">
- <TextView
- android:id="@android:id/empty"
+ <ProgressBar
+ android:id="@+id/progressbar"
android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:gravity="center"
- android:text="@string/empty"
- android:visibility="gone"
- style="@android:style/TextAppearance.Material.Subhead" />
+ android:layout_height="wrap_content"
+ android:indeterminate="true"
+ style="@style/TrimmedHorizontalProgressBar"
+ android:visibility="gone"/>
+
+ <FrameLayout
+ android:id="@+id/container_message_bar"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:elevation="8dp"
+ android:background="@color/material_grey_50"
+ android:visibility="gone"/>
+ <!-- The empty directory view -->
<LinearLayout
- android:id="@+id/content"
+ android:id="@android:id/empty"
+ android:gravity="center"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
- android:animateLayoutChanges="true">
-
- <ProgressBar
- android:id="@+id/progressbar"
- android:layout_width="match_parent"
+ android:visibility="gone">
+
+ <TextView
+ android:id="@+id/message"
+ android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:indeterminate="true"
- style="@style/TrimmedHorizontalProgressBar"
- android:visibility="gone"/>
+ android:text="@string/empty"
+ style="@android:style/TextAppearance.Material.Subhead" />
- <FrameLayout
- android:id="@+id/container_message_bar"
- android:layout_width="match_parent"
+ <Button
+ android:id="@+id/button_retry"
+ android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:elevation="8dp"
- android:background="@color/material_grey_50"
- android:visibility="gone"/>
-
- <!-- This FrameLayout works around b/24189541 -->
- <FrameLayout
- android:layout_width="match_parent"
- android:layout_height="match_parent">
-
- <android.support.v7.widget.RecyclerView
- android:id="@+id/recyclerView"
- android:scrollbars="vertical"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:paddingStart="@dimen/grid_padding_horiz"
- android:paddingEnd="@dimen/grid_padding_horiz"
- android:paddingTop="@dimen/grid_padding_vert"
- android:paddingBottom="@dimen/grid_padding_vert"
- android:clipToPadding="false"
- android:scrollbarStyle="outsideOverlay"
- android:drawSelectorOnTop="true"
- android:background="@color/directory_background" />
-
- </FrameLayout>
-
+ android:text="@string/button_retry"
+ style="?android:attr/buttonBarPositiveButtonStyle" />
+
</LinearLayout>
+
+ <!-- This FrameLayout works around b/24189541 -->
+ <FrameLayout
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <android.support.v7.widget.RecyclerView
+ android:id="@+id/recyclerView"
+ android:scrollbars="vertical"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:paddingStart="@dimen/grid_padding_horiz"
+ android:paddingEnd="@dimen/grid_padding_horiz"
+ android:paddingTop="@dimen/grid_padding_vert"
+ android:paddingBottom="@dimen/grid_padding_vert"
+ android:clipToPadding="false"
+ android:scrollbarStyle="outsideOverlay"
+ android:drawSelectorOnTop="true"
+ android:background="@color/directory_background" />
+
+ </FrameLayout>
</com.android.documentsui.DirectoryView>
diff --git a/packages/DocumentsUI/res/values/strings.xml b/packages/DocumentsUI/res/values/strings.xml
index 28018f8e..a12edf3 100644
--- a/packages/DocumentsUI/res/values/strings.xml
+++ b/packages/DocumentsUI/res/values/strings.xml
@@ -81,7 +81,8 @@
<string name="button_move">Move</string>
<!-- Button label that hides the error bar [CHAR LIMIT=24] -->
<string name="button_dismiss">Dismiss</string>
-
+ <string name="button_retry">Try Again</string>
+
<!-- Mode that sorts documents by their display name alphabetically [CHAR LIMIT=24] -->
<string name="sort_name">By name</string>
<!-- Mode that sorts documents by their last modified time in descending order; most recent first [CHAR LIMIT=24] -->
diff --git a/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java b/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java
index 1585908..c8ec4dc 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java
@@ -33,14 +33,11 @@
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
-import android.os.Parcel;
-import android.os.Parcelable;
import android.provider.DocumentsContract;
import android.provider.DocumentsContract.Root;
import android.support.annotation.LayoutRes;
import android.support.annotation.Nullable;
import android.util.Log;
-import android.util.SparseArray;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
@@ -67,7 +64,6 @@
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
-import java.util.HashMap;
import java.util.List;
import java.util.concurrent.Executor;
@@ -367,129 +363,6 @@
public static String EXTRA_DIRECTORY_COPY = "com.android.documentsui.DIRECTORY_COPY";
}
- public static class State implements android.os.Parcelable {
- public int action;
- public String[] acceptMimes;
-
- /** Explicit user choice */
- public int userMode = MODE_UNKNOWN;
- /** Derived after loader */
- public int derivedMode = MODE_LIST;
-
- /** Explicit user choice */
- public int userSortOrder = SORT_ORDER_UNKNOWN;
- /** Derived after loader */
- public int derivedSortOrder = SORT_ORDER_DISPLAY_NAME;
-
- public boolean allowMultiple;
- public boolean forceSize ;
- public boolean showSize;
- public boolean localOnly ;
- public boolean forceAdvanced ;
- public boolean showAdvanced ;
- public boolean stackTouched ;
- public boolean restored ;
- public boolean directoryCopy ;
- /** Transfer mode for file copy/move operations. */
- public int transferMode;
-
- /** Current user navigation stack; empty implies recents. */
- public DocumentStack stack = new DocumentStack();
- /** Currently active search, overriding any stack. */
- public String currentSearch;
-
- /** Instance state for every shown directory */
- public HashMap<String, SparseArray<Parcelable>> dirState = new HashMap<>();
-
- /** Currently copying file */
- public List<DocumentInfo> selectedDocumentsForCopy = new ArrayList<DocumentInfo>();
-
- /** Name of the package that started DocsUI */
- public List<String> excludedAuthorities = new ArrayList<>();
-
- public static final int ACTION_OPEN = 1;
- public static final int ACTION_CREATE = 2;
- public static final int ACTION_GET_CONTENT = 3;
- public static final int ACTION_OPEN_TREE = 4;
- public static final int ACTION_MANAGE = 5;
- public static final int ACTION_BROWSE = 6;
- public static final int ACTION_OPEN_COPY_DESTINATION = 8;
-
- public static final int MODE_UNKNOWN = 0;
- public static final int MODE_LIST = 1;
- public static final int MODE_GRID = 2;
-
- public static final int SORT_ORDER_UNKNOWN = 0;
- public static final int SORT_ORDER_DISPLAY_NAME = 1;
- public static final int SORT_ORDER_LAST_MODIFIED = 2;
- public static final int SORT_ORDER_SIZE = 3;
-
- public void initAcceptMimes(Intent intent) {
- if (intent.hasExtra(Intent.EXTRA_MIME_TYPES)) {
- acceptMimes = intent.getStringArrayExtra(Intent.EXTRA_MIME_TYPES);
- } else {
- String glob = intent.getType();
- acceptMimes = new String[] { glob != null ? glob : "*/*" };
- }
- }
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- @Override
- public void writeToParcel(Parcel out, int flags) {
- out.writeInt(action);
- out.writeInt(userMode);
- out.writeStringArray(acceptMimes);
- out.writeInt(userSortOrder);
- out.writeInt(allowMultiple ? 1 : 0);
- out.writeInt(forceSize ? 1 : 0);
- out.writeInt(showSize ? 1 : 0);
- out.writeInt(localOnly ? 1 : 0);
- out.writeInt(forceAdvanced ? 1 : 0);
- out.writeInt(showAdvanced ? 1 : 0);
- out.writeInt(stackTouched ? 1 : 0);
- out.writeInt(restored ? 1 : 0);
- DurableUtils.writeToParcel(out, stack);
- out.writeString(currentSearch);
- out.writeMap(dirState);
- out.writeList(selectedDocumentsForCopy);
- out.writeList(excludedAuthorities);
- }
-
- public static final Creator<State> CREATOR = new Creator<State>() {
- @Override
- public State createFromParcel(Parcel in) {
- final State state = new State();
- state.action = in.readInt();
- state.userMode = in.readInt();
- state.acceptMimes = in.readStringArray();
- state.userSortOrder = in.readInt();
- state.allowMultiple = in.readInt() != 0;
- state.forceSize = in.readInt() != 0;
- state.showSize = in.readInt() != 0;
- state.localOnly = in.readInt() != 0;
- state.forceAdvanced = in.readInt() != 0;
- state.showAdvanced = in.readInt() != 0;
- state.stackTouched = in.readInt() != 0;
- state.restored = in.readInt() != 0;
- DurableUtils.readFromParcel(in, state.stack);
- state.currentSearch = in.readString();
- in.readMap(state.dirState, null);
- in.readList(state.selectedDocumentsForCopy, null);
- in.readList(state.excludedAuthorities, null);
- return state;
- }
-
- @Override
- public State[] newArray(int size) {
- return new State[size];
- }
- };
- }
-
void setDisplayAdvancedDevices(boolean display) {
State state = getDisplayState();
LocalPreferences.setDisplayAdvancedDevices(this, display);
diff --git a/packages/DocumentsUI/src/com/android/documentsui/CopyService.java b/packages/DocumentsUI/src/com/android/documentsui/CopyService.java
index f8ec8f1..f1492dc7 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/CopyService.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/CopyService.java
@@ -16,6 +16,7 @@
package com.android.documentsui;
+import static com.android.documentsui.Shared.DEBUG;
import static com.android.documentsui.model.DocumentInfo.getCursorLong;
import static com.android.documentsui.model.DocumentInfo.getCursorString;
@@ -56,7 +57,6 @@
public class CopyService extends IntentService {
public static final String TAG = "CopyService";
- public static final boolean DEBUG = false;
private static final String EXTRA_CANCEL = "com.android.documentsui.CANCEL";
public static final String EXTRA_SRC_LIST = "com.android.documentsui.SRC_LIST";
diff --git a/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java b/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java
index ea8ecf5..5eacf21 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java
@@ -16,14 +16,15 @@
package com.android.documentsui;
-import static com.android.documentsui.BaseActivity.State.ACTION_BROWSE;
-import static com.android.documentsui.BaseActivity.State.ACTION_CREATE;
-import static com.android.documentsui.BaseActivity.State.ACTION_MANAGE;
-import static com.android.documentsui.BaseActivity.State.MODE_GRID;
-import static com.android.documentsui.BaseActivity.State.MODE_LIST;
-import static com.android.documentsui.BaseActivity.State.MODE_UNKNOWN;
-import static com.android.documentsui.BaseActivity.State.SORT_ORDER_UNKNOWN;
+import static com.android.documentsui.Shared.DEBUG;
import static com.android.documentsui.Shared.TAG;
+import static com.android.documentsui.State.ACTION_BROWSE;
+import static com.android.documentsui.State.ACTION_CREATE;
+import static com.android.documentsui.State.ACTION_MANAGE;
+import static com.android.documentsui.State.MODE_GRID;
+import static com.android.documentsui.State.MODE_LIST;
+import static com.android.documentsui.State.MODE_UNKNOWN;
+import static com.android.documentsui.State.SORT_ORDER_UNKNOWN;
import static com.android.documentsui.model.DocumentInfo.getCursorInt;
import static com.android.documentsui.model.DocumentInfo.getCursorLong;
import static com.android.documentsui.model.DocumentInfo.getCursorString;
@@ -93,7 +94,6 @@
import android.widget.Toast;
import com.android.documentsui.BaseActivity.DocumentContext;
-import com.android.documentsui.BaseActivity.State;
import com.android.documentsui.MultiSelectManager.Selection;
import com.android.documentsui.ProviderExecutor.Preemptable;
import com.android.documentsui.RecentsProvider.StateColumns;
@@ -124,7 +124,6 @@
public static final int REQUEST_COPY_DESTINATION = 1;
private static final int LOADER_ID = 42;
- private static final boolean DEBUG = false;
private static final boolean DEBUG_ENABLE_DND = false;
private static final String EXTRA_TYPE = "type";
@@ -367,21 +366,6 @@
@Override
public void onLoadFinished(Loader<DirectoryResult> loader, DirectoryResult result) {
- if (result == null || result.exception != null) {
- // onBackPressed does a fragment transaction, which can't be done inside
- // onLoadFinished
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- final Activity activity = getActivity();
- if (activity != null) {
- activity.onBackPressed();
- }
- }
- });
- return;
- }
-
if (!isAdded()) return;
mModel.update(result);
@@ -629,7 +613,6 @@
@Override
public void onItemStateChanged(int position, boolean selected) {
-
final Cursor cursor = mModel.getItem(position);
checkNotNull(cursor, "Cursor cannot be null.");
@@ -715,8 +698,9 @@
return true;
} else if (id == R.id.menu_delete) {
- deleteDocuments(selection);
+ // Exit selection mode first, so we avoid deselecting deleted documents.
mode.finish();
+ deleteDocuments(selection);
return true;
} else if (id == R.id.menu_copy_to) {
@@ -725,8 +709,9 @@
return true;
} else if (id == R.id.menu_move_to) {
- transferDocuments(selection, CopyService.TRANSFER_MODE_MOVE);
+ // Exit selection mode first, so we avoid deselecting deleted documents.
mode.finish();
+ transferDocuments(selection, CopyService.TRANSFER_MODE_MOVE);
return true;
} else if (id == R.id.menu_copy_to_clipboard) {
@@ -898,6 +883,29 @@
}
}
+ void showEmptyView() {
+ mEmptyView.setVisibility(View.VISIBLE);
+ mRecView.setVisibility(View.GONE);
+ TextView msg = (TextView) mEmptyView.findViewById(R.id.message);
+ msg.setText(R.string.empty);
+ // No retry button for the empty view.
+ mEmptyView.findViewById(R.id.button_retry).setVisibility(View.GONE);
+ }
+
+ void showErrorView() {
+ mEmptyView.setVisibility(View.VISIBLE);
+ mRecView.setVisibility(View.GONE);
+ TextView msg = (TextView) mEmptyView.findViewById(R.id.message);
+ msg.setText(R.string.query_error);
+ // TODO: Enable this once the retry button does something.
+ mEmptyView.findViewById(R.id.button_retry).setVisibility(View.GONE);
+ }
+
+ void showRecyclerView() {
+ mEmptyView.setVisibility(View.GONE);
+ mRecView.setVisibility(View.VISIBLE);
+ }
+
private final class DocumentsAdapter extends RecyclerView.Adapter<DocumentHolder> {
private final Context mContext;
@@ -1950,21 +1958,16 @@
mProgressBar.setVisibility(model.isLoading() ? View.VISIBLE : View.GONE);
if (model.isEmpty()) {
- mEmptyView.setVisibility(View.VISIBLE);
- mRecView.setVisibility(View.GONE);
+ showEmptyView();
} else {
- mEmptyView.setVisibility(View.GONE);
- mRecView.setVisibility(View.VISIBLE);
+ showRecyclerView();
+ mAdapter.notifyDataSetChanged();
}
-
- mAdapter.notifyDataSetChanged();
}
@Override
public void onModelUpdateFailed(Exception e) {
- // TODO: deal with catastrophic update failures
- String error = getString(R.string.query_error);
- mAdapter.notifyDataSetChanged();
+ showErrorView();
}
}
}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/DirectoryLoader.java b/packages/DocumentsUI/src/com/android/documentsui/DirectoryLoader.java
index 0edb241..bb82b38 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/DirectoryLoader.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/DirectoryLoader.java
@@ -16,12 +16,12 @@
package com.android.documentsui;
-import static com.android.documentsui.BaseActivity.State.MODE_UNKNOWN;
-import static com.android.documentsui.BaseActivity.State.SORT_ORDER_DISPLAY_NAME;
-import static com.android.documentsui.BaseActivity.State.SORT_ORDER_LAST_MODIFIED;
-import static com.android.documentsui.BaseActivity.State.SORT_ORDER_SIZE;
-import static com.android.documentsui.BaseActivity.State.SORT_ORDER_UNKNOWN;
import static com.android.documentsui.Shared.TAG;
+import static com.android.documentsui.State.MODE_UNKNOWN;
+import static com.android.documentsui.State.SORT_ORDER_DISPLAY_NAME;
+import static com.android.documentsui.State.SORT_ORDER_LAST_MODIFIED;
+import static com.android.documentsui.State.SORT_ORDER_SIZE;
+import static com.android.documentsui.State.SORT_ORDER_UNKNOWN;
import static com.android.documentsui.model.DocumentInfo.getCursorInt;
import android.content.AsyncTaskLoader;
@@ -37,7 +37,6 @@
import android.provider.DocumentsContract.Document;
import android.util.Log;
-import com.android.documentsui.BaseActivity.State;
import com.android.documentsui.RecentsProvider.StateColumns;
import com.android.documentsui.model.DocumentInfo;
import com.android.documentsui.model.RootInfo;
diff --git a/packages/DocumentsUI/src/com/android/documentsui/DirectoryView.java b/packages/DocumentsUI/src/com/android/documentsui/DirectoryView.java
index 4893652..000b92a 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/DirectoryView.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/DirectoryView.java
@@ -18,9 +18,9 @@
import android.content.Context;
import android.util.AttributeSet;
-import android.widget.FrameLayout;
+import android.widget.LinearLayout;
-public class DirectoryView extends FrameLayout {
+public class DirectoryView extends LinearLayout {
private float mPosition = 0f;
private int mWidth;
diff --git a/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java b/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java
index dbfcf40..4658fe3 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java
@@ -16,13 +16,12 @@
package com.android.documentsui;
-import static com.android.documentsui.BaseActivity.State.ACTION_CREATE;
-import static com.android.documentsui.BaseActivity.State.ACTION_GET_CONTENT;
-import static com.android.documentsui.BaseActivity.State.ACTION_OPEN;
-import static com.android.documentsui.BaseActivity.State.ACTION_OPEN_COPY_DESTINATION;
-import static com.android.documentsui.BaseActivity.State.ACTION_OPEN_TREE;
-import static com.android.documentsui.DirectoryFragment.ANIM_DOWN;
import static com.android.documentsui.DirectoryFragment.ANIM_NONE;
+import static com.android.documentsui.State.ACTION_CREATE;
+import static com.android.documentsui.State.ACTION_GET_CONTENT;
+import static com.android.documentsui.State.ACTION_OPEN;
+import static com.android.documentsui.State.ACTION_OPEN_COPY_DESTINATION;
+import static com.android.documentsui.State.ACTION_OPEN_TREE;
import android.app.Activity;
import android.app.Fragment;
diff --git a/packages/DocumentsUI/src/com/android/documentsui/IconUtils.java b/packages/DocumentsUI/src/com/android/documentsui/IconUtils.java
index ec1cb1d..a1213d2 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/IconUtils.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/IconUtils.java
@@ -222,7 +222,7 @@
return context.getDrawable(R.drawable.ic_doc_album);
}
- if (mode == BaseActivity.State.MODE_GRID) {
+ if (mode == State.MODE_GRID) {
return context.getDrawable(R.drawable.ic_grid_folder);
} else {
return context.getDrawable(R.drawable.ic_doc_folder);
diff --git a/packages/DocumentsUI/src/com/android/documentsui/ManageRootActivity.java b/packages/DocumentsUI/src/com/android/documentsui/ManageRootActivity.java
index f5b1d8e..4754899 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/ManageRootActivity.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/ManageRootActivity.java
@@ -16,9 +16,8 @@
package com.android.documentsui;
-import static com.android.documentsui.BaseActivity.State.ACTION_MANAGE;
-import static com.android.documentsui.DirectoryFragment.ANIM_DOWN;
import static com.android.documentsui.DirectoryFragment.ANIM_NONE;
+import static com.android.documentsui.State.ACTION_MANAGE;
import android.app.Activity;
import android.app.Fragment;
diff --git a/packages/DocumentsUI/src/com/android/documentsui/MultiSelectManager.java b/packages/DocumentsUI/src/com/android/documentsui/MultiSelectManager.java
index 5839943..858fb42 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/MultiSelectManager.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/MultiSelectManager.java
@@ -365,8 +365,8 @@
// To make this more correct, we'd need to update the Ranger class to return
// information about what has changed.
notifySelectionChanged();
- } else if (toggleSelection(input.getItemPosition())) {
- notifySelectionChanged();
+ } else {
+ toggleSelection(input.getItemPosition());
}
}
@@ -375,14 +375,13 @@
* a new Ranger (range selection manager) at that point is created.
*
* @param position
- * @return True if state changed.
*/
- private boolean toggleSelection(int position) {
+ private void toggleSelection(int position) {
// Position may be special "no position" during certain
// transitional phases. If so, skip handling of the event.
if (position == RecyclerView.NO_POSITION) {
if (DEBUG) Log.d(TAG, "Ignoring toggle for element with no position.");
- return false;
+ return;
}
boolean changed = false;
@@ -391,7 +390,7 @@
} else {
boolean canSelect = notifyBeforeItemStateChange(position, true);
if (!canSelect) {
- return false;
+ return;
}
if (mSingleSelect && !mSelection.isEmpty()) {
clearSelectionQuietly();
@@ -407,7 +406,9 @@
changed = true;
}
- return changed;
+ if (changed) {
+ notifySelectionChanged();
+ }
}
/**
diff --git a/packages/DocumentsUI/src/com/android/documentsui/PickFragment.java b/packages/DocumentsUI/src/com/android/documentsui/PickFragment.java
index 5f6a5e9..48e28dc 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/PickFragment.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/PickFragment.java
@@ -21,7 +21,6 @@
import android.app.FragmentManager;
import android.app.FragmentTransaction;
import android.os.Bundle;
-import android.text.TextUtils;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@@ -29,8 +28,6 @@
import com.android.documentsui.model.DocumentInfo;
-import java.util.Locale;
-
/**
* Display pick confirmation bar, usually for selecting a directory.
*/
@@ -93,7 +90,7 @@
};
/**
- * @param action Which action defined in BaseActivity.State is the picker shown for.
+ * @param action Which action defined in State is the picker shown for.
*/
public void setPickTarget(int action, int transferMode, DocumentInfo pickTarget) {
mAction = action;
@@ -109,11 +106,11 @@
*/
private void updateView() {
switch (mAction) {
- case BaseActivity.State.ACTION_OPEN_TREE:
+ case State.ACTION_OPEN_TREE:
mPick.setText(R.string.button_select);
mCancel.setVisibility(View.GONE);
break;
- case BaseActivity.State.ACTION_OPEN_COPY_DESTINATION:
+ case State.ACTION_OPEN_COPY_DESTINATION:
mPick.setText(R.string.button_copy);
mCancel.setVisibility(View.VISIBLE);
break;
@@ -123,7 +120,7 @@
}
if (mPickTarget != null && (
- mAction == BaseActivity.State.ACTION_OPEN_TREE ||
+ mAction == State.ACTION_OPEN_TREE ||
mPickTarget.isCreateSupported())) {
mContainer.setVisibility(View.VISIBLE);
} else {
diff --git a/packages/DocumentsUI/src/com/android/documentsui/QuickViewIntentBuilder.java b/packages/DocumentsUI/src/com/android/documentsui/QuickViewIntentBuilder.java
index 4685c41..607cb95 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/QuickViewIntentBuilder.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/QuickViewIntentBuilder.java
@@ -16,6 +16,8 @@
package com.android.documentsui;
+import static com.android.documentsui.Shared.DEBUG;
+import static com.android.documentsui.Shared.TAG;
import static com.android.documentsui.model.DocumentInfo.getCursorString;
import android.content.ClipData;
@@ -38,9 +40,6 @@
*/
final class QuickViewIntentBuilder {
- private static final String TAG = "QvIntentBuilder";
- private static final boolean DEBUG = false;
-
private final DocumentInfo mDocument;
private final DocumentContext mContext;
diff --git a/packages/DocumentsUI/src/com/android/documentsui/RecentLoader.java b/packages/DocumentsUI/src/com/android/documentsui/RecentLoader.java
index 1a7095a..c2b64fb 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/RecentLoader.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/RecentLoader.java
@@ -16,8 +16,9 @@
package com.android.documentsui;
-import static com.android.documentsui.BaseActivity.State.SORT_ORDER_LAST_MODIFIED;
+import static com.android.documentsui.Shared.DEBUG;
import static com.android.documentsui.Shared.TAG;
+import static com.android.documentsui.State.SORT_ORDER_LAST_MODIFIED;
import android.app.ActivityManager;
import android.content.AsyncTaskLoader;
@@ -34,7 +35,6 @@
import android.text.format.DateUtils;
import android.util.Log;
-import com.android.documentsui.BaseActivity.State;
import com.android.documentsui.model.RootInfo;
import com.google.common.util.concurrent.AbstractFuture;
@@ -53,8 +53,6 @@
import java.util.concurrent.TimeUnit;
public class RecentLoader extends AsyncTaskLoader<DirectoryResult> {
- private static final boolean DEBUG = false;
-
// TODO: clean up cursor ownership so background thread doesn't traverse
// previously returned cursors for filtering/sorting; this currently races
// with the UI thread.
diff --git a/packages/DocumentsUI/src/com/android/documentsui/RecentsCreateFragment.java b/packages/DocumentsUI/src/com/android/documentsui/RecentsCreateFragment.java
index 6811331..cf682fa 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/RecentsCreateFragment.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/RecentsCreateFragment.java
@@ -45,7 +45,6 @@
import android.widget.ImageView;
import android.widget.TextView;
-import com.android.documentsui.BaseActivity.State;
import com.android.documentsui.RecentsProvider.RecentColumns;
import com.android.documentsui.model.DocumentStack;
import com.android.documentsui.model.DurableUtils;
diff --git a/packages/DocumentsUI/src/com/android/documentsui/RecentsProvider.java b/packages/DocumentsUI/src/com/android/documentsui/RecentsProvider.java
index f6e4349..82eb732 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/RecentsProvider.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/RecentsProvider.java
@@ -39,6 +39,7 @@
import com.android.documentsui.model.DocumentStack;
import com.android.documentsui.model.DurableUtils;
import com.android.internal.util.Predicate;
+
import com.google.android.collect.Sets;
import libcore.io.IoUtils;
diff --git a/packages/DocumentsUI/src/com/android/documentsui/RootsCache.java b/packages/DocumentsUI/src/com/android/documentsui/RootsCache.java
index cb46bca..de35cef 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/RootsCache.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/RootsCache.java
@@ -16,8 +16,8 @@
package com.android.documentsui;
-import static com.android.documentsui.Shared.TAG;
import static com.android.documentsui.Shared.DEBUG;
+import static com.android.documentsui.Shared.TAG;
import android.content.ContentProviderClient;
import android.content.ContentResolver;
@@ -35,12 +35,11 @@
import android.os.SystemClock;
import android.provider.DocumentsContract;
import android.provider.DocumentsContract.Root;
+import android.support.annotation.VisibleForTesting;
import android.util.Log;
-import com.android.documentsui.BaseActivity.State;
import com.android.documentsui.model.RootInfo;
import com.android.internal.annotations.GuardedBy;
-import android.support.annotation.VisibleForTesting;
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.Multimap;
@@ -372,10 +371,8 @@
if (state.directoryCopy && root.isDownloads()) continue;
// Only show empty roots when creating, or in browse mode.
- if (empty && (state.action != State.ACTION_BROWSE ||
- state.action != State.ACTION_CREATE ||
- state.action != State.ACTION_OPEN_TREE ||
- state.action != State.ACTION_OPEN_COPY_DESTINATION)) {
+ if (empty && (state.action == State.ACTION_OPEN
+ || state.action == State.ACTION_GET_CONTENT)) {
if (DEBUG) Log.i(TAG, "Skipping empty root: " + root);
continue;
}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/RootsFragment.java b/packages/DocumentsUI/src/com/android/documentsui/RootsFragment.java
index c02184b..c98da47 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/RootsFragment.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/RootsFragment.java
@@ -41,7 +41,6 @@
import android.widget.ListView;
import android.widget.TextView;
-import com.android.documentsui.BaseActivity.State;
import com.android.documentsui.model.DocumentInfo;
import com.android.documentsui.model.RootInfo;
diff --git a/packages/DocumentsUI/src/com/android/documentsui/RootsLoader.java b/packages/DocumentsUI/src/com/android/documentsui/RootsLoader.java
index 49651b4..c81377a 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/RootsLoader.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/RootsLoader.java
@@ -19,7 +19,6 @@
import android.content.AsyncTaskLoader;
import android.content.Context;
-import com.android.documentsui.BaseActivity.State;
import com.android.documentsui.model.RootInfo;
import java.util.Collection;
diff --git a/packages/DocumentsUI/src/com/android/documentsui/SortingCursorWrapper.java b/packages/DocumentsUI/src/com/android/documentsui/SortingCursorWrapper.java
index 3ec3d1c..6698ff1 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/SortingCursorWrapper.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/SortingCursorWrapper.java
@@ -16,9 +16,9 @@
package com.android.documentsui;
-import static com.android.documentsui.BaseActivity.State.SORT_ORDER_DISPLAY_NAME;
-import static com.android.documentsui.BaseActivity.State.SORT_ORDER_LAST_MODIFIED;
-import static com.android.documentsui.BaseActivity.State.SORT_ORDER_SIZE;
+import static com.android.documentsui.State.SORT_ORDER_DISPLAY_NAME;
+import static com.android.documentsui.State.SORT_ORDER_LAST_MODIFIED;
+import static com.android.documentsui.State.SORT_ORDER_SIZE;
import static com.android.documentsui.model.DocumentInfo.getCursorLong;
import static com.android.documentsui.model.DocumentInfo.getCursorString;
diff --git a/packages/DocumentsUI/src/com/android/documentsui/State.java b/packages/DocumentsUI/src/com/android/documentsui/State.java
new file mode 100644
index 0000000..bbffad3
--- /dev/null
+++ b/packages/DocumentsUI/src/com/android/documentsui/State.java
@@ -0,0 +1,153 @@
+/*
+ * Copyright (C) 2013 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 com.android.documentsui;
+
+import android.content.Intent;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.util.SparseArray;
+
+import com.android.documentsui.model.DocumentInfo;
+import com.android.documentsui.model.DocumentStack;
+import com.android.documentsui.model.DurableUtils;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+
+public class State implements android.os.Parcelable {
+ public int action;
+ public String[] acceptMimes;
+
+ /** Explicit user choice */
+ public int userMode = MODE_UNKNOWN;
+ /** Derived after loader */
+ public int derivedMode = MODE_LIST;
+
+ /** Explicit user choice */
+ public int userSortOrder = SORT_ORDER_UNKNOWN;
+ /** Derived after loader */
+ public int derivedSortOrder = SORT_ORDER_DISPLAY_NAME;
+
+ public boolean allowMultiple;
+ public boolean forceSize ;
+ public boolean showSize;
+ public boolean localOnly ;
+ public boolean forceAdvanced ;
+ public boolean showAdvanced ;
+ public boolean stackTouched ;
+ public boolean restored ;
+ public boolean directoryCopy ;
+ /** Transfer mode for file copy/move operations. */
+ public int transferMode;
+
+ /** Current user navigation stack; empty implies recents. */
+ public DocumentStack stack = new DocumentStack();
+ /** Currently active search, overriding any stack. */
+ public String currentSearch;
+
+ /** Instance state for every shown directory */
+ public HashMap<String, SparseArray<Parcelable>> dirState = new HashMap<>();
+
+ /** Currently copying file */
+ public List<DocumentInfo> selectedDocumentsForCopy = new ArrayList<DocumentInfo>();
+
+ /** Name of the package that started DocsUI */
+ public List<String> excludedAuthorities = new ArrayList<>();
+
+ public static final int ACTION_OPEN = 1;
+ public static final int ACTION_CREATE = 2;
+ public static final int ACTION_GET_CONTENT = 3;
+ public static final int ACTION_OPEN_TREE = 4;
+ public static final int ACTION_MANAGE = 5;
+ public static final int ACTION_BROWSE = 6;
+ public static final int ACTION_OPEN_COPY_DESTINATION = 8;
+
+ public static final int MODE_UNKNOWN = 0;
+ public static final int MODE_LIST = 1;
+ public static final int MODE_GRID = 2;
+
+ public static final int SORT_ORDER_UNKNOWN = 0;
+ public static final int SORT_ORDER_DISPLAY_NAME = 1;
+ public static final int SORT_ORDER_LAST_MODIFIED = 2;
+ public static final int SORT_ORDER_SIZE = 3;
+
+ public void initAcceptMimes(Intent intent) {
+ if (intent.hasExtra(Intent.EXTRA_MIME_TYPES)) {
+ acceptMimes = intent.getStringArrayExtra(Intent.EXTRA_MIME_TYPES);
+ } else {
+ String glob = intent.getType();
+ acceptMimes = new String[] { glob != null ? glob : "*/*" };
+ }
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeInt(action);
+ out.writeInt(userMode);
+ out.writeStringArray(acceptMimes);
+ out.writeInt(userSortOrder);
+ out.writeInt(allowMultiple ? 1 : 0);
+ out.writeInt(forceSize ? 1 : 0);
+ out.writeInt(showSize ? 1 : 0);
+ out.writeInt(localOnly ? 1 : 0);
+ out.writeInt(forceAdvanced ? 1 : 0);
+ out.writeInt(showAdvanced ? 1 : 0);
+ out.writeInt(stackTouched ? 1 : 0);
+ out.writeInt(restored ? 1 : 0);
+ DurableUtils.writeToParcel(out, stack);
+ out.writeString(currentSearch);
+ out.writeMap(dirState);
+ out.writeList(selectedDocumentsForCopy);
+ out.writeList(excludedAuthorities);
+ }
+
+ public static final Creator<State> CREATOR = new Creator<State>() {
+ @Override
+ public State createFromParcel(Parcel in) {
+ final State state = new State();
+ state.action = in.readInt();
+ state.userMode = in.readInt();
+ state.acceptMimes = in.readStringArray();
+ state.userSortOrder = in.readInt();
+ state.allowMultiple = in.readInt() != 0;
+ state.forceSize = in.readInt() != 0;
+ state.showSize = in.readInt() != 0;
+ state.localOnly = in.readInt() != 0;
+ state.forceAdvanced = in.readInt() != 0;
+ state.showAdvanced = in.readInt() != 0;
+ state.stackTouched = in.readInt() != 0;
+ state.restored = in.readInt() != 0;
+ DurableUtils.readFromParcel(in, state.stack);
+ state.currentSearch = in.readString();
+ in.readMap(state.dirState, null);
+ in.readList(state.selectedDocumentsForCopy, null);
+ in.readList(state.excludedAuthorities, null);
+ return state;
+ }
+
+ @Override
+ public State[] newArray(int size) {
+ return new State[size];
+ }
+ };
+}
\ No newline at end of file
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/RootsCacheTest.java b/packages/DocumentsUI/tests/src/com/android/documentsui/RootsCacheTest.java
index 1325706..7d3498e 100644
--- a/packages/DocumentsUI/tests/src/com/android/documentsui/RootsCacheTest.java
+++ b/packages/DocumentsUI/tests/src/com/android/documentsui/RootsCacheTest.java
@@ -19,7 +19,6 @@
import android.test.AndroidTestCase;
import android.test.suitebuilder.annotation.SmallTest;
-import com.android.documentsui.BaseActivity.State;
import com.android.documentsui.model.RootInfo;
import com.google.common.collect.Lists;
diff --git a/packages/SystemUI/res/layout/recents.xml b/packages/SystemUI/res/layout/recents.xml
index 8140dd6..064d225 100644
--- a/packages/SystemUI/res/layout/recents.xml
+++ b/packages/SystemUI/res/layout/recents.xml
@@ -39,12 +39,6 @@
android:layout_width="match_parent"
android:layout_height="match_parent" />
- <!-- Debug Overlay View -->
- <ViewStub android:id="@+id/debug_overlay_stub"
- android:layout="@layout/recents_debug_overlay"
- android:layout_width="match_parent"
- android:layout_height="match_parent" />
-
<!-- Nav Bar Scrim View -->
<ImageView
android:id="@+id/nav_bar_scrim"
diff --git a/packages/SystemUI/res/layout/recents_debug_overlay.xml b/packages/SystemUI/res/layout/recents_debug_overlay.xml
deleted file mode 100644
index d23495e..0000000
--- a/packages/SystemUI/res/layout/recents_debug_overlay.xml
+++ /dev/null
@@ -1,35 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2014 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.
--->
-<com.android.systemui.recents.views.DebugOverlayView
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:focusable="false">
- <SeekBar
- android:id="@+id/debug_seek_bar_1"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_gravity="top"
- android:layout_marginTop="25dp" />
- <SeekBar
- android:id="@+id/debug_seek_bar_2"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_gravity="top"
- android:layout_marginTop="50dp" />
-</com.android.systemui.recents.views.DebugOverlayView>
-
-
diff --git a/packages/SystemUI/src/com/android/systemui/recents/Constants.java b/packages/SystemUI/src/com/android/systemui/recents/Constants.java
index e1a8815..9781664 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/Constants.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/Constants.java
@@ -29,8 +29,6 @@
}
public static class DebugFlags {
- // Enable this with any other debug flag to see more info
- public static final boolean Verbose = false;
public static class App {
// Enables debug drawing for the transition thumbnail
@@ -39,10 +37,6 @@
public static final boolean EnableTaskFiltering = false;
// Enables dismiss-all
public static final boolean EnableDismissAll = false;
- // Enables debug mode
- public static final boolean EnableDebugMode = false;
- // Enables the search bar layout
- public static final boolean EnableSearchLayout = true;
// Enables the thumbnail alpha on the front-most task
public static final boolean EnableThumbnailAlphaOnFrontmost = false;
// This disables the bitmap and icon caches
@@ -63,7 +57,6 @@
public static class Values {
public static class App {
public static int AppWidgetHostId = 1024;
- public static String DebugModeVersion = "A";
}
public static class TaskStackView {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
index 4bb3e4a..c53e573 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
@@ -38,14 +38,12 @@
import com.android.systemui.Prefs;
import com.android.systemui.R;
import com.android.systemui.recents.misc.Console;
-import com.android.systemui.recents.misc.DebugTrigger;
import com.android.systemui.recents.misc.ReferenceCountedTrigger;
import com.android.systemui.recents.misc.SystemServicesProxy;
import com.android.systemui.recents.model.RecentsTaskLoadPlan;
import com.android.systemui.recents.model.RecentsTaskLoader;
import com.android.systemui.recents.model.Task;
import com.android.systemui.recents.model.TaskStack;
-import com.android.systemui.recents.views.DebugOverlayView;
import com.android.systemui.recents.views.RecentsView;
import com.android.systemui.recents.views.SystemBarScrimViews;
import com.android.systemui.recents.views.ViewAnimation;
@@ -57,8 +55,7 @@
* The main Recents activity that is started from AlternateRecentsComponent.
*/
public class RecentsActivity extends Activity implements RecentsView.RecentsViewCallbacks,
- RecentsAppWidgetHost.RecentsAppWidgetHostCallbacks,
- DebugOverlayView.DebugOverlayViewCallbacks {
+ RecentsAppWidgetHost.RecentsAppWidgetHostCallbacks {
RecentsConfiguration mConfig;
long mLastTabKeyEventTime;
@@ -67,9 +64,7 @@
RecentsView mRecentsView;
SystemBarScrimViews mScrimViews;
ViewStub mEmptyViewStub;
- ViewStub mDebugOverlayStub;
View mEmptyView;
- DebugOverlayView mDebugOverlay;
// Resize task debug
RecentsResizeTaskDialog mResizeTaskDebugDialog;
@@ -176,16 +171,6 @@
}
};
- /**
- * A custom debug trigger to listen for a debug key chord.
- */
- final DebugTrigger mDebugTrigger = new DebugTrigger(new Runnable() {
- @Override
- public void run() {
- onDebugModeTriggered();
- }
- });
-
/** Updates the set of recent tasks */
void updateRecentsTasks() {
// If AlternateRecentsComponent has preloaded a load plan, then use that to prevent
@@ -352,9 +337,7 @@
View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN |
View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION);
mEmptyViewStub = (ViewStub) findViewById(R.id.empty_view_stub);
- mDebugOverlayStub = (ViewStub) findViewById(R.id.debug_overlay_stub);
mScrimViews = new SystemBarScrimViews(this, mConfig);
- inflateDebugOverlay();
// Bind the search app widget when we first start up
mSearchWidgetInfo = ssp.getOrBindSearchAppWidget(this, mAppWidgetHost);
@@ -366,27 +349,10 @@
registerReceiver(mSystemBroadcastReceiver, filter);
}
- /** Inflates the debug overlay if debug mode is enabled. */
- void inflateDebugOverlay() {
- if (!Constants.DebugFlags.App.EnableDebugMode) return;
-
- if (mConfig.debugModeEnabled && mDebugOverlay == null) {
- // Inflate the overlay and seek bars
- mDebugOverlay = (DebugOverlayView) mDebugOverlayStub.inflate();
- mDebugOverlay.setCallbacks(this);
- mRecentsView.setDebugOverlay(mDebugOverlay);
- }
- }
-
@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
setIntent(intent);
-
- // Clear any debug rects
- if (mDebugOverlay != null) {
- mDebugOverlay.clear();
- }
}
@Override
@@ -538,8 +504,6 @@
default:
break;
}
- // Pass through the debug trigger
- mDebugTrigger.onKeyEvent(keyCode);
return super.onKeyDown(keyCode, event);
}
@@ -557,33 +521,6 @@
dismissRecentsToFocusedTaskOrHome(true);
}
- /** Called when debug mode is triggered */
- public void onDebugModeTriggered() {
- if (mConfig.developerOptionsEnabled) {
- if (Prefs.getBoolean(this, Prefs.Key.DEBUG_MODE_ENABLED, false /* boolean */)) {
- // Disable the debug mode
- Prefs.remove(this, Prefs.Key.DEBUG_MODE_ENABLED);
- mConfig.debugModeEnabled = false;
- inflateDebugOverlay();
- if (mDebugOverlay != null) {
- mDebugOverlay.disable();
- }
- } else {
- // Enable the debug mode
- Prefs.putBoolean(this, Prefs.Key.DEBUG_MODE_ENABLED, true);
- mConfig.debugModeEnabled = true;
- inflateDebugOverlay();
- if (mDebugOverlay != null) {
- mDebugOverlay.enable();
- }
- }
- Toast.makeText(this, "Debug mode (" + Constants.Values.App.DebugModeVersion + ") " +
- (mConfig.debugModeEnabled ? "Enabled" : "Disabled") + ", please restart Recents now",
- Toast.LENGTH_SHORT).show();
- }
- }
-
-
/**** RecentsResizeTaskDialog ****/
private RecentsResizeTaskDialog getResizeTaskDebugDialog() {
@@ -655,16 +592,4 @@
mRecentsView.setSearchBar(null);
}
}
-
- /**** DebugOverlayView.DebugOverlayViewCallbacks ****/
-
- @Override
- public void onPrimarySeekBarChanged(float progress) {
- // Do nothing
- }
-
- @Override
- public void onSecondarySeekBarChanged(float progress) {
- // Do nothing
- }
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/misc/DebugTrigger.java b/packages/SystemUI/src/com/android/systemui/recents/misc/DebugTrigger.java
deleted file mode 100644
index fbf8a86..0000000
--- a/packages/SystemUI/src/com/android/systemui/recents/misc/DebugTrigger.java
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * Copyright (C) 2014 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 com.android.systemui.recents.misc;
-
-import android.os.Handler;
-import android.os.SystemClock;
-import android.view.KeyEvent;
-import com.android.systemui.recents.Constants;
-
-/**
- * A trigger for catching a debug chord.
- * We currently use volume up then volume down to trigger this mode.
- */
-public class DebugTrigger {
-
- Handler mHandler;
- Runnable mTriggeredRunnable;
-
- int mLastKeyCode;
- long mLastKeyCodeTime;
-
- public DebugTrigger(Runnable triggeredRunnable) {
- mHandler = new Handler();
- mTriggeredRunnable = triggeredRunnable;
- }
-
- /** Resets the debug trigger */
- void reset() {
- mLastKeyCode = 0;
- mLastKeyCodeTime = 0;
- }
-
- /**
- * Processes a key event and tests if it is a part of the trigger. If the chord is complete,
- * then we just call the callback.
- */
- public void onKeyEvent(int keyCode) {
- if (!Constants.DebugFlags.App.EnableDebugMode) return;
-
- if (mLastKeyCode == 0) {
- if (keyCode == KeyEvent.KEYCODE_VOLUME_UP) {
- mLastKeyCode = keyCode;
- mLastKeyCodeTime = SystemClock.uptimeMillis();
- return;
- }
- } else {
- if (mLastKeyCode == KeyEvent.KEYCODE_VOLUME_UP &&
- keyCode == KeyEvent.KEYCODE_VOLUME_DOWN) {
- if ((SystemClock.uptimeMillis() - mLastKeyCodeTime) < 750) {
- mTriggeredRunnable.run();
- }
- }
- }
- reset();
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java b/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java
index a760a41..515e578 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java
@@ -17,7 +17,6 @@
package com.android.systemui.recents.model;
import android.graphics.Color;
-import android.graphics.Rect;
import com.android.systemui.recents.Constants;
import com.android.systemui.recents.RecentsConfiguration;
import com.android.systemui.recents.misc.NamedCounter;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/DebugOverlayView.java b/packages/SystemUI/src/com/android/systemui/recents/views/DebugOverlayView.java
deleted file mode 100644
index 452830d..0000000
--- a/packages/SystemUI/src/com/android/systemui/recents/views/DebugOverlayView.java
+++ /dev/null
@@ -1,190 +0,0 @@
-/*
- * Copyright (C) 2014 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 com.android.systemui.recents.views;
-
-import android.content.Context;
-import android.graphics.Canvas;
-import android.graphics.Paint;
-import android.graphics.Rect;
-import android.util.AttributeSet;
-import android.util.Pair;
-import android.view.View;
-import android.widget.FrameLayout;
-import android.widget.SeekBar;
-import com.android.systemui.R;
-import com.android.systemui.recents.RecentsConfiguration;
-
-import java.util.ArrayList;
-
-/**
- * A full screen overlay layer that allows us to draw views from throughout the system on the top
- * most layer.
- */
-public class DebugOverlayView extends FrameLayout implements SeekBar.OnSeekBarChangeListener {
-
- public interface DebugOverlayViewCallbacks {
- public void onPrimarySeekBarChanged(float progress);
- public void onSecondarySeekBarChanged(float progress);
- }
-
- final static int sCornerRectSize = 50;
-
- RecentsConfiguration mConfig;
- DebugOverlayViewCallbacks mCb;
-
- ArrayList<Pair<Rect, Integer>> mRects = new ArrayList<Pair<Rect, Integer>>();
- String mText;
- Paint mDebugOutline = new Paint();
- Paint mTmpPaint = new Paint();
- Rect mTmpRect = new Rect();
- boolean mEnabled = true;
-
- SeekBar mPrimarySeekBar;
- SeekBar mSecondarySeekBar;
-
- public DebugOverlayView(Context context) {
- this(context, null);
- }
-
- public DebugOverlayView(Context context, AttributeSet attrs) {
- this(context, attrs, 0);
- }
-
- public DebugOverlayView(Context context, AttributeSet attrs, int defStyleAttr) {
- this(context, attrs, defStyleAttr, 0);
- }
-
- public DebugOverlayView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
- super(context, attrs, defStyleAttr, defStyleRes);
- mConfig = RecentsConfiguration.getInstance();
- mDebugOutline.setColor(0xFFff0000);
- mDebugOutline.setStyle(Paint.Style.STROKE);
- mDebugOutline.setStrokeWidth(8f);
- setWillNotDraw(false);
- }
-
- public void setCallbacks(DebugOverlayViewCallbacks cb) {
- mCb = cb;
- }
-
- @Override
- protected void onFinishInflate() {
- mPrimarySeekBar = (SeekBar) findViewById(R.id.debug_seek_bar_1);
- mPrimarySeekBar.setOnSeekBarChangeListener(this);
- mSecondarySeekBar = (SeekBar) findViewById(R.id.debug_seek_bar_2);
- mSecondarySeekBar.setOnSeekBarChangeListener(this);
- }
-
- /** Enables the debug overlay drawing. */
- public void enable() {
- mEnabled = true;
- setVisibility(View.VISIBLE);
- }
-
- /** Disables the debug overlay drawing. */
- public void disable() {
- mEnabled = false;
- setVisibility(View.GONE);
- }
-
- /** Clears all debug rects. */
- public void clear() {
- mRects.clear();
- }
-
- /** Adds a rect to be drawn. */
- void addRect(Rect r, int color) {
- mRects.add(new Pair<Rect, Integer>(r, color));
- invalidate();
- }
-
- /** Adds a view's global rect to be drawn. */
- void addViewRect(View v, int color) {
- Rect vr = new Rect();
- v.getGlobalVisibleRect(vr);
- mRects.add(new Pair<Rect, Integer>(vr, color));
- invalidate();
- }
-
- /** Adds a rect, relative to a given view to be drawn. */
- void addRectRelativeToView(View v, Rect r, int color) {
- Rect vr = new Rect();
- v.getGlobalVisibleRect(vr);
- r.offsetTo(vr.left, vr.top);
- mRects.add(new Pair<Rect, Integer>(r, color));
- invalidate();
- }
-
- /** Sets the debug text at the bottom of the screen. */
- void setText(String message) {
- mText = message;
- invalidate();
- }
-
- @Override
- protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- super.onMeasure(widthMeasureSpec, heightMeasureSpec);
- addRect(new Rect(0, 0, sCornerRectSize, sCornerRectSize), 0xFFff0000);
- addRect(new Rect(getMeasuredWidth() - sCornerRectSize, getMeasuredHeight() - sCornerRectSize,
- getMeasuredWidth(), getMeasuredHeight()), 0xFFff0000);
- }
-
- @Override
- protected void onDraw(Canvas canvas) {
- if (mEnabled) {
- // Draw the outline
- canvas.drawRect(0, 0, getMeasuredWidth(), getMeasuredHeight(), mDebugOutline);
-
- // Draw the rects
- int numRects = mRects.size();
- for (int i = 0; i < numRects; i++) {
- Pair<Rect, Integer> r = mRects.get(i);
- mTmpPaint.setColor(r.second);
- canvas.drawRect(r.first, mTmpPaint);
- }
-
- // Draw the text
- if (mText != null && mText.length() > 0) {
- mTmpPaint.setColor(0xFFff0000);
- mTmpPaint.setTextSize(60);
- mTmpPaint.getTextBounds(mText, 0, 1, mTmpRect);
- canvas.drawText(mText, 10f, getMeasuredHeight() - mTmpRect.height() - mConfig.systemInsets.bottom, mTmpPaint);
- }
- }
- }
-
- /**** SeekBar.OnSeekBarChangeListener Implementation ****/
-
- @Override
- public void onStopTrackingTouch(SeekBar seekBar) {
- // Do nothing
- }
-
- @Override
- public void onStartTrackingTouch(SeekBar seekBar) {
- // Do nothing
- }
-
- @Override
- public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
- if (seekBar == mPrimarySeekBar) {
- mCb.onPrimarySeekBarChanged((float) progress / mPrimarySeekBar.getMax());
- } else if (seekBar == mSecondarySeekBar) {
- mCb.onSecondarySeekBarChanged((float) progress / mSecondarySeekBar.getMax());
- }
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/FakeShadowDrawable.java b/packages/SystemUI/src/com/android/systemui/recents/views/FakeShadowDrawable.java
index 509ad1b..41adbed 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/FakeShadowDrawable.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/FakeShadowDrawable.java
@@ -28,7 +28,6 @@
import android.graphics.Shader;
import android.graphics.drawable.Drawable;
import android.util.Log;
-
import com.android.systemui.R;
import com.android.systemui.recents.RecentsConfiguration;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
index c7d1dd1..fab8b3a 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
@@ -78,7 +78,6 @@
RecentsConfiguration mConfig;
LayoutInflater mInflater;
- DebugOverlayView mDebugOverlay;
ArrayList<TaskStack> mStacks;
TaskStackView mTaskStackView;
@@ -108,11 +107,6 @@
mCb = cb;
}
- /** Sets the debug overlay */
- public void setDebugOverlay(DebugOverlayView overlay) {
- mDebugOverlay = overlay;
- }
-
/** Set/get the bsp root node */
public void setTaskStack(TaskStack stack) {
if (mConfig.launchedReuseTaskStackViews) {
@@ -134,11 +128,6 @@
addView(mTaskStackView);
}
- // Enable debug mode drawing on all the stacks if necessary
- if (mConfig.debugModeEnabled) {
- mTaskStackView.setDebugOverlay(mDebugOverlay);
- }
-
// Trigger a new layout
requestLayout();
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
index 8058c5e..4db8b37 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
@@ -79,7 +79,6 @@
ViewPool<TaskView, Task> mViewPool;
ArrayList<TaskViewTransform> mCurrentTaskTransforms = new ArrayList<TaskViewTransform>();
DozeTrigger mUIDozeTrigger;
- DebugOverlayView mDebugOverlay;
DismissView mDismissAllButton;
boolean mDismissAllButtonAnimating;
int mFocusedTaskIndex = -1;
@@ -161,11 +160,6 @@
return mStack;
}
- /** Sets the debug overlay */
- public void setDebugOverlay(DebugOverlayView overlay) {
- mDebugOverlay = overlay;
- }
-
/** Updates the list of task views */
void updateTaskViewsList() {
mTaskViews.clear();
@@ -334,9 +328,6 @@
int[] visibleRange = mTmpVisibleRange;
boolean isValidVisibleRange = updateStackTransforms(mCurrentTaskTransforms, tasks,
stackScroll, visibleRange, false);
- if (mDebugOverlay != null) {
- mDebugOverlay.setText("vis[" + visibleRange[1] + "-" + visibleRange[0] + "]");
- }
// Inflate and add the dismiss button if necessary
if (Constants.DebugFlags.App.EnableDismissAll && mDismissAllButton == null) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
index b01a2a8..10d4a96 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
@@ -112,7 +112,7 @@
public void appTransitionStarting(long startTime, long duration);
public void showAssistDisclosure();
public void startAssist(Bundle args);
- public void onCameraLaunchGestureDetected();
+ public void onCameraLaunchGestureDetected(int source);
}
public CommandQueue(Callbacks callbacks, StatusBarIconList list) {
@@ -306,10 +306,10 @@
}
@Override
- public void onCameraLaunchGestureDetected() {
+ public void onCameraLaunchGestureDetected(int source) {
synchronized (mList) {
mHandler.removeMessages(MSG_CAMERA_LAUNCH_GESTURE);
- mHandler.obtainMessage(MSG_CAMERA_LAUNCH_GESTURE).sendToTarget();
+ mHandler.obtainMessage(MSG_CAMERA_LAUNCH_GESTURE, source, 0).sendToTarget();
}
}
@@ -415,7 +415,7 @@
mCallbacks.startAssist((Bundle) msg.obj);
break;
case MSG_CAMERA_LAUNCH_GESTURE:
- mCallbacks.onCameraLaunchGestureDetected();
+ mCallbacks.onCameraLaunchGestureDetected(msg.arg1);
break;
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
index 012dc9c..14176a6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
@@ -77,6 +77,13 @@
final static String TAG = "PhoneStatusBar/KeyguardBottomAreaView";
+ public static final String CAMERA_LAUNCH_SOURCE_AFFORDANCE = "lockscreen_affordance";
+ public static final String CAMERA_LAUNCH_SOURCE_WIGGLE = "wiggle_gesture";
+ public static final String CAMERA_LAUNCH_SOURCE_POWER_DOUBLE_TAP = "power_double_tap";
+
+ public static final String EXTRA_CAMERA_LAUNCH_SOURCE
+ = "com.android.systemui.camera_launch_source";
+
private static final Intent SECURE_CAMERA_INTENT =
new Intent(MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA_SECURE)
.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
@@ -170,7 +177,7 @@
CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL, true /* force */);
return true;
} else if (host == mCameraImageView) {
- launchCamera();
+ launchCamera(CAMERA_LAUNCH_SOURCE_AFFORDANCE);
return true;
} else if (host == mLeftAffordanceView) {
launchLeftAffordance();
@@ -349,7 +356,7 @@
@Override
public void onClick(View v) {
if (v == mCameraImageView) {
- launchCamera();
+ launchCamera(CAMERA_LAUNCH_SOURCE_AFFORDANCE);
} else if (v == mLeftAffordanceView) {
launchLeftAffordance();
} if (v == mLockIcon) {
@@ -417,8 +424,9 @@
}
}
- public void launchCamera() {
+ public void launchCamera(String source) {
final Intent intent = getCameraIntent();
+ intent.putExtra(EXTRA_CAMERA_LAUNCH_SOURCE, source);
boolean wouldLaunchResolverActivity = PreviewInflater.wouldLaunchResolverActivity(
mContext, intent, KeyguardUpdateMonitor.getCurrentUser());
if (intent == SECURE_CAMERA_INTENT && !wouldLaunchResolverActivity) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
index 12d373d..08353cb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -22,6 +22,7 @@
import android.animation.PropertyValuesHolder;
import android.animation.ValueAnimator;
import android.app.ActivityManager;
+import android.app.StatusBarManager;
import android.content.Context;
import android.content.pm.ResolveInfo;
import android.content.res.Configuration;
@@ -204,6 +205,7 @@
private boolean mHeadsUpAnimatingAway;
private boolean mLaunchingAffordance;
private FalsingManager mFalsingManager;
+ private String mLastCameraLaunchSource = KeyguardBottomAreaView.CAMERA_LAUNCH_SOURCE_AFFORDANCE;
private Runnable mHeadsUpExistenceChangedRunnable = new Runnable() {
@Override
@@ -480,6 +482,7 @@
mUnlockIconActive = false;
if (!mLaunchingAffordance) {
mAfforanceHelper.reset(false);
+ mLastCameraLaunchSource = KeyguardBottomAreaView.CAMERA_LAUNCH_SOURCE_AFFORDANCE;
}
closeQs();
mStatusBar.dismissPopups();
@@ -1971,20 +1974,23 @@
mKeyguardBottomArea.launchLeftAffordance();
}
} else {
- EventLogTags.writeSysuiLockscreenGesture(
- EventLogConstants.SYSUI_LOCKSCREEN_GESTURE_SWIPE_CAMERA, lengthDp, velocityDp);
-
+ if (KeyguardBottomAreaView.CAMERA_LAUNCH_SOURCE_AFFORDANCE.equals(
+ mLastCameraLaunchSource)) {
+ EventLogTags.writeSysuiLockscreenGesture(
+ EventLogConstants.SYSUI_LOCKSCREEN_GESTURE_SWIPE_CAMERA,
+ lengthDp, velocityDp);
+ }
mFalsingManager.onCameraOn();
if (mFalsingManager.shouldEnforceBouncer()) {
mStatusBar.executeRunnableDismissingKeyguard(new Runnable() {
@Override
public void run() {
- mKeyguardBottomArea.launchCamera();
+ mKeyguardBottomArea.launchCamera(mLastCameraLaunchSource);
}
}, null, true /* dismissShade */, false /* afterKeyguardGone */);
}
else {
- mKeyguardBottomArea.launchCamera();
+ mKeyguardBottomArea.launchCamera(mLastCameraLaunchSource);
}
}
mStatusBar.startLaunchTransitionTimeout();
@@ -2425,7 +2431,17 @@
return !mDozing;
}
- public void launchCamera(boolean animate) {
+ public void launchCamera(boolean animate, int source) {
+ if (source == StatusBarManager.CAMERA_LAUNCH_SOURCE_POWER_DOUBLE_TAP) {
+ mLastCameraLaunchSource = KeyguardBottomAreaView.CAMERA_LAUNCH_SOURCE_POWER_DOUBLE_TAP;
+ } else if (source == StatusBarManager.CAMERA_LAUNCH_SOURCE_WIGGLE) {
+ mLastCameraLaunchSource = KeyguardBottomAreaView.CAMERA_LAUNCH_SOURCE_WIGGLE;
+ } else {
+
+ // Default.
+ mLastCameraLaunchSource = KeyguardBottomAreaView.CAMERA_LAUNCH_SOURCE_AFFORDANCE;
+ }
+
// If we are launching it when we are occluded already we don't want it to animate,
// nor setting these flags, since the occluded state doesn't change anymore, hence it's
// never reset.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
index 151fa3c..98f5444 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -492,6 +492,7 @@
private ExpandableNotificationRow mDraggedDownRow;
private boolean mLaunchCameraOnScreenTurningOn;
private boolean mLaunchCameraOnFinishedGoingToSleep;
+ private int mLastCameraLaunchSource;
private PowerManager.WakeLock mGestureWakeLock;
private Vibrator mVibrator;
@@ -3992,7 +3993,7 @@
mHandler.post(new Runnable() {
@Override
public void run() {
- onCameraLaunchGestureDetected();
+ onCameraLaunchGestureDetected(mLastCameraLaunchSource);
}
});
}
@@ -4010,7 +4011,7 @@
mFalsingManager.onScreenTurningOn();
mNotificationPanel.onScreenTurningOn();
if (mLaunchCameraOnScreenTurningOn) {
- mNotificationPanel.launchCamera(false);
+ mNotificationPanel.launchCamera(false, mLastCameraLaunchSource);
mLaunchCameraOnScreenTurningOn = false;
}
}
@@ -4175,7 +4176,8 @@
}
@Override
- public void onCameraLaunchGestureDetected() {
+ public void onCameraLaunchGestureDetected(int source) {
+ mLastCameraLaunchSource = source;
if (mStartedGoingToSleep) {
mLaunchCameraOnFinishedGoingToSleep = true;
return;
@@ -4201,7 +4203,7 @@
mGestureWakeLock.acquire(LAUNCH_TRANSITION_TIMEOUT_MS + 1000L);
}
if (mScreenTurningOn || mStatusBarKeyguardViewManager.isScreenTurnedOn()) {
- mNotificationPanel.launchCamera(mDeviceInteractive /* animate */);
+ mNotificationPanel.launchCamera(mDeviceInteractive /* animate */, source);
} else {
// We need to defer the camera launch until the screen comes on, since otherwise
// we will dismiss us too early since we are waiting on an activity to be drawn and
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java
index 2587b9f..bbe5dd9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java
@@ -171,7 +171,7 @@
}
@Override
- public void onCameraLaunchGestureDetected() {
+ public void onCameraLaunchGestureDetected(int source) {
}
@Override
diff --git a/services/accessibility/java/com/android/server/accessibility/TouchExplorer.java b/services/accessibility/java/com/android/server/accessibility/TouchExplorer.java
index 85730cd..c3f5c43 100644
--- a/services/accessibility/java/com/android/server/accessibility/TouchExplorer.java
+++ b/services/accessibility/java/com/android/server/accessibility/TouchExplorer.java
@@ -29,6 +29,7 @@
import android.os.Handler;
import android.os.SystemClock;
import android.util.Slog;
+import android.view.GestureDetector;
import android.view.InputDevice;
import android.view.KeyEvent;
import android.view.MotionEvent;
@@ -114,9 +115,6 @@
// Timeout within which we try to detect a tap.
private final int mTapTimeout;
- // Timeout within which we try to detect a double tap.
- private final int mDoubleTapTimeout;
-
// Slop between the down and up tap to be a tap.
private final int mTouchSlop;
@@ -230,7 +228,6 @@
mInjectedPointerTracker = new InjectedPointerTracker();
mTapTimeout = ViewConfiguration.getTapTimeout();
mDetermineUserIntentTimeout = ViewConfiguration.getDoubleTapTimeout();
- mDoubleTapTimeout = ViewConfiguration.getDoubleTapTimeout();
mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
mDoubleTapSlop = ViewConfiguration.get(context).getScaledDoubleTapSlop();
mHandler = new Handler(context.getMainLooper());
@@ -248,7 +245,7 @@
mSendTouchInteractionEndDelayed = new SendAccessibilityEventDelayed(
AccessibilityEvent.TYPE_TOUCH_INTERACTION_END,
mDetermineUserIntentTimeout);
- mDoubleTapDetector = new DoubleTapDetector();
+ mDoubleTapDetector = new DoubleTapDetector(mContext);
final float density = context.getResources().getDisplayMetrics().density;
mScaledMinPointerDistanceToUseMiddleLocation =
(int) (MIN_POINTER_DISTANCE_TO_USE_MIDDLE_LOCATION_DIP * density);
@@ -1109,66 +1106,63 @@
}
}
- private class DoubleTapDetector {
- private MotionEvent mDownEvent;
- private MotionEvent mFirstTapEvent;
+ private class DoubleTapDetector extends GestureDetector.SimpleOnGestureListener {
+ private final GestureDetector mGestureDetector;
+ private boolean mFirstTapDetected;
+ private boolean mDoubleTapDetected;
- public void onMotionEvent(MotionEvent event, int policyFlags) {
- final int actionIndex = event.getActionIndex();
- final int action = event.getActionMasked();
- switch (action) {
- case MotionEvent.ACTION_DOWN:
- case MotionEvent.ACTION_POINTER_DOWN: {
- if (mFirstTapEvent != null
- && !GestureUtils.isSamePointerContext(mFirstTapEvent, event)) {
- clear();
- }
- mDownEvent = MotionEvent.obtain(event);
- } break;
- case MotionEvent.ACTION_UP:
- case MotionEvent.ACTION_POINTER_UP: {
- if (mDownEvent == null) {
- return;
- }
- if (!GestureUtils.isSamePointerContext(mDownEvent, event)) {
- clear();
- return;
- }
- if (GestureUtils.isTap(mDownEvent, event, mTapTimeout, mTouchSlop,
- actionIndex)) {
- if (mFirstTapEvent == null || GestureUtils.isTimedOut(mFirstTapEvent,
- event, mDoubleTapTimeout)) {
- mFirstTapEvent = MotionEvent.obtain(event);
- mDownEvent.recycle();
- mDownEvent = null;
- return;
- }
- if (GestureUtils.isMultiTap(mFirstTapEvent, event, mDoubleTapTimeout,
- mDoubleTapSlop, actionIndex)) {
- onDoubleTap(event, policyFlags);
- mFirstTapEvent.recycle();
- mFirstTapEvent = null;
- mDownEvent.recycle();
- mDownEvent = null;
- return;
- }
- mFirstTapEvent.recycle();
- mFirstTapEvent = null;
- } else {
- if (mFirstTapEvent != null) {
- mFirstTapEvent.recycle();
- mFirstTapEvent = null;
- }
- }
- mDownEvent.recycle();
- mDownEvent = null;
- } break;
- }
+ DoubleTapDetector(Context context) {
+ mGestureDetector = new GestureDetector(context, this);
+ mGestureDetector.setOnDoubleTapListener(this);
}
- public void onDoubleTap(MotionEvent secondTapUp, int policyFlags) {
+ public void onMotionEvent(MotionEvent event, int policyFlags) {
+ switch (event.getActionMasked()) {
+ case MotionEvent.ACTION_DOWN:
+ mDoubleTapDetected = false;
+ break;
+
+ case MotionEvent.ACTION_UP:
+ maybeFinishDoubleTap(event, policyFlags);
+ break;
+ }
+ mGestureDetector.onTouchEvent(event);
+ }
+
+ @Override
+ public boolean onDown(MotionEvent event) {
+ return true;
+ }
+
+ @Override
+ public boolean onSingleTapUp(MotionEvent event) {
+ mFirstTapDetected = true;
+ return false;
+ }
+
+ @Override
+ public boolean onSingleTapConfirmed(MotionEvent event) {
+ clear();
+ return false;
+ }
+
+ @Override
+ public boolean onDoubleTap(MotionEvent event) {
+ // The processing of the double tap is deferred until the finger is
+ // lifted, so that we can detect a long press on the second tap.
+ mDoubleTapDetected = true;
+ return true;
+ }
+
+ private void maybeFinishDoubleTap(MotionEvent event, int policyFlags) {
+ if (!mDoubleTapDetected) {
+ return;
+ }
+
+ clear();
+
// This should never be called when more than two pointers are down.
- if (secondTapUp.getPointerCount() > 2) {
+ if (event.getPointerCount() > 2) {
return;
}
@@ -1184,8 +1178,8 @@
mSendTouchInteractionEndDelayed.forceSendAndRemove();
}
- final int pointerId = secondTapUp.getPointerId(secondTapUp.getActionIndex());
- final int pointerIndex = secondTapUp.findPointerIndex(pointerId);
+ final int pointerId = event.getPointerId(event.getActionIndex());
+ final int pointerIndex = event.findPointerIndex(pointerId);
Point clickLocation = mTempPoint;
final int result = computeClickLocation(clickLocation);
@@ -1196,34 +1190,28 @@
// Do the click.
PointerProperties[] properties = new PointerProperties[1];
properties[0] = new PointerProperties();
- secondTapUp.getPointerProperties(pointerIndex, properties[0]);
+ event.getPointerProperties(pointerIndex, properties[0]);
PointerCoords[] coords = new PointerCoords[1];
coords[0] = new PointerCoords();
coords[0].x = clickLocation.x;
coords[0].y = clickLocation.y;
- MotionEvent event = MotionEvent.obtain(secondTapUp.getDownTime(),
- secondTapUp.getEventTime(), MotionEvent.ACTION_DOWN, 1, properties,
- coords, 0, 0, 1.0f, 1.0f, secondTapUp.getDeviceId(), 0,
- secondTapUp.getSource(), secondTapUp.getFlags());
+ MotionEvent click_event = MotionEvent.obtain(event.getDownTime(),
+ event.getEventTime(), MotionEvent.ACTION_DOWN, 1, properties,
+ coords, 0, 0, 1.0f, 1.0f, event.getDeviceId(), 0,
+ event.getSource(), event.getFlags());
final boolean targetAccessibilityFocus = (result == CLICK_LOCATION_ACCESSIBILITY_FOCUS);
- sendActionDownAndUp(event, policyFlags, targetAccessibilityFocus);
- event.recycle();
+ sendActionDownAndUp(click_event, policyFlags, targetAccessibilityFocus);
+ click_event.recycle();
+ return;
}
public void clear() {
- if (mDownEvent != null) {
- mDownEvent.recycle();
- mDownEvent = null;
- }
- if (mFirstTapEvent != null) {
- mFirstTapEvent.recycle();
- mFirstTapEvent = null;
- }
+ mFirstTapDetected = false;
+ mDoubleTapDetected = false;
}
public boolean firstTapDetected() {
- return mFirstTapEvent != null
- && SystemClock.uptimeMillis() - mFirstTapEvent.getEventTime() < mDoubleTapTimeout;
+ return mFirstTapDetected;
}
}
diff --git a/services/core/java/com/android/server/GestureLauncherService.java b/services/core/java/com/android/server/GestureLauncherService.java
index 7c85001..f245985 100644
--- a/services/core/java/com/android/server/GestureLauncherService.java
+++ b/services/core/java/com/android/server/GestureLauncherService.java
@@ -17,6 +17,7 @@
package com.android.server;
import android.app.ActivityManager;
+import android.app.StatusBarManager;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
@@ -263,7 +264,8 @@
}
if (launched) {
Slog.i(TAG, "Power button double tap gesture detected, launching camera.");
- launched = handleCameraLaunchGesture(false /* useWakelock */);
+ launched = handleCameraLaunchGesture(false /* useWakelock */,
+ StatusBarManager.CAMERA_LAUNCH_SOURCE_POWER_DOUBLE_TAP);
if (launched) {
MetricsLogger.action(mContext, MetricsLogger.ACTION_DOUBLE_TAP_POWER_CAMERA_GESTURE,
(int) doubleTapInterval);
@@ -276,7 +278,7 @@
/**
* @return true if camera was launched, false otherwise.
*/
- private boolean handleCameraLaunchGesture(boolean useWakelock) {
+ private boolean handleCameraLaunchGesture(boolean useWakelock, int source) {
boolean userSetupComplete = Settings.Secure.getInt(mContext.getContentResolver(),
Settings.Secure.USER_SETUP_COMPLETE, 0) != 0;
if (!userSetupComplete) {
@@ -295,7 +297,7 @@
}
StatusBarManagerInternal service = LocalServices.getService(
StatusBarManagerInternal.class);
- service.onCameraLaunchGestureDetected();
+ service.onCameraLaunchGestureDetected(source);
return true;
}
@@ -334,7 +336,8 @@
Slog.d(TAG, String.format("Received a camera launch event: " +
"values=[%.4f, %.4f, %.4f].", values[0], values[1], values[2]));
}
- if (handleCameraLaunchGesture(true /* useWakelock */)) {
+ if (handleCameraLaunchGesture(true /* useWakelock */,
+ StatusBarManager.CAMERA_LAUNCH_SOURCE_WIGGLE)) {
MetricsLogger.action(mContext, MetricsLogger.ACTION_WIGGLE_CAMERA_GESTURE);
trackCameraLaunchEvent(event);
}
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 07a7af4..bd10c63 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -994,6 +994,8 @@
*/
int mConfigurationSeq = 0;
+ boolean mSuppressResizeConfigChanges = false;
+
/**
* Hardware-reported OpenGLES version.
*/
@@ -17515,6 +17517,15 @@
}
@Override
+ public void suppressResizeConfigChanges(boolean suppress) throws RemoteException {
+ enforceCallingPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS,
+ "suppressResizeConfigChanges()");
+ synchronized (this) {
+ mSuppressResizeConfigChanges = suppress;
+ }
+ }
+
+ @Override
public void updatePersistentConfiguration(Configuration values) {
enforceCallingPermission(android.Manifest.permission.CHANGE_CONFIGURATION,
"updateConfiguration()");
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index 9809c2e..5d106dc 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -4181,8 +4181,12 @@
| ActivityInfo.CONFIG_SMALLEST_SCREEN_SIZE | ActivityInfo.CONFIG_ORIENTATION)) == 0;
}
- private boolean relaunchActivityLocked(ActivityRecord r, int changes, boolean andResume,
- boolean preserveWindow) {
+ private void relaunchActivityLocked(
+ ActivityRecord r, int changes, boolean andResume, boolean preserveWindow) {
+ if (mService.mSuppressResizeConfigChanges && preserveWindow) {
+ return;
+ }
+
List<ResultInfo> results = null;
List<ReferrerIntent> newIntents = null;
if (andResume) {
@@ -4222,8 +4226,6 @@
mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r);
r.state = ActivityState.PAUSED;
}
-
- return true;
}
boolean willActivityBeVisibleLocked(IBinder token) {
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 99ca050..e49a7e4 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -2524,11 +2524,14 @@
}
/** @see AudioManager#setBluetoothScoOn(boolean) */
- public void setBluetoothScoOn(boolean on){
+ public void setBluetoothScoOn(boolean on) {
if (!checkAudioSettingsPermission("setBluetoothScoOn()")) {
return;
}
+ setBluetoothScoOnInt(on);
+ }
+ public void setBluetoothScoOnInt(boolean on) {
if (on) {
mForcedUseForComm = AudioSystem.FORCE_BT_SCO;
} else if (mForcedUseForComm == AudioSystem.FORCE_BT_SCO) {
@@ -2889,6 +2892,8 @@
mScoAudioState = SCO_STATE_INACTIVE;
broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
}
+ AudioSystem.setParameters("A2dpSuspended=false");
+ setBluetoothScoOnInt(false);
}
private void broadcastScoConnectionState(int state) {
diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java
index 533f425..452378f 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController.java
@@ -837,7 +837,6 @@
if (mPendingScreenOff && target != Display.STATE_OFF) {
setScreenState(Display.STATE_OFF);
mPendingScreenOff = false;
- mPowerState.dismissColorFade();
}
if (target == Display.STATE_ON) {
@@ -911,7 +910,6 @@
// A black surface is already hiding the contents of the screen.
setScreenState(Display.STATE_OFF);
mPendingScreenOff = false;
- mPowerState.dismissColorFade();
} else if (performScreenOffTransition
&& mPowerState.prepareColorFade(mContext,
mColorFadeFadesConfig ?
diff --git a/services/core/java/com/android/server/display/LocalDisplayAdapter.java b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
index be37f52..088d96e 100644
--- a/services/core/java/com/android/server/display/LocalDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
@@ -544,7 +544,7 @@
physIndex = findDisplayInfoIndexLocked(colorTransformId, modeId);
}
}
- if (physIndex > 0 && mActivePhysIndex == physIndex) {
+ if (mActivePhysIndex == physIndex) {
return;
}
SurfaceControl.setActiveConfig(getDisplayTokenLocked(), physIndex);
diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java b/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java
index 5d01931..25d646d 100644
--- a/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java
@@ -28,5 +28,5 @@
void showScreenPinningRequest();
void showAssistDisclosure();
void startAssist(Bundle args);
- void onCameraLaunchGestureDetected();
+ void onCameraLaunchGestureDetected(int source);
}
diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
index 11a1639..19b03d5 100644
--- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
@@ -178,10 +178,10 @@
}
@Override
- public void onCameraLaunchGestureDetected() {
+ public void onCameraLaunchGestureDetected(int source) {
if (mBar != null) {
try {
- mBar.onCameraLaunchGestureDetected();
+ mBar.onCameraLaunchGestureDetected(source);
} catch (RemoteException e) {
}
}
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 4392ab4..ede377d 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -22,6 +22,7 @@
import static com.android.server.wm.WindowManagerService.DEBUG_VISIBILITY;
import static com.android.server.wm.WindowManagerService.TAG;
import static com.android.server.wm.WindowState.RESIZE_HANDLE_WIDTH_IN_DP;
+import static com.android.server.wm.WindowState.BOUNDS_FOR_TOUCH;
import android.graphics.Rect;
import android.graphics.Region;
@@ -255,10 +256,10 @@
}
/**
- * Find the id of the task whose outside touch area (for resizing) (x, y)
- * falls within. Returns -1 if the touch doesn't fall into a resizing area.
+ * Find the window whose outside touch area (for resizing) (x, y) falls within.
+ * Returns null if the touch doesn't fall into a resizing area.
*/
- int taskIdForControlPoint(int x, int y) {
+ WindowState findWindowForControlPoint(int x, int y) {
final int delta = mService.dipToPixel(RESIZE_HANDLE_WIDTH_IN_DP, mDisplayMetrics);
for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
TaskStack stack = mStacks.get(stackNdx);
@@ -269,22 +270,31 @@
for (int taskNdx = tasks.size() - 1; taskNdx >= 0; --taskNdx) {
final Task task = tasks.get(taskNdx);
if (task.isFullscreen()) {
- return -1;
+ return null;
}
- task.getBounds(mTmpRect);
- mTmpRect.inset(-delta, -delta);
- if (mTmpRect.contains(x, y)) {
- mTmpRect.inset(delta, delta);
- if (!mTmpRect.contains(x, y)) {
- return task.mTaskId;
+
+ // We need to use the visible frame on the window for any touch-related
+ // tests. Can't use the task's bounds because the original task bounds
+ // might be adjusted to fit the content frame. (One example is when the
+ // task is put to top-left quadrant, the actual visible frame would not
+ // start at (0,0) after it's adjusted for the status bar.)
+ WindowState win = task.getTopAppMainWindow();
+ if (win != null) {
+ win.getVisibleBounds(mTmpRect, !BOUNDS_FOR_TOUCH);
+ mTmpRect.inset(-delta, -delta);
+ if (mTmpRect.contains(x, y)) {
+ mTmpRect.inset(delta, delta);
+ if (!mTmpRect.contains(x, y)) {
+ return win;
+ }
+ // User touched inside the task. No need to look further,
+ // focus transfer will be handled in ACTION_UP.
+ return null;
}
- // User touched inside the task. No need to look further,
- // focus transfer will be handled in ACTION_UP.
- return -1;
}
}
}
- return -1;
+ return null;
}
void setTouchExcludeRegion(Task focusedTask) {
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 6ebff42..d1111f7 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -437,6 +437,11 @@
return mStack != null && mStack.mStackId == DOCKED_STACK_ID;
}
+ WindowState getTopAppMainWindow() {
+ final int tokensCount = mAppTokens.size();
+ return tokensCount > 0 ? mAppTokens.get(tokensCount - 1).findMainWindow() : null;
+ }
+
@Override
public boolean isFullscreen() {
return mFullscreen;
diff --git a/services/core/java/com/android/server/wm/TaskPositioner.java b/services/core/java/com/android/server/wm/TaskPositioner.java
index 9557d121..d1904d8 100644
--- a/services/core/java/com/android/server/wm/TaskPositioner.java
+++ b/services/core/java/com/android/server/wm/TaskPositioner.java
@@ -35,12 +35,13 @@
import android.os.RemoteException;
import android.util.DisplayMetrics;
import android.util.Slog;
+import android.view.Choreographer;
import android.view.Display;
import android.view.DisplayInfo;
import android.view.InputChannel;
import android.view.InputDevice;
import android.view.InputEvent;
-import android.view.InputEventReceiver;
+import android.view.BatchedInputEventReceiver;
import android.view.MotionEvent;
import android.view.SurfaceControl;
import android.view.WindowManager;
@@ -103,9 +104,10 @@
InputApplicationHandle mDragApplicationHandle;
InputWindowHandle mDragWindowHandle;
- private final class WindowPositionerEventReceiver extends InputEventReceiver {
- public WindowPositionerEventReceiver(InputChannel inputChannel, Looper looper) {
- super(inputChannel, looper);
+ private final class WindowPositionerEventReceiver extends BatchedInputEventReceiver {
+ public WindowPositionerEventReceiver(
+ InputChannel inputChannel, Looper looper, Choreographer choreographer) {
+ super(inputChannel, looper, choreographer);
}
@Override
@@ -222,8 +224,8 @@
mClientChannel = channels[1];
mService.mInputManager.registerInputChannel(mServerChannel, null);
- mInputEventReceiver = new WindowPositionerEventReceiver(mClientChannel,
- mService.mH.getLooper());
+ mInputEventReceiver = new WindowPositionerEventReceiver(
+ mClientChannel, mService.mH.getLooper(), mService.mChoreographer);
mDragApplicationHandle = new InputApplicationHandle(null);
mDragApplicationHandle.name = TAG;
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index d510c4a..22f9f50 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -6885,37 +6885,29 @@
}
boolean startMovingTask(IWindow window, float startX, float startY) {
- WindowState callingWin = null;
+ WindowState win = null;
synchronized (mWindowMap) {
- callingWin = windowForClientLocked(null, window, false);
- if (!startPositioningLocked(callingWin, false /*resize*/, startX, startY)) {
+ win = windowForClientLocked(null, window, false);
+ if (!startPositioningLocked(win, false /*resize*/, startX, startY)) {
return false;
}
}
try {
- mActivityManager.setFocusedTask(callingWin.getTask().mTaskId);
+ mActivityManager.setFocusedTask(win.getTask().mTaskId);
} catch(RemoteException e) {}
return true;
}
private void startResizingTask(DisplayContent displayContent, int startX, int startY) {
- int taskId = -1;
- AppWindowToken atoken = null;
+ WindowState win = null;
synchronized (mWindowMap) {
- taskId = displayContent.taskIdForControlPoint(startX, startY);
- Task task = mTaskIdToTask.get(taskId);
- if (task == null || task.mAppTokens == null) {
- return;
- }
- AppTokenList tokens = task.mAppTokens;
- atoken = tokens.get(tokens.size() - 1);
- WindowState win = atoken.findMainWindow();
+ win = displayContent.findWindowForControlPoint(startX, startY);
if (!startPositioningLocked(win, true /*resize*/, startX, startY)) {
return;
}
}
try {
- mActivityManager.setFocusedTask(taskId);
+ mActivityManager.setFocusedTask(win.getTask().mTaskId);
} catch(RemoteException e) {}
}
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 64440d3..c73dbaf 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -943,7 +943,6 @@
*/
void getVisibleBounds(Rect bounds, boolean forTouch) {
boolean intersectWithStackBounds = mAppToken != null && mAppToken.mCropWindowsToStack;
- boolean isFreeform = false;
bounds.setEmpty();
mTmpRect.setEmpty();
if (intersectWithStackBounds) {
@@ -955,13 +954,9 @@
}
}
- final Task task = getTask();
- if (task != null) {
- task.getBounds(bounds);
- isFreeform = task.inFreeformWorkspace();
- if (intersectWithStackBounds) {
- bounds.intersect(mTmpRect);
- }
+ bounds.set(mVisibleFrame);
+ if (intersectWithStackBounds) {
+ bounds.intersect(mTmpRect);
}
if (bounds.isEmpty()) {
@@ -971,7 +966,7 @@
}
return;
}
- if (forTouch && isFreeform) {
+ if (forTouch && inFreeformWorkspace()) {
final DisplayMetrics displayMetrics = getDisplayContent().getDisplayMetrics();
final int delta = mService.dipToPixel(RESIZE_HANDLE_WIDTH_IN_DP, displayMetrics);
bounds.inset(-delta, -delta);
diff --git a/services/net/java/android/net/dhcp/DhcpClient.java b/services/net/java/android/net/dhcp/DhcpClient.java
index 9ee9cf4..e0d2ac1 100644
--- a/services/net/java/android/net/dhcp/DhcpClient.java
+++ b/services/net/java/android/net/dhcp/DhcpClient.java
@@ -244,8 +244,9 @@
private PendingIntent createStateMachineCommandIntent(final String cmdName, final int cmd) {
String action = DhcpClient.class.getName() + "." + mIfaceName + "." + cmdName;
- Intent intent = new Intent(action, null)
- .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
+ Intent intent = new Intent(action, null).addFlags(
+ Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT |
+ Intent.FLAG_RECEIVER_FOREGROUND);
// TODO: The intent's package covers the whole of the system server, so it's pretty generic.
// Consider adding some sort of token as well.
intent.setPackage(mContext.getPackageName());
diff --git a/tests/CameraPrewarmTest/src/com/google/android/test/cameraprewarm/CameraActivity.java b/tests/CameraPrewarmTest/src/com/google/android/test/cameraprewarm/CameraActivity.java
index 0b43666..8085db7 100644
--- a/tests/CameraPrewarmTest/src/com/google/android/test/cameraprewarm/CameraActivity.java
+++ b/tests/CameraPrewarmTest/src/com/google/android/test/cameraprewarm/CameraActivity.java
@@ -31,5 +31,7 @@
super.onCreate(savedInstanceState);
setContentView(R.layout.camera_activity);
Log.i(TAG, "Activity created");
+ Log.i(TAG, "Source: "
+ + getIntent().getStringExtra("com.android.systemui.camera_launch_source"));
}
}
diff --git a/tests/CameraPrewarmTest/src/com/google/android/test/cameraprewarm/SecureCameraActivity.java b/tests/CameraPrewarmTest/src/com/google/android/test/cameraprewarm/SecureCameraActivity.java
index 530fe00..242d3b2 100644
--- a/tests/CameraPrewarmTest/src/com/google/android/test/cameraprewarm/SecureCameraActivity.java
+++ b/tests/CameraPrewarmTest/src/com/google/android/test/cameraprewarm/SecureCameraActivity.java
@@ -17,6 +17,7 @@
package com.google.android.test.cameraprewarm;
import android.app.Activity;
+import android.graphics.Camera;
import android.os.Bundle;
import android.util.Log;
import android.view.WindowManager;
@@ -31,5 +32,7 @@
setContentView(R.layout.camera_activity);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED);
Log.i(CameraActivity.TAG, "Activity created");
+ Log.i(CameraActivity.TAG, "Source: "
+ + getIntent().getStringExtra("com.android.systemui.camera_launch_source"));
}
}