OSDN Git Service

Merge "Avoid sealed check when unparceling AccessibilityNodeInfo" into mnc-dev
authorAlan Viverette <alanv@google.com>
Thu, 14 May 2015 20:20:47 +0000 (20:20 +0000)
committerAndroid (Google) Code Review <android-gerrit@google.com>
Thu, 14 May 2015 20:20:48 +0000 (20:20 +0000)
19 files changed:
api/current.txt
api/system-current.txt
core/java/android/os/StrictMode.java
core/java/android/view/ViewRootImpl.java
core/java/android/view/inputmethod/InputMethodManager.java
core/java/android/webkit/FindActionModeCallback.java
core/java/android/widget/Editor.java
core/java/android/widget/TextView.java
core/tests/coretests/AndroidManifest.xml
core/tests/coretests/src/com/android/internal/policy/PhoneWindowActionModeTest.java [new file with mode: 0644]
core/tests/coretests/src/com/android/internal/policy/PhoneWindowActionModeTestActivity.java [moved from telecomm/java/android/telecom/IConferenceable.java with 51% similarity]
rs/java/android/renderscript/Element.java
services/core/java/com/android/server/am/ActivityManagerDebugConfig.java
services/core/java/com/android/server/am/ActivityManagerService.java
services/core/java/com/android/server/am/ActivityStackSupervisor.java
services/core/java/com/android/server/am/TaskRecord.java
telecomm/java/android/telecom/Conference.java
telecomm/java/android/telecom/Conferenceable.java
telecomm/java/android/telecom/Connection.java

index dcce5f4..fbb6554 100644 (file)
@@ -30051,7 +30051,7 @@ package android.telecom {
     field public static final int ROUTE_WIRED_OR_EARPIECE = 5; // 0x5
   }
 
