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();
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();
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();
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();
}
/**
- * 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);
mLastWasImTarget = imTarget;
InputMethodManager imm = InputMethodManager.peekInstance();
if (imm != null && imTarget) {
+ imm.startGettingWindowFocus(mView);
imm.onWindowFocus(mView, mView.findFocus(),
mWindowAttributes.softInputMode,
!mHasHadWindowFocus, mWindowAttributes.flags);
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);
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.
* 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);
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;
}
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);
+ }
}
}
}
}
}
+ /** @hide */
+ public void startGettingWindowFocus(View rootView) {
+ synchronized (mH) {
+ mCurRootView = rootView;
+ }
+ }
+
/**
* Report the current selection range.
*
+ " mBindSequence=" + mBindSequence
+ " mCurId=" + mCurId);
p.println(" mCurMethod=" + mCurMethod);
+ p.println(" mCurRootView=" + mCurRootView);
p.println(" mServedView=" + mServedView);
p.println(" mNextServedView=" + mNextServedView);
p.println(" mServedConnecting=" + mServedConnecting);
}
public void showSoftInput() {
+ mInput.startGettingWindowFocus(mEditText.getRootView());
mInput.focusIn(mEditText);
mInput.showSoftInput(mEditText, 0);
}
// 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
mTextView.removeCallbacks(mShowSuggestionRunnable);
}
+ // Cancel the single tap delayed runnable.
+ if (mSelectionModeWithoutSelectionRunnable != null) {
+ mTextView.removeCallbacks(mSelectionModeWithoutSelectionRunnable);
+ }
+
destroyDisplayListsData();
if (mSpellChecker != null) {
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();
// 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;
// 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;
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);
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;
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);
</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">
--- /dev/null
+/*
+ * 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;
+ }
+ }
+}
/*
- * 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));
+ }
}
}
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;
}
switch (dt) {
// Support only primitive integer/float/boolean types as vectors.
+ case FLOAT_16:
case FLOAT_32:
case FLOAT_64:
case SIGNED_8:
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;
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" : "";
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;
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();
}
void startLockTaskModeLocked(TaskRecord task) {
+ if (DEBUG_LOCKTASK) Slog.w(TAG_LOCKTASK, "startLockTaskModeLocked: " + task);
if (task.mLockTaskAuth == LOCK_TASK_AUTH_DONT_LOCK) {
return;
}
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) {
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,
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.List;
import java.util.Set;
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;
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;
}
}
+ 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);
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) {
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;
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;
}
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);
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();
}
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";
/** 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;
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;
/**
* 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,
* 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() {}
}
* 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;