-  public abstract class Conference implements android.telecom.Conferenceable {
+  public abstract class Conference extends android.telecom.Conferenceable {
     ctor public Conference(android.telecom.PhoneAccountHandle);
     method public final boolean addConnection(android.telecom.Connection);
     method public final void destroy();
@@ -30090,10 +30090,10 @@ package android.telecom {
     field public static final long CONNECT_TIME_NOT_SPECIFIED = 0L; // 0x0L
   }
 
-  public abstract interface Conferenceable {
+  public abstract class Conferenceable {
   }
 
-  public abstract class Connection implements android.telecom.Conferenceable {
+  public abstract class Connection extends android.telecom.Conferenceable {
     ctor public Connection();
     method public static java.lang.String capabilitiesToString(int);
     method public static android.telecom.Connection createCanceledConnection();
index d0ce53a..07fb2d7 100644 (file)
@@ -32204,7 +32204,7 @@ package android.telecom {
     field public static final int ROUTE_WIRED_OR_EARPIECE = 5; // 0x5
   }
 
-  public abstract class Conference implements android.telecom.Conferenceable {
+  public abstract class Conference extends android.telecom.Conferenceable {
     ctor public Conference(android.telecom.PhoneAccountHandle);
     method public final boolean addConnection(android.telecom.Connection);
     method public final void destroy();
@@ -32248,10 +32248,10 @@ package android.telecom {
     field public static final long CONNECT_TIME_NOT_SPECIFIED = 0L; // 0x0L
   }
 
-  public abstract interface Conferenceable {
+  public abstract class Conferenceable {
   }
 
-  public abstract class Connection implements android.telecom.Conferenceable {
+  public abstract class Connection extends android.telecom.Conferenceable {
     ctor public Connection();
     method public static java.lang.String capabilitiesToString(int);
     method public static android.telecom.Connection createCanceledConnection();
index 0b55998..1cc2d33 100644 (file)
@@ -476,8 +476,18 @@ public final class StrictMode {
             }
 
             /**
-             * Enable detection of mismatches between defined resource types
+             * Enables detection of mismatches between defined resource types
              * and getter calls.
+             * <p>
+             * This helps detect accidental type mismatches and potentially
+             * expensive type conversions when obtaining typed resources.
+             * <p>
+             * For example, a strict mode violation would be thrown when
+             * calling {@link android.content.res.TypedArray#getInt(int, int)}
+             * on an index that contains a String-type resource. If the string
+             * value can be parsed as an integer, this method call will return
+             * a value without crashing; however, the developer should format
+             * the resource as an integer to avoid unnecessary type conversion.
              */
             public Builder detectResourceMismatches() {
                 return enable(DETECT_RESOURCE_MISMATCH);
index 1cbd886..4f2a3fa 100644 (file)
@@ -2015,6 +2015,7 @@ public final class ViewRootImpl implements ViewParent,
                 mLastWasImTarget = imTarget;
                 InputMethodManager imm = InputMethodManager.peekInstance();
                 if (imm != null && imTarget) {
+                    imm.startGettingWindowFocus(mView);
                     imm.onWindowFocus(mView, mView.findFocus(),
                             mWindowAttributes.softInputMode,
                             !mHasHadWindowFocus, mWindowAttributes.flags);
@@ -3321,6 +3322,10 @@ public final class ViewRootImpl implements ViewParent,
 
                     InputMethodManager imm = InputMethodManager.peekInstance();
                     if (mView != null) {
+                        if (hasWindowFocus && imm != null && mLastWasImTarget &&
+                                !isInLocalFocusMode()) {
+                            imm.startGettingWindowFocus(mView);
+                        }
                         mAttachInfo.mKeyDispatchState.reset();
                         mView.dispatchWindowFocusChanged(hasWindowFocus);
                         mAttachInfo.mTreeObserver.dispatchOnWindowFocusChange(hasWindowFocus);
index 1fb791c..568e160 100644 (file)
@@ -281,7 +281,12 @@ public final class InputMethodManager {
     boolean mFullscreenMode;
     
     // -----------------------------------------------------------
-
+    
+    /**
+     * This is the root view of the overall window that currently has input
+     * method focus.
+     */
+    View mCurRootView;
     /**
      * This is the view that should currently be served by an input method,
      * regardless of the state of setting that up.
@@ -801,6 +806,7 @@ public final class InputMethodManager {
      * Disconnect any existing input connection, clearing the served view.
      */
     void finishInputLocked() {
+        mCurRootView = null;
         mNextServedView = null;
         if (mServedView != null) {
             if (DEBUG) Log.v(TAG, "FINISH INPUT: " + mServedView);
@@ -1284,9 +1290,10 @@ public final class InputMethodManager {
     void focusInLocked(View view) {
         if (DEBUG) Log.v(TAG, "focusIn: " + view);
         
-        if (!view.hasWindowFocus()) {
-            // This is a request from a window that doesn't have window focus, so ignore it.
-            if (DEBUG) Log.v(TAG, "Not focused window, ignoring");
+        if (mCurRootView != view.getRootView()) {
+            // This is a request from a window that isn't in the window with
+            // IME focus, so ignore it.
+            if (DEBUG) Log.v(TAG, "Not IME target window, ignoring");
             return;
         }
         
@@ -1303,9 +1310,16 @@ public final class InputMethodManager {
             if (DEBUG) Log.v(TAG, "focusOut: " + view
                     + " mServedView=" + mServedView
                     + " winFocus=" + view.hasWindowFocus());
-            if (mServedView == view && view.hasWindowFocus()) {
-                mNextServedView = null;
-                scheduleCheckFocusLocked(view);
+            if (mServedView != view) {
+                // The following code would auto-hide the IME if we end up
+                // with no more views with focus.  This can happen, however,
+                // whenever we go into touch mode, so it ends up hiding
+                // at times when we don't really want it to.  For now it
+                // seems better to just turn it all off.
+                if (false && view.hasWindowFocus()) {
+                    mNextServedView = null;
+                    scheduleCheckFocusLocked(view);
+                }
             }
         }
     }
@@ -1428,6 +1442,13 @@ public final class InputMethodManager {
         }
     }
     
+    /** @hide */
+    public void startGettingWindowFocus(View rootView) {
+        synchronized (mH) {
+            mCurRootView = rootView;
+        }
+    }
+    
     /**
      * Report the current selection range.
      *
@@ -2135,6 +2156,7 @@ public final class InputMethodManager {
                 + " mBindSequence=" + mBindSequence
                 + " mCurId=" + mCurId);
         p.println("  mCurMethod=" + mCurMethod);
+        p.println("  mCurRootView=" + mCurRootView);
         p.println("  mServedView=" + mServedView);
         p.println("  mNextServedView=" + mNextServedView);
         p.println("  mServedConnecting=" + mServedConnecting);
index 6fef2d6..ab6a2f9 100644 (file)
@@ -154,6 +154,7 @@ public class FindActionModeCallback implements ActionMode.Callback, TextWatcher,
     }
 
     public void showSoftInput() {
+        mInput.startGettingWindowFocus(mEditText.getRootView());
         mInput.focusIn(mEditText);
         mInput.showSoftInput(mEditText, 0);
     }
index 5e33f83..a1194f7 100644 (file)
@@ -209,6 +209,10 @@ public class Editor {
     // Set when this TextView gained focus with some text selected. Will start selection mode.
     boolean mCreatedWithASelection;
 
+    boolean mDoubleTap = false;
+
+    private Runnable mSelectionModeWithoutSelectionRunnable;
+
     // The span controller helps monitoring the changes to which the Editor needs to react:
     // - EasyEditSpans, for which we have some UI to display on attach and on hide
     // - SelectionSpans, for which we need to call updateSelection if an IME is attached
@@ -349,6 +353,11 @@ public class Editor {
             mTextView.removeCallbacks(mShowSuggestionRunnable);
         }
 
+        // Cancel the single tap delayed runnable.
+        if (mSelectionModeWithoutSelectionRunnable != null) {
+            mTextView.removeCallbacks(mSelectionModeWithoutSelectionRunnable);
+        }
+
         destroyDisplayListsData();
 
         if (mSpellChecker != null) {
@@ -3722,10 +3731,28 @@ public class Editor {
         public void show() {
             super.show();
 
-            final long durationSinceLastCutCopyOrTextChanged =
+            final long durationSinceCutOrCopy =
                     SystemClock.uptimeMillis() - TextView.sLastCutCopyOrTextChangedTime;
-            if (durationSinceLastCutCopyOrTextChanged < RECENT_CUT_COPY_DURATION) {
-                startSelectionActionModeWithoutSelection();
+
+            // Cancel the single tap delayed runnable.
+            if (mDoubleTap && mSelectionModeWithoutSelectionRunnable != null) {
+                mTextView.removeCallbacks(mSelectionModeWithoutSelectionRunnable);
+            }
+
+            // Prepare and schedule the single tap runnable to run exactly after the double tap
+            // timeout has passed.
+            if (!mDoubleTap && (durationSinceCutOrCopy < RECENT_CUT_COPY_DURATION)) {
+                if (mSelectionModeWithoutSelectionRunnable == null) {
+                    mSelectionModeWithoutSelectionRunnable = new Runnable() {
+                        public void run() {
+                            startSelectionActionModeWithoutSelection();
+                        }
+                    };
+                }
+
+                mTextView.postDelayed(
+                        mSelectionModeWithoutSelectionRunnable,
+                        ViewConfiguration.getDoubleTapTimeout() + 1);
             }
 
             hideAfterDelay();
@@ -4159,8 +4186,6 @@ public class Editor {
         // The offsets of that last touch down event. Remembered to start selection there.
         private int mMinTouchOffset, mMaxTouchOffset;
 
-        // Double tap detection
-        private long mPreviousTapUpTime = 0;
         private float mDownPositionX, mDownPositionY;
         private boolean mGestureStayedInTapRegion;
 
@@ -4242,8 +4267,7 @@ public class Editor {
 
                     // Double tap detection
                     if (mGestureStayedInTapRegion) {
-                        long duration = SystemClock.uptimeMillis() - mPreviousTapUpTime;
-                        if (duration <= ViewConfiguration.getDoubleTapTimeout()) {
+                        if (mDoubleTap) {
                             final float deltaX = x - mDownPositionX;
                             final float deltaY = y - mDownPositionY;
                             final float distanceSquared = deltaX * deltaX + deltaY * deltaY;
@@ -4352,7 +4376,6 @@ public class Editor {
                     break;
 
                 case MotionEvent.ACTION_UP:
-                    mPreviousTapUpTime = SystemClock.uptimeMillis();
                     if (mDragAcceleratorActive) {
                         // No longer dragging to select text, let the parent intercept events.
                         mTextView.getParent().requestDisallowInterceptTouchEvent(false);
index 3df218e..5acd79f 100644 (file)
@@ -599,6 +599,9 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
     private final Paint mHighlightPaint;
     private boolean mHighlightPathBogus = true;
 
+    private boolean mFirstTouch = false;
+    private long mLastTouchUpTime = 0;
+
     // Although these fields are specific to editable text, they are not added to Editor because
     // they are defined by the TextView's style and are theme-dependent.
     int mCursorDrawableRes;
@@ -8279,6 +8282,22 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
     public boolean onTouchEvent(MotionEvent event) {
         final int action = event.getActionMasked();
 
+        if (mEditor != null && action == MotionEvent.ACTION_DOWN) {
+            // Detect double tap and inform the Editor.
+            if (mFirstTouch && (SystemClock.uptimeMillis() - mLastTouchUpTime) <=
+                    ViewConfiguration.getDoubleTapTimeout()) {
+                mEditor.mDoubleTap = true;
+                mFirstTouch = false;
+            } else {
+                mEditor.mDoubleTap = false;
+                mFirstTouch = true;
+            }
+        }
+
+        if (action == MotionEvent.ACTION_UP) {
+            mLastTouchUpTime = SystemClock.uptimeMillis();
+        }
+
         if (mEditor != null) {
             mEditor.onTouchEvent(event);
 
index 1043b6f..263ea62 100644 (file)
         </activity>
         <activity android:name="com.android.internal.app.WindowDecorActionBarTestActivity">
         </activity>
+        <activity android:name="com.android.internal.policy.PhoneWindowActionModeTestActivity">
+        </activity>
 
         <receiver android:name="android.app.activity.AbortReceiver">
             <intent-filter android:priority="1">
diff --git a/core/tests/coretests/src/com/android/internal/policy/PhoneWindowActionModeTest.java b/core/tests/coretests/src/com/android/internal/policy/PhoneWindowActionModeTest.java
new file mode 100644 (file)
index 0000000..b860c20
--- /dev/null
@@ -0,0 +1,372 @@
+/*
+ * 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 com.android.internal.policy;
+
+import android.test.ActivityInstrumentationTestCase2;
+import android.test.UiThreadTest;
+import android.view.ActionMode;
+import android.view.ActionMode.Callback;
+import android.view.KeyEvent;
+import android.view.Menu;
+import android.view.MenuInflater;
+import android.view.MenuItem;
+import android.view.MotionEvent;
+import android.view.SearchEvent;
+import android.view.View;
+import android.view.Window;
+import android.view.WindowManager.LayoutParams;
+import android.view.accessibility.AccessibilityEvent;
+
+/**
+ * Tests {@link PhoneWindow}'s {@link ActionMode} related methods.
+ */
+public final class PhoneWindowActionModeTest
+        extends ActivityInstrumentationTestCase2<PhoneWindowActionModeTestActivity> {
+
+    private PhoneWindow mPhoneWindow;
+    private MockWindowCallback mWindowCallback;
+    private MockActionModeCallback mActionModeCallback;
+
+    public PhoneWindowActionModeTest() {
+        super(PhoneWindowActionModeTestActivity.class);
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        mPhoneWindow = (PhoneWindow) getActivity().getWindow();
+        mWindowCallback = new MockWindowCallback();
+        mPhoneWindow.setCallback(mWindowCallback);
+        mActionModeCallback = new MockActionModeCallback();
+    }
+
+    public void testStartActionModeWithCallback() {
+        mWindowCallback.mShouldReturnOwnActionMode = true;
+
+        ActionMode mode = mPhoneWindow.getDecorView().startActionMode(
+                mActionModeCallback, ActionMode.TYPE_FLOATING);
+
+        assertEquals(mWindowCallback.mLastCreatedActionMode, mode);
+    }
+
+    public void testStartActionModePrimaryFinishesPreviousMode() {
+        // Use custom callback to control the provided ActionMode.
+        mWindowCallback.mShouldReturnOwnActionMode = true;
+
+        ActionMode mode1 = mPhoneWindow.getDecorView().startActionMode(
+                mActionModeCallback, ActionMode.TYPE_PRIMARY);
+        ActionMode mode2 = mPhoneWindow.getDecorView().startActionMode(
+                mActionModeCallback, ActionMode.TYPE_PRIMARY);
+
+        assertTrue(mode1 instanceof MockActionMode);
+        assertTrue(((MockActionMode) mode1).mIsFinished);
+        assertNotNull(mode2);
+    }
+
+    public void testStartActionModeFloatingFinishesPreviousMode() {
+        // Use custom callback to control the provided ActionMode.
+        mWindowCallback.mShouldReturnOwnActionMode = true;
+
+        ActionMode mode1 = mPhoneWindow.getDecorView().startActionMode(
+                mActionModeCallback, ActionMode.TYPE_FLOATING);
+        ActionMode mode2 = mPhoneWindow.getDecorView().startActionMode(
+                mActionModeCallback, ActionMode.TYPE_FLOATING);
+
+        assertTrue(mode1 instanceof MockActionMode);
+        assertTrue(((MockActionMode) mode1).mIsFinished);
+        assertNotNull(mode2);
+    }
+
+    public void testStartActionModePreservesPreviousModeOfDifferentType1() {
+        // Use custom callback to control the provided ActionMode.
+        mWindowCallback.mShouldReturnOwnActionMode = true;
+
+        ActionMode mode1 = mPhoneWindow.getDecorView().startActionMode(
+                mActionModeCallback, ActionMode.TYPE_FLOATING);
+        ActionMode mode2 = mPhoneWindow.getDecorView().startActionMode(
+                mActionModeCallback, ActionMode.TYPE_PRIMARY);
+
+        assertTrue(mode1 instanceof MockActionMode);
+        assertFalse(((MockActionMode) mode1).mIsFinished);
+        assertNotNull(mode2);
+    }
+
+    public void testStartActionModePreservesPreviousModeOfDifferentType2() {
+        // Use custom callback to control the provided ActionMode.
+        mWindowCallback.mShouldReturnOwnActionMode = true;
+
+        ActionMode mode1 = mPhoneWindow.getDecorView().startActionMode(
+                mActionModeCallback, ActionMode.TYPE_PRIMARY);
+        ActionMode mode2 = mPhoneWindow.getDecorView().startActionMode(
+                mActionModeCallback, ActionMode.TYPE_FLOATING);
+
+        assertTrue(mode1 instanceof MockActionMode);
+        assertFalse(((MockActionMode) mode1).mIsFinished);
+        assertNotNull(mode2);
+    }
+
+    public void testWindowCallbackModesLifecycleIsNotHandled() {
+        mWindowCallback.mShouldReturnOwnActionMode = true;
+
+        ActionMode mode = mPhoneWindow.getDecorView().startActionMode(
+                mActionModeCallback, ActionMode.TYPE_PRIMARY);
+
+        assertNotNull(mode);
+        assertEquals(mWindowCallback.mLastCreatedActionMode, mode);
+        assertFalse(mActionModeCallback.mIsCreateActionModeCalled);
+        assertTrue(mWindowCallback.mIsActionModeStarted);
+    }
+
+    @UiThreadTest
+    public void testCreatedPrimaryModeLifecycleIsHandled() {
+        mWindowCallback.mShouldReturnOwnActionMode = false;
+
+        ActionMode mode = mPhoneWindow.getDecorView().startActionMode(
+                mActionModeCallback, ActionMode.TYPE_PRIMARY);
+
+        assertNotNull(mode);
+        assertEquals(ActionMode.TYPE_PRIMARY, mode.getType());
+        assertTrue(mActionModeCallback.mIsCreateActionModeCalled);
+        assertTrue(mWindowCallback.mIsActionModeStarted);
+    }
+
+    @UiThreadTest
+    public void testCreatedFloatingModeLifecycleIsHandled() {
+        mWindowCallback.mShouldReturnOwnActionMode = false;
+
+        ActionMode mode = mPhoneWindow.getDecorView().startActionMode(
+                mActionModeCallback, ActionMode.TYPE_FLOATING);
+
+        assertNotNull(mode);
+        assertEquals(ActionMode.TYPE_FLOATING, mode.getType());
+        assertTrue(mActionModeCallback.mIsCreateActionModeCalled);
+        assertTrue(mWindowCallback.mIsActionModeStarted);
+    }
+
+    @UiThreadTest
+    public void testCreatedModeIsNotStartedIfCreateReturnsFalse() {
+        mWindowCallback.mShouldReturnOwnActionMode = false;
+        mActionModeCallback.mShouldCreateActionMode = false;
+
+        ActionMode mode = mPhoneWindow.getDecorView().startActionMode(
+                mActionModeCallback, ActionMode.TYPE_FLOATING);
+
+        assertTrue(mActionModeCallback.mIsCreateActionModeCalled);
+        assertFalse(mWindowCallback.mIsActionModeStarted);
+        assertNull(mode);
+    }
+
+    private static final class MockWindowCallback implements Window.Callback {
+        private boolean mShouldReturnOwnActionMode = false;
+        private MockActionMode mLastCreatedActionMode;
+        private boolean mIsActionModeStarted = false;
+
+        @Override
+        public boolean dispatchKeyEvent(KeyEvent event) {
+            return false;
+        }
+
+        @Override
+        public boolean dispatchKeyShortcutEvent(KeyEvent event) {
+            return false;
+        }
+
+        @Override
+        public boolean dispatchTouchEvent(MotionEvent event) {
+            return false;
+        }
+
+        @Override
+        public boolean dispatchTrackballEvent(MotionEvent event) {
+            return false;
+        }
+
+        @Override
+        public boolean dispatchGenericMotionEvent(MotionEvent event) {
+            return false;
+        }
+
+        @Override
+        public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) {
+            return false;
+        }
+
+        @Override
+        public View onCreatePanelView(int featureId) {
+            return null;
+        }
+
+        @Override
+        public boolean onCreatePanelMenu(int featureId, Menu menu) {
+            return false;
+        }
+
+        @Override
+        public boolean onPreparePanel(int featureId, View view, Menu menu) {
+            return false;
+        }
+
+        @Override
+        public boolean onMenuOpened(int featureId, Menu menu) {
+            return false;
+        }
+
+        @Override
+        public boolean onMenuItemSelected(int featureId, MenuItem item) {
+            return false;
+        }
+
+        @Override
+        public void onWindowAttributesChanged(LayoutParams attrs) {}
+
+        @Override
+        public void onContentChanged() {}
+
+        @Override
+        public void onWindowFocusChanged(boolean hasFocus) {}
+
+        @Override
+        public void onAttachedToWindow() {}
+
+        @Override
+        public void onDetachedFromWindow() {}
+
+        @Override
+        public void onPanelClosed(int featureId, Menu menu) {}
+
+        @Override
+        public boolean onSearchRequested() {
+            return false;
+        }
+
+        @Override
+        public boolean onSearchRequested(SearchEvent searchEvent) {
+            return false;
+        }
+
+        @Override
+        public ActionMode onWindowStartingActionMode(Callback callback) {
+            if (mShouldReturnOwnActionMode) {
+                MockActionMode mode = new MockActionMode();
+                mLastCreatedActionMode = mode;
+                return mode;
+            }
+            return null;
+        }
+
+        @Override
+        public ActionMode onWindowStartingActionMode(Callback callback, int type) {
+            if (mShouldReturnOwnActionMode) {
+                MockActionMode mode = new MockActionMode();
+                mode.mActionModeType = type;
+                mLastCreatedActionMode = mode;
+                return mode;
+            }
+            return null;
+        }
+
+        @Override
+        public void onActionModeStarted(ActionMode mode) {
+            mIsActionModeStarted = true;
+        }
+
+        @Override
+        public void onActionModeFinished(ActionMode mode) {}
+    }
+
+    private static final class MockActionModeCallback implements ActionMode.Callback {
+        private boolean mShouldCreateActionMode = true;
+        private boolean mIsCreateActionModeCalled = false;
+
+        @Override
+        public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
+            return true;
+        }
+
+        @Override
+        public void onDestroyActionMode(ActionMode mode) {}
+
+        @Override
+        public boolean onCreateActionMode(ActionMode mode, Menu menu) {
+            mIsCreateActionModeCalled = true;
+            return mShouldCreateActionMode;
+        }
+
+        @Override
+        public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
+            return false;
+        }
+    }
+
+    private static final class MockActionMode extends ActionMode {
+        private int mActionModeType = ActionMode.TYPE_PRIMARY;
+        private boolean mIsFinished = false;
+
+        @Override
+        public int getType() {
+            return mActionModeType;
+        }
+
+        @Override
+        public void setTitle(CharSequence title) {}
+
+        @Override
+        public void setTitle(int resId) {}
+
+        @Override
+        public void setSubtitle(CharSequence subtitle) {}
+
+        @Override
+        public void setSubtitle(int resId) {}
+
+        @Override
+        public void setCustomView(View view) {}
+
+        @Override
+        public void invalidate() {}
+
+        @Override
+        public void finish() {
+            mIsFinished = true;
+        }
+
+        @Override
+        public Menu getMenu() {
+            return null;
+        }
+
+        @Override
+        public CharSequence getTitle() {
+            return null;
+        }
+
+        @Override
+        public CharSequence getSubtitle() {
+            return null;
+        }
+
+        @Override
+        public View getCustomView() {
+            return null;
+        }
+
+        @Override
+        public MenuInflater getMenuInflater() {
+            return null;
+        }
+    }
+}
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2014 The Android Open Source Project
+ * 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.
  * 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
+ * limitations under the License.
  */
 
-package android.telecom;
+package com.android.internal.policy;
 
-/**
- * Interface used to identify entities with which another entity can participate in a conference
- * call with.  The {@link ConnectionService} implementation will only recognize
- * {@link Conferenceable}s which are {@link Connection}s or {@link Conference}s.
- * <p>
- * @deprecated use {@link Conferenceable} instead.
- * @hide
- */
-public interface IConferenceable extends Conferenceable {
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.View;
+
+public class PhoneWindowActionModeTestActivity extends Activity {
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(new View(this));
+    }
 }
index 4b3e30f..6efb6d6 100644 (file)
@@ -536,8 +536,8 @@ public class Element extends BaseObj {
     }
 
     public static Element F16_3(RenderScript rs) {
-        if(rs.mElement_FLOAT_3 == null) {
-            rs.mElement_FLOAT_3 = createVector(rs, DataType.FLOAT_16, 3);
+        if(rs.mElement_HALF_3 == null) {
+            rs.mElement_HALF_3 = createVector(rs, DataType.FLOAT_16, 3);
         }
         return rs.mElement_HALF_3;
     }
@@ -911,6 +911,7 @@ public class Element extends BaseObj {
 
         switch (dt) {
         // Support only primitive integer/float/boolean types as vectors.
+        case FLOAT_16:
         case FLOAT_32:
         case FLOAT_64:
         case SIGNED_8:
index d64e39f..925fae0 100644 (file)
@@ -51,6 +51,7 @@ class ActivityManagerDebugConfig {
     static final boolean DEBUG_FOCUS = false;
     static final boolean DEBUG_IMMERSIVE = DEBUG_ALL || false;
     static final boolean DEBUG_LOCKSCREEN = DEBUG_ALL || false;
+    static final boolean DEBUG_LOCKTASK = DEBUG_ALL || false;
     static final boolean DEBUG_LRU = DEBUG_ALL || false;
     static final boolean DEBUG_MU = DEBUG_ALL || false;
     static final boolean DEBUG_OOM_ADJ = DEBUG_ALL || false;
@@ -82,6 +83,7 @@ class ActivityManagerDebugConfig {
     static final String POSTFIX_FOCUS = (APPEND_CATEGORY_NAME) ? "_Focus" : "";
     static final String POSTFIX_IMMERSIVE = (APPEND_CATEGORY_NAME) ? "_Immersive" : "";
     static final String POSTFIX_LOCKSCREEN = (APPEND_CATEGORY_NAME) ? "_LOCKSCREEN" : "";
+    static final String POSTFIX_LOCKTASK = (APPEND_CATEGORY_NAME) ? "_LOCKTASK" : "";
     static final String POSTFIX_LRU = (APPEND_CATEGORY_NAME) ? "_LRU" : "";
     static final String POSTFIX_MU = "_MU";
     static final String POSTFIX_OOM_ADJ = (APPEND_CATEGORY_NAME) ? "_OomAdj" : "";
index 9ffb874..2158395 100644 (file)
@@ -265,6 +265,7 @@ public final class ActivityManagerService extends ActivityManagerNative
     private static final String TAG_FOCUS = TAG + POSTFIX_FOCUS;
     private static final String TAG_IMMERSIVE = TAG + POSTFIX_IMMERSIVE;
     private static final String TAG_LOCKSCREEN = TAG + POSTFIX_LOCKSCREEN;
+    private static final String TAG_LOCKTASK = TAG + POSTFIX_LOCKTASK;
     private static final String TAG_LRU = TAG + POSTFIX_LRU;
     private static final String TAG_MU = TAG + POSTFIX_MU;
     private static final String TAG_OOM_ADJ = TAG + POSTFIX_OOM_ADJ;
@@ -8762,6 +8763,7 @@ public final class ActivityManagerService extends ActivityManagerNative
             throw new SecurityException("updateLockTaskPackage called from non-system process");
         }
         synchronized (this) {
+            if (DEBUG_LOCKTASK) Slog.w(TAG_LOCKTASK, "Whitelisting " + userId + ":" + packages);
             mLockTaskPackages.put(userId, packages);
             mStackSupervisor.onLockTaskPackagesUpdatedLocked();
         }
@@ -8769,6 +8771,7 @@ public final class ActivityManagerService extends ActivityManagerNative
 
 
     void startLockTaskModeLocked(TaskRecord task) {
+        if (DEBUG_LOCKTASK) Slog.w(TAG_LOCKTASK, "startLockTaskModeLocked: " + task);
         if (task.mLockTaskAuth == LOCK_TASK_AUTH_DONT_LOCK) {
             return;
         }
@@ -8785,6 +8788,7 @@ public final class ActivityManagerService extends ActivityManagerNative
                 task.mLockTaskUid = callingUid;
                 if (task.mLockTaskAuth == LOCK_TASK_AUTH_PINNABLE) {
                     // startLockTask() called by app and task mode is lockTaskModeDefault.
+                    if (DEBUG_LOCKTASK) Slog.w(TAG_LOCKTASK, "Mode default, asking user");
                     StatusBarManagerInternal statusBarManager =
                             LocalServices.getService(StatusBarManagerInternal.class);
                     if (statusBarManager != null) {
@@ -8797,6 +8801,8 @@ public final class ActivityManagerService extends ActivityManagerNative
                     throw new IllegalArgumentException("Invalid task, not in foreground");
                 }
             }
+            if (DEBUG_LOCKTASK) Slog.w(TAG_LOCKTASK, isSystemInitiated ? "Locking pinned" :
+                    "Locking fully");
             mStackSupervisor.setLockTaskModeLocked(task, isSystemInitiated ?
                     ActivityManager.LOCK_TASK_MODE_PINNED :
                     ActivityManager.LOCK_TASK_MODE_LOCKED,
index 54ea6d7..f304828 100644 (file)
@@ -117,6 +117,7 @@ import java.io.FileDescriptor;
 import java.io.IOException;
 import java.io.PrintWriter;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.List;
 import java.util.Set;
 
@@ -124,6 +125,7 @@ public final class ActivityStackSupervisor implements DisplayListener {
     private static final String TAG = TAG_WITH_CLASS_NAME ? "ActivityStackSupervisor" : TAG_AM;
     private static final String TAG_CONFIGURATION = TAG + POSTFIX_CONFIGURATION;
     private static final String TAG_FOCUS = TAG + POSTFIX_FOCUS;
+    private static final String TAG_LOCKTASK = TAG + POSTFIX_LOCKTASK;
     private static final String TAG_PAUSE = TAG + POSTFIX_PAUSE;
     private static final String TAG_RESULTS = TAG + POSTFIX_RESULTS;
     private static final String TAG_RECENTS = TAG + POSTFIX_RECENTS;
@@ -1183,7 +1185,7 @@ public final class ActivityStackSupervisor implements DisplayListener {
 
         final TaskRecord task = r.task;
         if (task.mLockTaskAuth == LOCK_TASK_AUTH_LAUNCHABLE) {
-            setLockTaskModeLocked(task, LOCK_TASK_MODE_LOCKED, "lockTaskLaunchMode attribute");
+            setLockTaskModeLocked(task, LOCK_TASK_MODE_LOCKED, "mLockTaskAuth==LAUNCHABLE");
         }
 
         final ActivityStack stack = task.stack;
@@ -3327,6 +3329,18 @@ public final class ActivityStackSupervisor implements DisplayListener {
         }
     }
 
+    private String lockTaskModeToString() {
+        switch (mLockTaskModeState) {
+            case LOCK_TASK_MODE_LOCKED:
+                return "LOCKED";
+            case LOCK_TASK_MODE_PINNED:
+                return "PINNED";
+            case LOCK_TASK_MODE_NONE:
+                return "NONE";
+            default: return "unknown=" + mLockTaskModeState;
+        }
+    }
+
     public void dump(PrintWriter pw, String prefix) {
         pw.print(prefix); pw.print("mFocusedStack=" + mFocusedStack);
                 pw.print(" mLastFocusedStack="); pw.println(mLastFocusedStack);
@@ -3334,7 +3348,16 @@ public final class ActivityStackSupervisor implements DisplayListener {
         pw.print(prefix); pw.println("mCurTaskId=" + mCurTaskId);
         pw.print(prefix); pw.println("mUserStackInFront=" + mUserStackInFront);
         pw.print(prefix); pw.println("mActivityContainers=" + mActivityContainers);
-        pw.print(prefix); pw.println("mLockTaskModeTasks" + mLockTaskModeTasks);
+        pw.print(prefix); pw.print("mLockTaskModeState=" + lockTaskModeToString());
+                final SparseArray<String[]> packages = mService.mLockTaskPackages;
+                if (packages.size() > 0) {
+                    pw.println(" mLockTaskPackages (userId:packages)=");
+                    for (int i = 0; i < packages.size(); ++i) {
+                        pw.print(prefix); pw.print(prefix); pw.print(packages.keyAt(i));
+                        pw.print(":"); pw.println(Arrays.toString(packages.valueAt(i)));
+                    }
+                }
+                pw.println(" mLockTaskModeTasks" + mLockTaskModeTasks);
     }
 
     ArrayList<ActivityRecord> getDumpActivitiesLocked(String name) {
@@ -3654,6 +3677,8 @@ public final class ActivityStackSupervisor implements DisplayListener {
     void removeLockedTaskLocked(final TaskRecord task) {
         if (mLockTaskModeTasks.remove(task) && mLockTaskModeTasks.isEmpty()) {
             // Last one.
+            if (DEBUG_LOCKTASK) Slog.d(TAG_LOCKTASK, "removeLockedTask: task=" + task +
+                    " last task, reverting locktask mode. Callers=" + Debug.getCallers(3));
             final Message lockTaskMsg = Message.obtain();
             lockTaskMsg.arg1 = task.userId;
             lockTaskMsg.what = LOCK_TASK_END_MSG;
@@ -3679,20 +3704,26 @@ public final class ActivityStackSupervisor implements DisplayListener {
                 removeLockedTaskLocked(lockedTask);
                 if (!mLockTaskModeTasks.isEmpty()) {
                     // There are locked tasks remaining, can only finish this task, not unlock it.
+                    if (DEBUG_LOCKTASK) Slog.w(TAG_LOCKTASK,
+                            "setLockTaskModeLocked: Tasks remaining, can't unlock");
                     lockedTask.performClearTaskLocked();
                     resumeTopActivitiesLocked();
                     return;
                 }
             }
+            if (DEBUG_LOCKTASK) Slog.w(TAG_LOCKTASK,
+                    "setLockTaskModeLocked: No tasks to unlock. Callers=" + Debug.getCallers(4));
             return;
         }
 
         // Should have already been checked, but do it again.
         if (task.mLockTaskAuth == LOCK_TASK_AUTH_DONT_LOCK) {
+            if (DEBUG_LOCKTASK) Slog.w(TAG_LOCKTASK,
+                    "setLockTaskModeLocked: Can't lock due to auth");
             return;
         }
         if (isLockTaskModeViolation(task)) {
-            Slog.e(TAG, "setLockTaskMode: Attempt to start an unauthorized lock task.");
+            Slog.e(TAG_LOCKTASK, "setLockTaskMode: Attempt to start an unauthorized lock task.");
             return;
         }
 
@@ -3706,6 +3737,8 @@ public final class ActivityStackSupervisor implements DisplayListener {
             mHandler.sendMessage(lockTaskMsg);
         }
         // Add it or move it to the top.
+        if (DEBUG_LOCKTASK) Slog.w(TAG_LOCKTASK, "setLockTaskModeLocked: Locking to " + task +
+                " Callers=" + Debug.getCallers(4));
         mLockTaskModeTasks.remove(task);
         mLockTaskModeTasks.add(task);
 
@@ -3759,6 +3792,13 @@ public final class ActivityStackSupervisor implements DisplayListener {
                 stack.onLockTaskPackagesUpdatedLocked();
             }
         }
+        final ActivityRecord r = topRunningActivityLocked();
+        final TaskRecord task = r != null ? r.task : null;
+        if (mLockTaskModeTasks.isEmpty() && task != null
+                && task.mLockTaskAuth == LOCK_TASK_AUTH_LAUNCHABLE) {
+            // This task must have just been authorized.
+            setLockTaskModeLocked(task, ActivityManager.LOCK_TASK_MODE_LOCKED, "package updated");
+        }
         if (didSomething) {
             resumeTopActivitiesLocked();
         }
index 5e9f2b0..f653e9e 100644 (file)
@@ -63,6 +63,7 @@ import java.util.ArrayList;
 final class TaskRecord {
     private static final String TAG = TAG_WITH_CLASS_NAME ? "TaskRecord" : TAG_AM;
     private static final String TAG_RECENTS = TAG + POSTFIX_RECENTS;
+    private static final String TAG_LOCKTASK = TAG + POSTFIX_LOCKTASK;
     private static final String TAG_TASKS = TAG + POSTFIX_TASKS;
 
     static final String ATTR_TASKID = "task_id";
@@ -134,12 +135,11 @@ final class TaskRecord {
 
     /** Can't be put in lockTask mode. */
     final static int LOCK_TASK_AUTH_DONT_LOCK = 0;
-    /** Can enter lockTask with user approval if not already in lockTask. */
+    /** Can enter lockTask with user approval. Can never start over existing lockTask task. */
     final static int LOCK_TASK_AUTH_PINNABLE = 1;
     /** Starts in LOCK_TASK_MODE_LOCKED automatically. Can start over existing lockTask task. */
     final static int LOCK_TASK_AUTH_LAUNCHABLE = 2;
-    /** Enters LOCK_TASK_MODE_LOCKED via startLockTask(), enters LOCK_TASK_MODE_PINNED from
-     * Overview. Can start over existing lockTask task. */
+    /** Can enter lockTask with user approval. Can start over existing lockTask task. */
     final static int LOCK_TASK_AUTH_WHITELISTED = 3;
     int mLockTaskAuth = LOCK_TASK_AUTH_PINNABLE;
 
@@ -744,21 +744,31 @@ final class TaskRecord {
     void setLockTaskAuth() {
         switch (mLockTaskMode) {
             case LOCK_TASK_LAUNCH_MODE_DEFAULT:
+                if (DEBUG_LOCKTASK) Slog.d(TAG_LOCKTASK, "setLockTaskAuth: task=" + this +
+                        " mLockTaskAuth=" + (isLockTaskWhitelistedLocked() ?
+                        "WHITELISTED" : "PINNABLE"));
                 mLockTaskAuth = isLockTaskWhitelistedLocked() ?
                     LOCK_TASK_AUTH_WHITELISTED : LOCK_TASK_AUTH_PINNABLE;
                 break;
 
             case LOCK_TASK_LAUNCH_MODE_NEVER:
+                if (DEBUG_LOCKTASK) Slog.d(TAG_LOCKTASK, "setLockTaskAuth: task=" + this +
+                        " mLockTaskAuth=" + (mPrivileged ? "DONT_LOCK" : "PINNABLE"));
                 mLockTaskAuth = mPrivileged ?
                         LOCK_TASK_AUTH_DONT_LOCK : LOCK_TASK_AUTH_PINNABLE;
                 break;
 
             case LOCK_TASK_LAUNCH_MODE_ALWAYS:
+                if (DEBUG_LOCKTASK) Slog.d(TAG_LOCKTASK, "setLockTaskAuth: task=" + this +
+                        " mLockTaskAuth=" + (mPrivileged ? "LAUNCHABLE" : "PINNABLE"));
                 mLockTaskAuth = mPrivileged ?
                         LOCK_TASK_AUTH_LAUNCHABLE: LOCK_TASK_AUTH_PINNABLE;
                 break;
 
             case LOCK_TASK_LAUNCH_MODE_IF_WHITELISTED:
+                if (DEBUG_LOCKTASK) Slog.d(TAG_LOCKTASK, "setLockTaskAuth: task=" + this +
+                        " mLockTaskAuth=" + (isLockTaskWhitelistedLocked() ?
+                        "LAUNCHABLE" : "PINNABLE"));
                 mLockTaskAuth = isLockTaskWhitelistedLocked() ?
                         LOCK_TASK_AUTH_LAUNCHABLE : LOCK_TASK_AUTH_PINNABLE;
                 break;
index d8d9ab6..dfbb67a 100644 (file)
@@ -30,7 +30,7 @@ import java.util.concurrent.CopyOnWriteArraySet;
 /**
  * Represents a conference call which can contain any number of {@link Connection} objects.
  */
-public abstract class Conference implements Conferenceable {
+public abstract class Conference extends Conferenceable {
 
     /**
      * Used to indicate that the conference connection time is not specified.  If not specified,
index 5c4cbc5..bb6f2b8 100644 (file)
@@ -21,6 +21,6 @@ package android.telecom;
  * call with.  The {@link ConnectionService} implementation will only recognize
  * {@link Conferenceable}s which are {@link Connection}s or {@link Conference}s.
  */
-public interface Conferenceable {
-
+public abstract class Conferenceable {
+    Conferenceable() {}
 }
index f39f813..fba4e6a 100644 (file)
@@ -47,7 +47,7 @@ import java.util.concurrent.ConcurrentHashMap;
  * must call {@link #destroy()} to signal to the framework that the {@code Connection} is no
  * longer used and associated resources may be recovered.
  */
-public abstract class Connection implements Conferenceable {
+public abstract class Connection extends Conferenceable {
 
     public static final int STATE_INITIALIZING = 0;