Fixing taskMenu and taskView clicks in fallback activity

> Extracting common methods from Launcher & DragLauncher to base classes
> Remoting some dependencies on Launcher and using the base class instead

Change-Id: I121cacf8a14190b4703cda60bdeb4f79eee69ded
This commit is contained in:
Sunny Goyal 2018-03-14 12:30:11 -07:00
parent 39b5534b96
commit 0b0847b272
21 changed files with 749 additions and 546 deletions

View File

@ -15,15 +15,17 @@
-->
<com.android.quickstep.RecentsRootView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/drag_layer"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.android.quickstep.FallbackRecentsView
xmlns:android="http://schemas.android.com/apk/res/android"
android:theme="@style/HomeScreenElementTheme"
android:id="@+id/overview_panel"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipChildren="false"
android:clipToPadding="false" />
android:clipToPadding="false"
android:theme="@style/HomeScreenElementTheme" />
</com.android.quickstep.RecentsRootView>

View File

@ -36,11 +36,13 @@ public class UiFactory {
public static TouchController[] createTouchControllers(Launcher launcher) {
if (FeatureFlags.ENABLE_TWO_SWIPE_TARGETS) {
return new TouchController[] {
launcher.getDragController(),
new EdgeSwipeController(launcher),
new TwoStepSwipeController(launcher),
new OverviewSwipeController(launcher)};
} else {
return new TouchController[] {
launcher.getDragController(),
new TwoStepSwipeController(launcher),
new OverviewSwipeController(launcher)};
}

View File

@ -15,17 +15,25 @@
*/
package com.android.quickstep;
import android.app.ActivityOptions;
import android.os.Bundle;
import android.view.View;
import com.android.launcher3.BaseActivity;
import com.android.launcher3.BaseDraggingActivity;
import com.android.launcher3.InvariantDeviceProfile;
import com.android.launcher3.ItemInfo;
import com.android.launcher3.LauncherAppState;
import com.android.launcher3.R;
import com.android.launcher3.badge.BadgeInfo;
import com.android.launcher3.views.BaseDragLayer;
/**
* A simple activity to show the recently launched tasks
*/
public class RecentsActivity extends BaseActivity {
public class RecentsActivity extends BaseDraggingActivity {
private RecentsRootView mRecentsRootView;
private FallbackRecentsView mFallbackRecentsView;
@Override
protected void onCreate(Bundle savedInstanceState) {
@ -39,5 +47,30 @@ public class RecentsActivity extends BaseActivity {
: new InvariantDeviceProfile(this).getDeviceProfile(this));
setContentView(R.layout.fallback_recents_activity);
mRecentsRootView = findViewById(R.id.drag_layer);
mFallbackRecentsView = findViewById(R.id.overview_panel);
}
@Override
public BaseDragLayer getDragLayer() {
return mRecentsRootView;
}
@Override
public <T extends View> T getOverviewPanel() {
return (T) mFallbackRecentsView;
}
@Override
public BadgeInfo getBadgeInfoForItem(ItemInfo info) {
return null;
}
@Override
public ActivityOptions getActivityLaunchOptions(View v, boolean useDefaultLaunchOptions) {
return null;
}
@Override
public void invalidateParent(ItemInfo info) { }
}

View File

@ -21,17 +21,19 @@ import android.graphics.Rect;
import android.util.AttributeSet;
import com.android.launcher3.BaseActivity;
import com.android.launcher3.InsettableFrameLayout;
import com.android.launcher3.R;
import com.android.launcher3.util.Themes;
import com.android.launcher3.util.TouchController;
import com.android.launcher3.views.BaseDragLayer;
public class RecentsRootView extends InsettableFrameLayout {
public class RecentsRootView extends BaseDragLayer<RecentsActivity> {
private final BaseActivity mActivity;
public RecentsRootView(Context context, AttributeSet attrs) {
super(context, attrs);
mActivity = BaseActivity.fromContext(context);
mControllers = new TouchController[0];
}
@TargetApi(23)

View File

@ -30,8 +30,8 @@ import android.view.View;
import android.view.ViewTreeObserver.OnPreDrawListener;
import com.android.launcher3.AbstractFloatingView;
import com.android.launcher3.BaseDraggingActivity;
import com.android.launcher3.ItemInfo;
import com.android.launcher3.Launcher;
import com.android.launcher3.R;
import com.android.launcher3.ShortcutInfo;
import com.android.launcher3.popup.SystemShortcut;
@ -70,11 +70,12 @@ public class TaskSystemShortcut<T extends SystemShortcut> extends SystemShortcut
}
@Override
public View.OnClickListener getOnClickListener(Launcher launcher, ItemInfo itemInfo) {
public View.OnClickListener getOnClickListener(
BaseDraggingActivity activity, ItemInfo itemInfo) {
return null;
}
public View.OnClickListener getOnClickListener(final Launcher launcher, final TaskView view) {
public View.OnClickListener getOnClickListener(BaseDraggingActivity activity, TaskView view) {
Task task = view.getTask();
ShortcutInfo dummyInfo = new ShortcutInfo();
@ -82,14 +83,14 @@ public class TaskSystemShortcut<T extends SystemShortcut> extends SystemShortcut
ComponentName component = task.getTopComponent();
dummyInfo.intent.setComponent(component);
dummyInfo.user = UserHandle.of(task.key.userId);
dummyInfo.title = TaskUtils.getTitle(launcher, task);
dummyInfo.title = TaskUtils.getTitle(activity, task);
return getOnClickListenerForTask(launcher, task, dummyInfo);
return getOnClickListenerForTask(activity, task, dummyInfo);
}
protected View.OnClickListener getOnClickListenerForTask(final Launcher launcher,
final Task task, final ItemInfo dummyInfo) {
return mSystemShortcut.getOnClickListener(launcher, dummyInfo);
protected View.OnClickListener getOnClickListenerForTask(
BaseDraggingActivity activity, Task task, ItemInfo dummyInfo) {
return mSystemShortcut.getOnClickListener(activity, dummyInfo);
}
public static class AppInfo extends TaskSystemShortcut<SystemShortcut.AppInfo> {
@ -109,8 +110,9 @@ public class TaskSystemShortcut<T extends SystemShortcut> extends SystemShortcut
}
@Override
public View.OnClickListener getOnClickListener(Launcher launcher, TaskView taskView) {
if (launcher.getDeviceProfile().isMultiWindowMode) {
public View.OnClickListener getOnClickListener(
BaseDraggingActivity activity, TaskView taskView) {
if (activity.getDeviceProfile().isMultiWindowMode) {
return null;
}
final Task task = taskView.getTask();
@ -119,12 +121,12 @@ public class TaskSystemShortcut<T extends SystemShortcut> extends SystemShortcut
}
mTaskView = taskView;
return (v -> {
AbstractFloatingView.closeOpenViews(launcher, true,
AbstractFloatingView.closeOpenViews(activity, true,
AbstractFloatingView.TYPE_ALL & ~AbstractFloatingView.TYPE_REBIND_SAFE);
if (ActivityManagerWrapper.getInstance().startActivityFromRecents(task.key.id,
ActivityOptionsCompat.makeSplitScreenOptions(true))) {
ISystemUiProxy sysUiProxy = RecentsModel.getInstance(launcher).getSystemUiProxy();
ISystemUiProxy sysUiProxy = RecentsModel.getInstance(activity).getSystemUiProxy();
try {
sysUiProxy.onSplitScreenInvoked();
} catch (RemoteException e) {
@ -134,7 +136,7 @@ public class TaskSystemShortcut<T extends SystemShortcut> extends SystemShortcut
final Runnable animStartedListener = () -> {
mTaskView.getViewTreeObserver().addOnPreDrawListener(SplitScreen.this);
launcher.<RecentsView>getOverviewPanel().removeView(taskView);
activity.<RecentsView>getOverviewPanel().removeView(taskView);
};
final int[] position = new int[2];
@ -178,8 +180,9 @@ public class TaskSystemShortcut<T extends SystemShortcut> extends SystemShortcut
}
@Override
public View.OnClickListener getOnClickListener(Launcher launcher, TaskView taskView) {
ISystemUiProxy sysUiProxy = RecentsModel.getInstance(launcher).getSystemUiProxy();
public View.OnClickListener getOnClickListener(
BaseDraggingActivity activity, TaskView taskView) {
ISystemUiProxy sysUiProxy = RecentsModel.getInstance(activity).getSystemUiProxy();
if (sysUiProxy == null) {
return null;
}
@ -211,11 +214,11 @@ public class TaskSystemShortcut<T extends SystemShortcut> extends SystemShortcut
}
@Override
protected View.OnClickListener getOnClickListenerForTask(Launcher launcher, Task task,
ItemInfo itemInfo) {
if (InstantAppResolver.newInstance(launcher).isInstantApp(launcher,
protected View.OnClickListener getOnClickListenerForTask(
BaseDraggingActivity activity, Task task, ItemInfo itemInfo) {
if (InstantAppResolver.newInstance(activity).isInstantApp(activity,
task.getTopComponent().getPackageName())) {
return mSystemShortcut.createOnClickListener(launcher, itemInfo);
return mSystemShortcut.createOnClickListener(activity, itemInfo);
}
return null;
}

View File

@ -16,12 +16,12 @@
package com.android.quickstep;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.os.UserHandle;
import android.util.Log;
import com.android.launcher3.Launcher;
import com.android.launcher3.compat.LauncherAppsCompat;
import com.android.launcher3.compat.UserManagerCompat;
import com.android.systemui.shared.recents.model.Task;
@ -34,10 +34,10 @@ public class TaskUtils {
private static final String TAG = "TaskUtils";
public static CharSequence getTitle(Launcher launcher, Task task) {
LauncherAppsCompat launcherAppsCompat = LauncherAppsCompat.getInstance(launcher);
UserManagerCompat userManagerCompat = UserManagerCompat.getInstance(launcher);
PackageManager packageManager = launcher.getPackageManager();
public static CharSequence getTitle(Context context, Task task) {
LauncherAppsCompat launcherAppsCompat = LauncherAppsCompat.getInstance(context);
UserManagerCompat userManagerCompat = UserManagerCompat.getInstance(context);
PackageManager packageManager = context.getPackageManager();
UserHandle user = UserHandle.of(task.key.userId);
ApplicationInfo applicationInfo = launcherAppsCompat.getApplicationInfo(
task.getTopComponent().getPackageName(), 0, user);

View File

@ -32,14 +32,14 @@ import android.view.animation.AccelerateDecelerateInterpolator;
import android.widget.TextView;
import com.android.launcher3.AbstractFloatingView;
import com.android.launcher3.Launcher;
import com.android.launcher3.BaseDraggingActivity;
import com.android.launcher3.LauncherAnimUtils;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
import com.android.launcher3.anim.AnimationSuccessListener;
import com.android.launcher3.anim.RoundedRectRevealOutlineProvider;
import com.android.launcher3.dragndrop.DragLayer;
import com.android.launcher3.shortcuts.DeepShortcutView;
import com.android.launcher3.views.BaseDragLayer;
import com.android.quickstep.TaskSystemShortcut;
import com.android.quickstep.TaskUtils;
@ -60,7 +60,7 @@ public class TaskMenuView extends AbstractFloatingView {
private static final long OPEN_CLOSE_DURATION = 220;
private Launcher mLauncher;
private BaseDraggingActivity mActivity;
private TextView mTaskIconAndName;
private AnimatorSet mOpenCloseAnimator;
private TaskView mTaskView;
@ -72,7 +72,7 @@ public class TaskMenuView extends AbstractFloatingView {
public TaskMenuView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
mLauncher = Launcher.getLauncher(context);
mActivity = BaseDraggingActivity.fromContext(context);
setClipToOutline(true);
setOutlineProvider(new ViewOutlineProvider() {
@Override
@ -92,7 +92,7 @@ public class TaskMenuView extends AbstractFloatingView {
@Override
public boolean onControllerInterceptTouchEvent(MotionEvent ev) {
if (ev.getAction() == MotionEvent.ACTION_DOWN) {
DragLayer dl = mLauncher.getDragLayer();
BaseDragLayer dl = mActivity.getDragLayer();
if (!dl.isEventOverView(this, ev)) {
// TODO: log this once we have a new container type for it?
close(true);
@ -122,9 +122,9 @@ public class TaskMenuView extends AbstractFloatingView {
}
public static boolean showForTask(TaskView taskView) {
Launcher launcher = Launcher.getLauncher(taskView.getContext());
final TaskMenuView taskMenuView = (TaskMenuView) launcher.getLayoutInflater().inflate(
R.layout.task_menu, launcher.getDragLayer(), false);
BaseDraggingActivity activity = BaseDraggingActivity.fromContext(taskView.getContext());
final TaskMenuView taskMenuView = (TaskMenuView) activity.getLayoutInflater().inflate(
R.layout.task_menu, activity.getDragLayer(), false);
return taskMenuView.populateAndShowForTask(taskView);
}
@ -132,7 +132,7 @@ public class TaskMenuView extends AbstractFloatingView {
if (isAttachedToWindow()) {
return false;
}
mLauncher.getDragLayer().addView(this);
mActivity.getDragLayer().addView(this);
mTaskView = taskView;
addMenuOptions(mTaskView);
orientAroundTaskView(mTaskView);
@ -145,11 +145,11 @@ public class TaskMenuView extends AbstractFloatingView {
int iconSize = getResources().getDimensionPixelSize(R.dimen.task_thumbnail_icon_size);
icon.setBounds(0, 0, iconSize, iconSize);
mTaskIconAndName.setCompoundDrawables(null, icon, null, null);
mTaskIconAndName.setText(TaskUtils.getTitle(mLauncher, taskView.getTask()));
mTaskIconAndName.setText(TaskUtils.getTitle(getContext(), taskView.getTask()));
mTaskIconAndName.setOnClickListener(v -> close(true));
for (TaskSystemShortcut menuOption : MENU_OPTIONS) {
OnClickListener onClickListener = menuOption.getOnClickListener(mLauncher, taskView);
OnClickListener onClickListener = menuOption.getOnClickListener(mActivity, taskView);
if (onClickListener != null) {
addMenuOption(menuOption, onClickListener);
}
@ -157,7 +157,7 @@ public class TaskMenuView extends AbstractFloatingView {
}
private void addMenuOption(TaskSystemShortcut menuOption, OnClickListener onClickListener) {
DeepShortcutView menuOptionView = (DeepShortcutView) mLauncher.getLayoutInflater().inflate(
DeepShortcutView menuOptionView = (DeepShortcutView) mActivity.getLayoutInflater().inflate(
R.layout.system_shortcut, this, false);
menuOptionView.getIconView().setBackgroundResource(menuOption.iconResId);
menuOptionView.getBubbleText().setText(menuOption.labelResId);
@ -167,8 +167,8 @@ public class TaskMenuView extends AbstractFloatingView {
private void orientAroundTaskView(TaskView taskView) {
measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
mLauncher.getDragLayer().getDescendantRectRelativeToSelf(taskView, sTempRect);
Rect insets = mLauncher.getDragLayer().getInsets();
mActivity.getDragLayer().getDescendantRectRelativeToSelf(taskView, sTempRect);
Rect insets = mActivity.getDragLayer().getInsets();
int x = sTempRect.left + (sTempRect.width() - getMeasuredWidth()) / 2 - insets.left;
setX(Utilities.isRtl(getResources()) ? -x : x);
setY(sTempRect.top - mTaskIconAndName.getPaddingTop() - insets.top);
@ -211,7 +211,7 @@ public class TaskMenuView extends AbstractFloatingView {
private void closeComplete() {
mIsOpen = false;
mLauncher.getDragLayer().removeView(this);
mActivity.getDragLayer().removeView(this);
}
private RoundedRectRevealOutlineProvider createOpenCloseOutlineProvider() {

View File

@ -28,6 +28,7 @@ import android.view.ViewOutlineProvider;
import android.widget.FrameLayout;
import android.widget.ImageView;
import com.android.launcher3.BaseDraggingActivity;
import com.android.launcher3.Launcher;
import com.android.launcher3.R;
import com.android.quickstep.views.RecentsView.PageCallbacks;
@ -110,7 +111,8 @@ public class TaskView extends FrameLayout implements TaskCallbacks, PageCallback
if (mTask != null) {
final ActivityOptions opts;
if (animate) {
opts = Launcher.getLauncher(getContext()).getActivityLaunchOptions(this, false);
opts = BaseDraggingActivity.fromContext(getContext())
.getActivityLaunchOptions(this, false);
} else {
opts = ActivityOptions.makeCustomAnimation(getContext(), 0, 0);
}

View File

@ -24,9 +24,9 @@ import android.view.MotionEvent;
import android.view.View;
import android.widget.LinearLayout;
import com.android.launcher3.dragndrop.DragLayer;
import com.android.launcher3.userevent.nano.LauncherLogProto.Action;
import com.android.launcher3.util.TouchController;
import com.android.launcher3.views.BaseDragLayer;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@ -92,7 +92,7 @@ public abstract class AbstractFloatingView extends LinearLayout implements Touch
public final void close(boolean animate) {
animate &= !Utilities.isPowerSaverOn(getContext());
handleClose(animate);
Launcher.getLauncher(getContext()).getUserEventDispatcher()
BaseActivity.fromContext(getContext()).getUserEventDispatcher()
.resetElapsedContainerMillis("container closed");
}
@ -120,8 +120,8 @@ public abstract class AbstractFloatingView extends LinearLayout implements Touch
}
protected static <T extends AbstractFloatingView> T getOpenView(
Launcher launcher, @FloatingViewType int type) {
DragLayer dragLayer = launcher.getDragLayer();
BaseDraggingActivity activity, @FloatingViewType int type) {
BaseDragLayer dragLayer = activity.getDragLayer();
// Iterate in reverse order. AbstractFloatingView is added later to the dragLayer,
// and will be one of the last views.
for (int i = dragLayer.getChildCount() - 1; i >= 0; i--) {
@ -136,16 +136,17 @@ public abstract class AbstractFloatingView extends LinearLayout implements Touch
return null;
}
public static void closeOpenContainer(Launcher launcher, @FloatingViewType int type) {
AbstractFloatingView view = getOpenView(launcher, type);
public static void closeOpenContainer(BaseDraggingActivity activity,
@FloatingViewType int type) {
AbstractFloatingView view = getOpenView(activity, type);
if (view != null) {
view.close(true);
}
}
public static void closeOpenViews(Launcher launcher, boolean animate,
public static void closeOpenViews(BaseDraggingActivity activity, boolean animate,
@FloatingViewType int type) {
DragLayer dragLayer = launcher.getDragLayer();
BaseDragLayer dragLayer = activity.getDragLayer();
// Iterate in reverse order. AbstractFloatingView is added later to the dragLayer,
// and will be one of the last views.
for (int i = dragLayer.getChildCount() - 1; i >= 0; i--) {
@ -159,16 +160,16 @@ public abstract class AbstractFloatingView extends LinearLayout implements Touch
}
}
public static void closeAllOpenViews(Launcher launcher, boolean animate) {
closeOpenViews(launcher, animate, TYPE_ALL);
launcher.finishAutoCancelActionMode();
public static void closeAllOpenViews(BaseDraggingActivity activity, boolean animate) {
closeOpenViews(activity, animate, TYPE_ALL);
activity.finishAutoCancelActionMode();
}
public static void closeAllOpenViews(Launcher launcher) {
closeAllOpenViews(launcher, true);
public static void closeAllOpenViews(BaseDraggingActivity activity) {
closeAllOpenViews(activity, true);
}
public static AbstractFloatingView getTopOpenView(Launcher launcher) {
return getOpenView(launcher, TYPE_ALL);
public static AbstractFloatingView getTopOpenView(BaseDraggingActivity activity) {
return getOpenView(activity, TYPE_ALL);
}
}

View File

@ -0,0 +1,191 @@
/*
* Copyright (C) 2018 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.launcher3;
import android.app.ActivityOptions;
import android.content.ActivityNotFoundException;
import android.content.Context;
import android.content.ContextWrapper;
import android.content.Intent;
import android.graphics.Rect;
import android.os.Bundle;
import android.os.Process;
import android.os.StrictMode;
import android.os.UserHandle;
import android.util.Log;
import android.view.ActionMode;
import android.view.View;
import android.widget.Toast;
import com.android.launcher3.LauncherSettings.Favorites;
import com.android.launcher3.badge.BadgeInfo;
import com.android.launcher3.compat.LauncherAppsCompat;
import com.android.launcher3.shortcuts.DeepShortcutManager;
import com.android.launcher3.views.BaseDragLayer;
/**
* Extension of BaseActivity allowing support for drag-n-drop
*/
public abstract class BaseDraggingActivity extends BaseActivity {
private static final String TAG = "BaseDraggingActivity";
// The Intent extra that defines whether to ignore the launch animation
private static final String INTENT_EXTRA_IGNORE_LAUNCH_ANIMATION =
"com.android.launcher3.intent.extra.shortcut.INGORE_LAUNCH_ANIMATION";
// When starting an action mode, setting this tag will cause the action mode to be cancelled
// automatically when user interacts with the launcher.
public static final Object AUTO_CANCEL_ACTION_MODE = new Object();
private ActionMode mCurrentActionMode;
protected boolean mIsSafeModeEnabled;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mIsSafeModeEnabled = getPackageManager().isSafeMode();
}
@Override
public void onActionModeStarted(ActionMode mode) {
super.onActionModeStarted(mode);
mCurrentActionMode = mode;
}
@Override
public void onActionModeFinished(ActionMode mode) {
super.onActionModeFinished(mode);
mCurrentActionMode = null;
}
public boolean finishAutoCancelActionMode() {
if (mCurrentActionMode != null && AUTO_CANCEL_ACTION_MODE == mCurrentActionMode.getTag()) {
mCurrentActionMode.finish();
return true;
}
return false;
}
public abstract BaseDragLayer getDragLayer();
public abstract <T extends View> T getOverviewPanel();
public abstract BadgeInfo getBadgeInfoForItem(ItemInfo info);
public abstract void invalidateParent(ItemInfo info);
public static BaseDraggingActivity fromContext(Context context) {
if (context instanceof BaseDraggingActivity) {
return (BaseDraggingActivity) context;
}
return ((BaseDraggingActivity) ((ContextWrapper) context).getBaseContext());
}
public Rect getViewBounds(View v) {
int[] pos = new int[2];
v.getLocationOnScreen(pos);
return new Rect(pos[0], pos[1], pos[0] + v.getWidth(), pos[1] + v.getHeight());
}
public final Bundle getActivityLaunchOptionsAsBundle(View v, boolean useDefaultLaunchOptions) {
ActivityOptions activityOptions = getActivityLaunchOptions(v, useDefaultLaunchOptions);
return activityOptions == null ? null : activityOptions.toBundle();
}
public abstract ActivityOptions getActivityLaunchOptions(
View v, boolean useDefaultLaunchOptions);
public boolean startActivitySafely(View v, Intent intent, ItemInfo item) {
if (mIsSafeModeEnabled && !Utilities.isSystemApp(this, intent)) {
Toast.makeText(this, R.string.safemode_shortcut_error, Toast.LENGTH_SHORT).show();
return false;
}
// Only launch using the new animation if the shortcut has not opted out (this is a
// private contract between launcher and may be ignored in the future).
boolean useLaunchAnimation = (v != null) &&
!intent.hasExtra(INTENT_EXTRA_IGNORE_LAUNCH_ANIMATION);
Bundle optsBundle = useLaunchAnimation
? getActivityLaunchOptionsAsBundle(v, isInMultiWindowModeCompat())
: null;
UserHandle user = item == null ? null : item.user;
// Prepare intent
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
if (v != null) {
intent.setSourceBounds(getViewBounds(v));
}
try {
boolean isShortcut = Utilities.ATLEAST_MARSHMALLOW
&& (item instanceof ShortcutInfo)
&& (item.itemType == Favorites.ITEM_TYPE_SHORTCUT
|| item.itemType == Favorites.ITEM_TYPE_DEEP_SHORTCUT)
&& !((ShortcutInfo) item).isPromise();
if (isShortcut) {
// Shortcuts need some special checks due to legacy reasons.
startShortcutIntentSafely(intent, optsBundle, item);
} else if (user == null || user.equals(Process.myUserHandle())) {
// Could be launching some bookkeeping activity
startActivity(intent, optsBundle);
} else {
LauncherAppsCompat.getInstance(this).startActivityForProfile(
intent.getComponent(), user, intent.getSourceBounds(), optsBundle);
}
getUserEventDispatcher().logAppLaunch(v, intent);
return true;
} catch (ActivityNotFoundException|SecurityException e) {
Toast.makeText(this, R.string.activity_not_found, Toast.LENGTH_SHORT).show();
Log.e(TAG, "Unable to launch. tag=" + item + " intent=" + intent, e);
}
return false;
}
private void startShortcutIntentSafely(Intent intent, Bundle optsBundle, ItemInfo info) {
try {
StrictMode.VmPolicy oldPolicy = StrictMode.getVmPolicy();
try {
// Temporarily disable deathPenalty on all default checks. For eg, shortcuts
// containing file Uri's would cause a crash as penaltyDeathOnFileUriExposure
// is enabled by default on NYC.
StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder().detectAll()
.penaltyLog().build());
if (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT) {
String id = ((ShortcutInfo) info).getDeepShortcutId();
String packageName = intent.getPackage();
DeepShortcutManager.getInstance(this).startShortcut(
packageName, id, intent.getSourceBounds(), optsBundle, info.user);
} else {
// Could be launching some bookkeeping activity
startActivity(intent, optsBundle);
}
} finally {
StrictMode.setVmPolicy(oldPolicy);
}
} catch (SecurityException e) {
if (!onErrorStartingShortcut(intent, info)) {
throw e;
}
}
}
protected boolean onErrorStartingShortcut(Intent intent, ItemInfo info) {
return false;
}
}

View File

@ -44,7 +44,6 @@ import com.android.launcher3.Launcher.OnResumeCallback;
import com.android.launcher3.badge.BadgeInfo;
import com.android.launcher3.badge.BadgeRenderer;
import com.android.launcher3.folder.FolderIcon;
import com.android.launcher3.folder.FolderIconPreviewVerifier;
import com.android.launcher3.graphics.DrawableFactory;
import com.android.launcher3.graphics.IconPalette;
import com.android.launcher3.graphics.PreloadIconDrawable;
@ -65,7 +64,7 @@ public class BubbleTextView extends TextView implements ItemInfoUpdateReceiver,
private static final int[] STATE_PRESSED = new int[] {android.R.attr.state_pressed};
private final Launcher mLauncher;
private final BaseDraggingActivity mActivity;
private Drawable mIcon;
private final boolean mCenterVertically;
@ -133,8 +132,8 @@ public class BubbleTextView extends TextView implements ItemInfoUpdateReceiver,
public BubbleTextView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
mLauncher = Launcher.getLauncher(context);
DeviceProfile grid = mLauncher.getDeviceProfile();
mActivity = BaseDraggingActivity.fromContext(context);
DeviceProfile grid = mActivity.getDeviceProfile();
mSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop();
TypedArray a = context.obtainStyledAttributes(attrs,
@ -164,7 +163,7 @@ public class BubbleTextView extends TextView implements ItemInfoUpdateReceiver,
mLongPressHelper = new CheckLongPressHelper(this);
mStylusEventHelper = new StylusEventHelper(new SimpleOnStylusPressListener(this), this);
setAccessibilityDelegate(mLauncher.getAccessibilityDelegate());
setAccessibilityDelegate(mActivity.getAccessibilityDelegate());
}
@ -493,10 +492,10 @@ public class BubbleTextView extends TextView implements ItemInfoUpdateReceiver,
public void applyBadgeState(ItemInfo itemInfo, boolean animate) {
if (mIcon instanceof FastBitmapDrawable) {
boolean wasBadged = mBadgeInfo != null;
mBadgeInfo = mLauncher.getPopupDataProvider().getBadgeInfoForItem(itemInfo);
mBadgeInfo = mActivity.getBadgeInfoForItem(itemInfo);
boolean isBadged = mBadgeInfo != null;
float newBadgeScale = isBadged ? 1f : 0;
mBadgeRenderer = mLauncher.getDeviceProfile().mBadgeRenderer;
mBadgeRenderer = mActivity.getDeviceProfile().mBadgeRenderer;
if (wasBadged || isBadged) {
// Animate when a badge is first added or when it is removed.
if (animate && (wasBadged ^ isBadged) && isShown()) {
@ -572,15 +571,7 @@ public class BubbleTextView extends TextView implements ItemInfoUpdateReceiver,
applyFromApplicationInfo((AppInfo) info);
} else if (info instanceof ShortcutInfo) {
applyFromShortcutInfo((ShortcutInfo) info);
FolderIconPreviewVerifier verifier =
new FolderIconPreviewVerifier(mLauncher.getDeviceProfile().inv);
if (verifier.isItemInPreview(info.rank) && (info.container >= 0)) {
View folderIcon =
mLauncher.getWorkspace().getHomescreenIconByItemId(info.container);
if (folderIcon != null) {
folderIcon.invalidate();
}
}
mActivity.invalidateParent(info);
} else if (info instanceof PackageItemInfo) {
applyFromPackageItemInfo((PackageItemInfo) info);
}

View File

@ -25,7 +25,6 @@ import static com.android.launcher3.LauncherState.NORMAL;
import static com.android.launcher3.LauncherState.OVERVIEW;
import static com.android.launcher3.logging.LoggerUtils.newContainerTarget;
import android.Manifest;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
@ -47,7 +46,6 @@ import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.content.res.Configuration;
import android.database.sqlite.SQLiteDatabase;
import android.graphics.Rect;
import android.os.AsyncTask;
import android.os.Build;
import android.os.Bundle;
@ -60,7 +58,6 @@ import android.text.TextUtils;
import android.text.method.TextKeyListener;
import android.util.Log;
import android.util.SparseArray;
import android.view.ActionMode;
import android.view.KeyEvent;
import android.view.KeyboardShortcutGroup;
import android.view.KeyboardShortcutInfo;
@ -73,14 +70,13 @@ import android.view.animation.OvershootInterpolator;
import android.widget.Toast;
import com.android.launcher3.DropTarget.DragObject;
import com.android.launcher3.LauncherSettings.Favorites;
import com.android.launcher3.Workspace.ItemOperator;
import com.android.launcher3.accessibility.LauncherAccessibilityDelegate;
import com.android.launcher3.allapps.AllAppsContainerView;
import com.android.launcher3.allapps.AllAppsTransitionController;
import com.android.launcher3.allapps.DiscoveryBounce;
import com.android.launcher3.badge.BadgeInfo;
import com.android.launcher3.compat.AppWidgetManagerCompat;
import com.android.launcher3.compat.LauncherAppsCompat;
import com.android.launcher3.compat.LauncherAppsCompatVO;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.dragndrop.DragController;
@ -88,6 +84,7 @@ import com.android.launcher3.dragndrop.DragLayer;
import com.android.launcher3.dragndrop.DragView;
import com.android.launcher3.dynamicui.WallpaperColorInfo;
import com.android.launcher3.folder.FolderIcon;
import com.android.launcher3.folder.FolderIconPreviewVerifier;
import com.android.launcher3.keyboard.CustomActionsPopup;
import com.android.launcher3.keyboard.ViewGroupFocusHelper;
import com.android.launcher3.logging.FileLog;
@ -139,7 +136,7 @@ import java.util.Set;
/**
* Default launcher application.
*/
public class Launcher extends BaseActivity implements LauncherExterns, LauncherModel.Callbacks,
public class Launcher extends BaseDraggingActivity implements LauncherExterns, LauncherModel.Callbacks,
LauncherProviderChangeListener, WallpaperColorInfo.OnThemeChangeListener {
public static final String TAG = "Launcher";
static final boolean LOGD = false;
@ -166,10 +163,6 @@ public class Launcher extends BaseActivity implements LauncherExterns, LauncherM
*/
protected static final int REQUEST_LAST = 100;
// The Intent extra that defines whether to ignore the launch animation
static final String INTENT_EXTRA_IGNORE_LAUNCH_ANIMATION =
"com.android.launcher3.intent.extra.shortcut.INGORE_LAUNCH_ANIMATION";
// Type: int
private static final String RUNTIME_STATE_CURRENT_SCREEN = "launcher.current_screen";
// Type: int
@ -181,14 +174,8 @@ public class Launcher extends BaseActivity implements LauncherExterns, LauncherM
// Type: SparseArray<Parcelable>
private static final String RUNTIME_STATE_WIDGET_PANEL = "launcher.widget_panel";
// When starting an action mode, setting this tag will cause the action mode to be cancelled
// automatically when user interacts with the launcher.
public static final Object AUTO_CANCEL_ACTION_MODE = new Object();
private LauncherStateManager mStateManager;
private boolean mIsSafeModeEnabled;
private static final int ON_ACTIVITY_RESULT_ANIMATION_DELAY = 500;
// How long to wait before the new-shortcut animation automatically pans the workspace
@ -255,7 +242,6 @@ public class Launcher extends BaseActivity implements LauncherExterns, LauncherM
private boolean mAppLaunchSuccess;
private RotationHelper mRotationHelper;
private ActionMode mCurrentActionMode;
@Override
protected void onCreate(Bundle savedInstanceState) {
@ -288,7 +274,6 @@ public class Launcher extends BaseActivity implements LauncherExterns, LauncherM
initDeviceProfile(app.getInvariantDeviceProfile());
mSharedPrefs = Utilities.getPrefs(this);
mIsSafeModeEnabled = getPackageManager().isSafeMode();
mIconCache = app.getIconCache();
mAccessibilityDelegate = new LauncherAccessibilityDelegate(this);
@ -482,6 +467,22 @@ public class Launcher extends BaseActivity implements LauncherExterns, LauncherM
return mPopupDataProvider;
}
@Override
public BadgeInfo getBadgeInfoForItem(ItemInfo info) {
return mPopupDataProvider.getBadgeInfoForItem(info);
}
@Override
public void invalidateParent(ItemInfo info) {
FolderIconPreviewVerifier verifier = new FolderIconPreviewVerifier(getDeviceProfile().inv);
if (verifier.isItemInPreview(info.rank) && (info.container >= 0)) {
View folderIcon = getWorkspace().getHomescreenIconByItemId(info.container);
if (folderIcon != null) {
folderIcon.invalidate();
}
}
}
/**
* Returns whether we should delay spring loaded mode -- for shortcuts and widgets that have
* a configuration step, this allows the proper animations to run after other transitions.
@ -941,7 +942,7 @@ public class Launcher extends BaseActivity implements LauncherExterns, LauncherM
| View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
// Setup the drag layer
mDragLayer.setup(this, mDragController);
mDragLayer.setup(mDragController);
mWorkspace.setup(mDragController);
// Until the workspace is bound, ensure that we keep the wallpaper offset locked to the
@ -1180,6 +1181,7 @@ public class Launcher extends BaseActivity implements LauncherExterns, LauncherM
return (LauncherRootView) mLauncherView;
}
@Override
public DragLayer getDragLayer() {
return mDragLayer;
}
@ -1672,119 +1674,45 @@ public class Launcher extends BaseActivity implements LauncherExterns, LauncherM
}
}
private void startShortcutIntentSafely(Intent intent, Bundle optsBundle, ItemInfo info) {
try {
StrictMode.VmPolicy oldPolicy = StrictMode.getVmPolicy();
try {
// Temporarily disable deathPenalty on all default checks. For eg, shortcuts
// containing file Uri's would cause a crash as penaltyDeathOnFileUriExposure
// is enabled by default on NYC.
StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder().detectAll()
.penaltyLog().build());
if (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT) {
String id = ((ShortcutInfo) info).getDeepShortcutId();
String packageName = intent.getPackage();
DeepShortcutManager.getInstance(this).startShortcut(
packageName, id, intent.getSourceBounds(), optsBundle, info.user);
} else {
// Could be launching some bookkeeping activity
startActivity(intent, optsBundle);
}
} finally {
StrictMode.setVmPolicy(oldPolicy);
}
} catch (SecurityException e) {
// Due to legacy reasons, direct call shortcuts require Launchers to have the
// corresponding permission. Show the appropriate permission prompt if that
// is the case.
if (intent.getComponent() == null
&& Intent.ACTION_CALL.equals(intent.getAction())
&& checkSelfPermission(Manifest.permission.CALL_PHONE) !=
PackageManager.PERMISSION_GRANTED) {
setWaitingForResult(PendingRequestArgs
.forIntent(REQUEST_PERMISSION_CALL_PHONE, intent, info));
requestPermissions(new String[]{Manifest.permission.CALL_PHONE},
REQUEST_PERMISSION_CALL_PHONE);
} else {
// No idea why this was thrown.
throw e;
}
}
}
public Bundle getActivityLaunchOptionsAsBundle(View v, boolean useDefaultLaunchOptions) {
ActivityOptions activityOptions = getActivityLaunchOptions(v, useDefaultLaunchOptions);
return activityOptions == null ? null : activityOptions.toBundle();
}
@TargetApi(Build.VERSION_CODES.M)
@Override
public ActivityOptions getActivityLaunchOptions(View v, boolean useDefaultLaunchOptions) {
return useDefaultLaunchOptions
? mAppTransitionManager.getDefaultActivityLaunchOptions(this, v)
: mAppTransitionManager.getActivityLaunchOptions(this, v);
}
public Rect getViewBounds(View v) {
int[] pos = new int[2];
v.getLocationOnScreen(pos);
return new Rect(pos[0], pos[1], pos[0] + v.getWidth(), pos[1] + v.getHeight());
@TargetApi(Build.VERSION_CODES.M)
@Override
protected boolean onErrorStartingShortcut(Intent intent, ItemInfo info) {
// Due to legacy reasons, direct call shortcuts require Launchers to have the
// corresponding permission. Show the appropriate permission prompt if that
// is the case.
if (intent.getComponent() == null
&& Intent.ACTION_CALL.equals(intent.getAction())
&& checkSelfPermission(android.Manifest.permission.CALL_PHONE) !=
PackageManager.PERMISSION_GRANTED) {
setWaitingForResult(PendingRequestArgs
.forIntent(REQUEST_PERMISSION_CALL_PHONE, intent, info));
requestPermissions(new String[]{android.Manifest.permission.CALL_PHONE},
REQUEST_PERMISSION_CALL_PHONE);
return true;
} else {
return false;
}
}
public boolean startActivitySafely(View v, Intent intent, ItemInfo item) {
mAppLaunchSuccess = false;
if (mIsSafeModeEnabled && !Utilities.isSystemApp(this, intent)) {
Toast.makeText(this, R.string.safemode_shortcut_error, Toast.LENGTH_SHORT).show();
return mAppLaunchSuccess;
}
// Only launch using the new animation if the shortcut has not opted out (this is a
// private contract between launcher and may be ignored in the future).
boolean useLaunchAnimation = (v != null) &&
!intent.hasExtra(INTENT_EXTRA_IGNORE_LAUNCH_ANIMATION);
Bundle optsBundle = useLaunchAnimation
? getActivityLaunchOptionsAsBundle(v, isInMultiWindowModeCompat())
: null;
UserHandle user = item == null ? null : item.user;
// Prepare intent
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
if (v != null) {
intent.setSourceBounds(getViewBounds(v));
}
try {
boolean isShortcut = Utilities.ATLEAST_MARSHMALLOW
&& (item instanceof ShortcutInfo)
&& (item.itemType == Favorites.ITEM_TYPE_SHORTCUT
|| item.itemType == Favorites.ITEM_TYPE_DEEP_SHORTCUT)
&& !((ShortcutInfo) item).isPromise();
if (isShortcut) {
// Shortcuts need some special checks due to legacy reasons.
startShortcutIntentSafely(intent, optsBundle, item);
} else if (user == null || user.equals(Process.myUserHandle())) {
// Could be launching some bookkeeping activity
startActivity(intent, optsBundle);
} else {
LauncherAppsCompat.getInstance(this).startActivityForProfile(
intent.getComponent(), user, intent.getSourceBounds(), optsBundle);
}
if (v instanceof BubbleTextView) {
// This is set to the view that launched the activity that navigated the user away
// from launcher. Since there is no callback for when the activity has finished
// launching, enable the press state and keep this reference to reset the press
// state when we return to launcher.
BubbleTextView btv = (BubbleTextView) v;
btv.setStayPressed(true);
setOnResumeCallback(btv);
}
mAppLaunchSuccess = true;
getUserEventDispatcher().logAppLaunch(v, intent); // TODO for discovered apps b/35802115
} catch (ActivityNotFoundException|SecurityException e) {
Toast.makeText(this, R.string.activity_not_found, Toast.LENGTH_SHORT).show();
Log.e(TAG, "Unable to launch. tag=" + item + " intent=" + intent, e);
mAppLaunchSuccess = super.startActivitySafely(v, intent, item);
if (mAppLaunchSuccess && v instanceof BubbleTextView) {
// This is set to the view that launched the activity that navigated the user away
// from launcher. Since there is no callback for when the activity has finished
// launching, enable the press state and keep this reference to reset the press
// state when we return to launcher.
BubbleTextView btv = (BubbleTextView) v;
btv.setStayPressed(true);
setOnResumeCallback(btv);
}
return mAppLaunchSuccess;
}
@ -2515,26 +2443,6 @@ public class Launcher extends BaseActivity implements LauncherExterns, LauncherM
return ((Launcher) ((ContextWrapper) context).getBaseContext());
}
@Override
public void onActionModeStarted(ActionMode mode) {
super.onActionModeStarted(mode);
mCurrentActionMode = mode;
}
@Override
public void onActionModeFinished(ActionMode mode) {
super.onActionModeFinished(mode);
mCurrentActionMode = null;
}
public boolean finishAutoCancelActionMode() {
if (mCurrentActionMode != null && AUTO_CANCEL_ACTION_MODE == mCurrentActionMode.getTag()) {
mCurrentActionMode.finish();
return true;
}
return false;
}
/**
* Callback for listening for onResume
*/

View File

@ -3254,8 +3254,7 @@ public class Workspace extends PagedView<WorkspacePageIndicator>
&& v instanceof FolderIcon) {
FolderBadgeInfo folderBadgeInfo = new FolderBadgeInfo();
for (ShortcutInfo si : ((FolderInfo) info).contents) {
folderBadgeInfo.addBadgeInfo(mLauncher.getPopupDataProvider()
.getBadgeInfoForItem(si));
folderBadgeInfo.addBadgeInfo(mLauncher.getBadgeInfoForItem(si));
}
((FolderIcon) v).setBadgeInfo(folderBadgeInfo);
}

View File

@ -31,21 +31,17 @@ import android.util.AttributeSet;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityManager;
import android.view.animation.Interpolator;
import android.widget.FrameLayout;
import android.widget.TextView;
import com.android.launcher3.AbstractFloatingView;
import com.android.launcher3.CellLayout;
import com.android.launcher3.DropTargetBar;
import com.android.launcher3.InsettableFrameLayout;
import com.android.launcher3.Launcher;
import com.android.launcher3.R;
import com.android.launcher3.ShortcutAndWidgetContainer;
import com.android.launcher3.Utilities;
import com.android.launcher3.anim.Interpolators;
import com.android.launcher3.folder.Folder;
import com.android.launcher3.folder.FolderIcon;
@ -53,24 +49,20 @@ import com.android.launcher3.graphics.ViewScrim;
import com.android.launcher3.keyboard.ViewGroupFocusHelper;
import com.android.launcher3.uioverrides.UiFactory;
import com.android.launcher3.util.Thunk;
import com.android.launcher3.util.TouchController;
import com.android.launcher3.views.BaseDragLayer;
import java.util.ArrayList;
/**
* A ViewGroup that coordinates dragging across its descendants
*/
public class DragLayer extends InsettableFrameLayout {
public class DragLayer extends BaseDragLayer<Launcher> {
public static final int ANIMATION_END_DISAPPEAR = 0;
public static final int ANIMATION_END_REMAIN_VISIBLE = 2;
private final int[] mTmpXY = new int[2];
@Thunk DragController mDragController;
private Launcher mLauncher;
// Variables relating to animation of views after drop
private ValueAnimator mDropAnim = null;
private final TimeInterpolator mCubicEaseOutInterpolator = Interpolators.DEACCEL_1_5;
@ -79,9 +71,6 @@ public class DragLayer extends InsettableFrameLayout {
@Thunk View mAnchorView = null;
private boolean mHoverPointClosesFolder = false;
private final Rect mHitRect = new Rect();
private TouchCompleteListener mTouchCompleteListener;
private int mTopViewIndex;
private int mChildCountOnLastUpdate = -1;
@ -89,8 +78,6 @@ public class DragLayer extends InsettableFrameLayout {
// Related to adjacent page hints
private final ViewGroupFocusHelper mFocusIndicatorHelper;
protected TouchController[] mControllers;
private TouchController mActiveController;
/**
* Used to create a new DragLayer from XML.
*
@ -107,10 +94,9 @@ public class DragLayer extends InsettableFrameLayout {
mFocusIndicatorHelper = new ViewGroupFocusHelper(this);
}
public void setup(Launcher launcher, DragController dragController) {
mLauncher = launcher;
public void setup(DragController dragController) {
mDragController = dragController;
mControllers = UiFactory.createTouchControllers(mLauncher);
mControllers = UiFactory.createTouchControllers(mActivity);
}
public ViewGroupFocusHelper getFocusIndicatorHelper() {
@ -123,7 +109,7 @@ public class DragLayer extends InsettableFrameLayout {
}
public boolean isEventOverHotseat(MotionEvent ev) {
return isEventOverView(mLauncher.getHotseat(), ev);
return isEventOverView(mActivity.getHotseat(), ev);
}
private boolean isEventOverFolder(Folder folder, MotionEvent ev) {
@ -131,12 +117,7 @@ public class DragLayer extends InsettableFrameLayout {
}
private boolean isEventOverDropTargetBar(MotionEvent ev) {
return isEventOverView(mLauncher.getDropTargetBar(), ev);
}
public boolean isEventOverView(View view, MotionEvent ev) {
getDescendantRectRelativeToSelf(view, mHitRect);
return mHitRect.contains((int) ev.getX(), (int) ev.getY());
return isEventOverView(mActivity.getDropTargetBar(), ev);
}
@Override
@ -149,66 +130,33 @@ public class DragLayer extends InsettableFrameLayout {
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
int action = ev.getAction();
if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) {
if (mTouchCompleteListener != null) {
mTouchCompleteListener.onTouchComplete();
}
mTouchCompleteListener = null;
} else if (action == MotionEvent.ACTION_DOWN) {
mLauncher.finishAutoCancelActionMode();
}
return findActiveController(ev);
}
private boolean findActiveController(MotionEvent ev) {
mActiveController = null;
AbstractFloatingView topView = AbstractFloatingView.getTopOpenView(mLauncher);
if (topView != null && topView.onControllerInterceptTouchEvent(ev)) {
mActiveController = topView;
return true;
}
if (mLauncher.getStateManager().getState().disableInteraction) {
protected boolean findActiveController(MotionEvent ev) {
if (mActivity.getStateManager().getState().disableInteraction) {
// You Shall Not Pass!!!
mActiveController = null;
return true;
}
if (mDragController.onControllerInterceptTouchEvent(ev)) {
mActiveController = mDragController;
return true;
}
for (TouchController controller : mControllers) {
if (controller.onControllerInterceptTouchEvent(ev)) {
mActiveController = controller;
return true;
}
}
return false;
return super.findActiveController(ev);
}
@Override
public boolean onInterceptHoverEvent(MotionEvent ev) {
if (mLauncher == null || mLauncher.getWorkspace() == null) {
if (mActivity == null || mActivity.getWorkspace() == null) {
return false;
}
Folder currentFolder = Folder.getOpen(mLauncher);
Folder currentFolder = Folder.getOpen(mActivity);
if (currentFolder == null) {
return false;
} else {
AccessibilityManager accessibilityManager = (AccessibilityManager)
getContext().getSystemService(Context.ACCESSIBILITY_SERVICE);
AccessibilityManager accessibilityManager = (AccessibilityManager)
getContext().getSystemService(Context.ACCESSIBILITY_SERVICE);
if (accessibilityManager.isTouchExplorationEnabled()) {
final int action = ev.getAction();
boolean isOverFolderOrSearchBar;
switch (action) {
case MotionEvent.ACTION_HOVER_ENTER:
isOverFolderOrSearchBar = isEventOverFolder(currentFolder, ev) ||
(isInAccessibleDrag() && isEventOverDropTargetBar(ev));
(isInAccessibleDrag() && isEventOverDropTargetBar(ev));
if (!isOverFolderOrSearchBar) {
sendTapOutsideFolderAccessibilityEvent(currentFolder.isEditingName());
mHoverPointClosesFolder = true;
@ -218,7 +166,7 @@ public class DragLayer extends InsettableFrameLayout {
break;
case MotionEvent.ACTION_HOVER_MOVE:
isOverFolderOrSearchBar = isEventOverFolder(currentFolder, ev) ||
(isInAccessibleDrag() && isEventOverDropTargetBar(ev));
(isInAccessibleDrag() && isEventOverDropTargetBar(ev));
if (!isOverFolderOrSearchBar && !mHoverPointClosesFolder) {
sendTapOutsideFolderAccessibilityEvent(currentFolder.isEditingName());
mHoverPointClosesFolder = true;
@ -239,14 +187,22 @@ public class DragLayer extends InsettableFrameLayout {
this, AccessibilityEvent.TYPE_VIEW_FOCUSED, getContext().getString(stringId));
}
@Override
public boolean onHoverEvent(MotionEvent ev) {
// If we've received this, we've already done the necessary handling
// in onInterceptHoverEvent. Return true to consume the event.
return false;
}
private boolean isInAccessibleDrag() {
return mLauncher.getAccessibilityDelegate().isInAccessibleDrag();
return mActivity.getAccessibilityDelegate().isInAccessibleDrag();
}
@Override
public boolean onRequestSendAccessibilityEvent(View child, AccessibilityEvent event) {
// Shortcuts can appear above folder
View topView = AbstractFloatingView.getTopOpenView(mLauncher);
View topView = AbstractFloatingView.getTopOpenView(mActivity);
if (topView != null) {
if (child == topView) {
return super.onRequestSendAccessibilityEvent(child, event);
@ -263,117 +219,23 @@ public class DragLayer extends InsettableFrameLayout {
@Override
public void addChildrenForAccessibility(ArrayList<View> childrenForAccessibility) {
View topView = AbstractFloatingView.getTopOpenView(mLauncher);
View topView = AbstractFloatingView.getTopOpenView(mActivity);
if (topView != null) {
// Only add the top view as a child for accessibility when it is open
childrenForAccessibility.add(topView);
if (isInAccessibleDrag()) {
childrenForAccessibility.add(mLauncher.getDropTargetBar());
childrenForAccessibility.add(mActivity.getDropTargetBar());
}
} else {
super.addChildrenForAccessibility(childrenForAccessibility);
}
}
@Override
public boolean onHoverEvent(MotionEvent ev) {
// If we've received this, we've already done the necessary handling
// in onInterceptHoverEvent. Return true to consume the event.
return false;
}
@Override
public boolean onTouchEvent(MotionEvent ev) {
int action = ev.getAction();
if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) {
if (mTouchCompleteListener != null) {
mTouchCompleteListener.onTouchComplete();
}
mTouchCompleteListener = null;
}
if (mActiveController != null) {
return mActiveController.onControllerTouchEvent(ev);
} else {
// In case no child view handled the touch event, we may not get onIntercept anymore
return findActiveController(ev);
}
}
/**
* Determine the rect of the descendant in this DragLayer's coordinates
*
* @param descendant The descendant whose coordinates we want to find.
* @param r The rect into which to place the results.
* @return The factor by which this descendant is scaled relative to this DragLayer.
*/
public float getDescendantRectRelativeToSelf(View descendant, Rect r) {
mTmpXY[0] = 0;
mTmpXY[1] = 0;
float scale = getDescendantCoordRelativeToSelf(descendant, mTmpXY);
r.set(mTmpXY[0], mTmpXY[1],
(int) (mTmpXY[0] + scale * descendant.getMeasuredWidth()),
(int) (mTmpXY[1] + scale * descendant.getMeasuredHeight()));
return scale;
}
public float getLocationInDragLayer(View child, int[] loc) {
loc[0] = 0;
loc[1] = 0;
return getDescendantCoordRelativeToSelf(child, loc);
}
public float getDescendantCoordRelativeToSelf(View descendant, int[] coord) {
return getDescendantCoordRelativeToSelf(descendant, coord, false);
}
/**
* Given a coordinate relative to the descendant, find the coordinate in this DragLayer's
* coordinates.
*
* @param descendant The descendant to which the passed coordinate is relative.
* @param coord The coordinate that we want mapped.
* @param includeRootScroll Whether or not to account for the scroll of the root descendant:
* sometimes this is relevant as in a child's coordinates within the root descendant.
* @return The factor by which this descendant is scaled relative to this DragLayer. Caution
* this scale factor is assumed to be equal in X and Y, and so if at any point this
* assumption fails, we will need to return a pair of scale factors.
*/
public float getDescendantCoordRelativeToSelf(View descendant, int[] coord,
boolean includeRootScroll) {
return Utilities.getDescendantCoordRelativeToAncestor(descendant, this,
coord, includeRootScroll);
}
/**
* Inverse of {@link #getDescendantCoordRelativeToSelf(View, int[])}.
*/
public void mapCoordInSelfToDescendant(View descendant, int[] coord) {
Utilities.mapCoordInSelfToDescendant(descendant, this, coord);
}
public void getViewRectRelativeToSelf(View v, Rect r) {
int[] loc = new int[2];
getLocationInWindow(loc);
int x = loc[0];
int y = loc[1];
v.getLocationInWindow(loc);
int vX = loc[0];
int vY = loc[1];
int left = vX - x;
int top = vY - y;
r.set(left, top, left + v.getMeasuredWidth(), top + v.getMeasuredHeight());
}
@Override
public boolean dispatchUnhandledMove(View focused, int direction) {
// Consume the unhandled move if a container is open, to avoid switching pages underneath.
boolean isContainerOpen = AbstractFloatingView.getTopOpenView(mLauncher) != null;
return isContainerOpen || mDragController.dispatchUnhandledMove(focused, direction);
return super.dispatchUnhandledMove(focused, direction)
|| mDragController.dispatchUnhandledMove(focused, direction);
}
@Override
@ -386,91 +248,6 @@ public class DragLayer extends InsettableFrameLayout {
}
}
@Override
public LayoutParams generateLayoutParams(AttributeSet attrs) {
return new LayoutParams(getContext(), attrs);
}
@Override
protected LayoutParams generateDefaultLayoutParams() {
return new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
}
// Override to allow type-checking of LayoutParams.
@Override
protected boolean checkLayoutParams(ViewGroup.LayoutParams p) {
return p instanceof LayoutParams;
}
@Override
protected LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) {
return new LayoutParams(p);
}
public static class LayoutParams extends InsettableFrameLayout.LayoutParams {
public int x, y;
public boolean customPosition = false;
public LayoutParams(Context c, AttributeSet attrs) {
super(c, attrs);
}
public LayoutParams(int width, int height) {
super(width, height);
}
public LayoutParams(ViewGroup.LayoutParams lp) {
super(lp);
}
public void setWidth(int width) {
this.width = width;
}
public int getWidth() {
return width;
}
public void setHeight(int height) {
this.height = height;
}
public int getHeight() {
return height;
}
public void setX(int x) {
this.x = x;
}
public int getX() {
return x;
}
public void setY(int y) {
this.y = y;
}
public int getY() {
return y;
}
}
protected void onLayout(boolean changed, int l, int t, int r, int b) {
super.onLayout(changed, l, t, r, b);
int count = getChildCount();
for (int i = 0; i < count; i++) {
View child = getChildAt(i);
final FrameLayout.LayoutParams flp = (FrameLayout.LayoutParams) child.getLayoutParams();
if (flp instanceof LayoutParams) {
final LayoutParams lp = (LayoutParams) flp;
if (lp.customPosition) {
child.layout(lp.x, lp.y, lp.x + lp.width, lp.y + lp.height);
}
}
}
}
public void animateViewIntoPosition(DragView dragView, final int[] pos, float alpha,
float scaleX, float scaleY, int animationEndStyle, Runnable onFinishRunnable,
int duration) {
@ -709,14 +486,14 @@ public class DragLayer extends InsettableFrameLayout {
public void onViewAdded(View child) {
super.onViewAdded(child);
updateChildIndices();
UiFactory.onLauncherStateOrFocusChanged(mLauncher);
UiFactory.onLauncherStateOrFocusChanged(mActivity);
}
@Override
public void onViewRemoved(View child) {
super.onViewRemoved(child);
updateChildIndices();
UiFactory.onLauncherStateOrFocusChanged(mLauncher);
UiFactory.onLauncherStateOrFocusChanged(mActivity);
}
@Override
@ -768,32 +545,4 @@ public class DragLayer extends InsettableFrameLayout {
mFocusIndicatorHelper.draw(canvas);
super.dispatchDraw(canvas);
}
@Override
protected boolean onRequestFocusInDescendants(int direction, Rect previouslyFocusedRect) {
View topView = AbstractFloatingView.getTopOpenView(mLauncher);
if (topView != null) {
return topView.requestFocus(direction, previouslyFocusedRect);
} else {
return super.onRequestFocusInDescendants(direction, previouslyFocusedRect);
}
}
@Override
public void addFocusables(ArrayList<View> views, int direction, int focusableMode) {
View topView = AbstractFloatingView.getTopOpenView(mLauncher);
if (topView != null) {
topView.addFocusables(views, direction);
} else {
super.addFocusables(views, direction, focusableMode);
}
}
public void setTouchCompleteListener(TouchCompleteListener listener) {
mTouchCompleteListener = listener;
}
public interface TouchCompleteListener {
void onTouchComplete();
}
}

View File

@ -568,7 +568,7 @@ public class FolderIcon extends FrameLayout implements FolderListener {
@Override
public void onAdd(ShortcutInfo item, int rank) {
boolean wasBadged = mBadgeInfo.hasBadge();
mBadgeInfo.addBadgeInfo(mLauncher.getPopupDataProvider().getBadgeInfoForItem(item));
mBadgeInfo.addBadgeInfo(mLauncher.getBadgeInfoForItem(item));
boolean isBadged = mBadgeInfo.hasBadge();
updateBadgeScale(wasBadged, isBadged);
invalidate();
@ -578,7 +578,7 @@ public class FolderIcon extends FrameLayout implements FolderListener {
@Override
public void onRemove(ShortcutInfo item) {
boolean wasBadged = mBadgeInfo.hasBadge();
mBadgeInfo.subtractBadgeInfo(mLauncher.getPopupDataProvider().getBadgeInfoForItem(item));
mBadgeInfo.subtractBadgeInfo(mLauncher.getBadgeInfoForItem(item));
boolean isBadged = mBadgeInfo.hasBadge();
updateBadgeScale(wasBadged, isBadged);
invalidate();

View File

@ -745,7 +745,7 @@ public class PopupContainerWithArrow extends AbstractFloatingView implements Dra
private void updateNotificationHeader() {
ItemInfoWithIcon itemInfo = (ItemInfoWithIcon) mOriginalIcon.getTag();
BadgeInfo badgeInfo = mLauncher.getPopupDataProvider().getBadgeInfoForItem(itemInfo);
BadgeInfo badgeInfo = mLauncher.getBadgeInfoForItem(itemInfo);
if (mNotificationItemView != null && badgeInfo != null) {
mNotificationItemView.updateHeader(
badgeInfo.getNotificationCount(), itemInfo.iconColor);

View File

@ -9,6 +9,7 @@ import android.os.Bundle;
import android.view.View;
import com.android.launcher3.AbstractFloatingView;
import com.android.launcher3.BaseDraggingActivity;
import com.android.launcher3.ItemInfo;
import com.android.launcher3.Launcher;
import com.android.launcher3.R;
@ -27,7 +28,7 @@ import java.util.List;
*
* Example system shortcuts, defined as inner classes, include Widgets and AppInfo.
*/
public abstract class SystemShortcut extends ItemInfo {
public abstract class SystemShortcut<T extends BaseDraggingActivity> extends ItemInfo {
public final int iconResId;
public final int labelResId;
@ -36,10 +37,9 @@ public abstract class SystemShortcut extends ItemInfo {
this.labelResId = labelResId;
}
public abstract View.OnClickListener getOnClickListener(final Launcher launcher,
final ItemInfo itemInfo);
public abstract View.OnClickListener getOnClickListener(T activity, ItemInfo itemInfo);
public static class Widgets extends SystemShortcut {
public static class Widgets extends SystemShortcut<Launcher> {
public Widgets() {
super(R.drawable.ic_widget, R.string.widget_button_text);
@ -54,17 +54,14 @@ public abstract class SystemShortcut extends ItemInfo {
if (widgets == null) {
return null;
}
return new View.OnClickListener() {
@Override
public void onClick(View view) {
AbstractFloatingView.closeAllOpenViews(launcher);
WidgetsBottomSheet widgetsBottomSheet =
(WidgetsBottomSheet) launcher.getLayoutInflater().inflate(
R.layout.widgets_bottom_sheet, launcher.getDragLayer(), false);
widgetsBottomSheet.populateAndShow(itemInfo);
launcher.getUserEventDispatcher().logActionOnControl(Action.Touch.TAP,
ControlType.WIDGETS_BUTTON, view);
}
return (view) -> {
AbstractFloatingView.closeAllOpenViews(launcher);
WidgetsBottomSheet widgetsBottomSheet =
(WidgetsBottomSheet) launcher.getLayoutInflater().inflate(
R.layout.widgets_bottom_sheet, launcher.getDragLayer(), false);
widgetsBottomSheet.populateAndShow(itemInfo);
launcher.getUserEventDispatcher().logActionOnControl(Action.Touch.TAP,
ControlType.WIDGETS_BUTTON, view);
};
}
}
@ -75,18 +72,15 @@ public abstract class SystemShortcut extends ItemInfo {
}
@Override
public View.OnClickListener getOnClickListener(final Launcher launcher,
final ItemInfo itemInfo) {
return new View.OnClickListener() {
@Override
public void onClick(View view) {
Rect sourceBounds = launcher.getViewBounds(view);
Bundle opts = launcher.getActivityLaunchOptionsAsBundle(view, false);
new PackageManagerHelper(launcher).startDetailsActivityForInfo(
itemInfo, sourceBounds, opts);
launcher.getUserEventDispatcher().logActionOnControl(Action.Touch.TAP,
ControlType.APPINFO_TARGET, view);
}
public View.OnClickListener getOnClickListener(
BaseDraggingActivity activity, ItemInfo itemInfo) {
return (view) -> {
Rect sourceBounds = activity.getViewBounds(view);
Bundle opts = activity.getActivityLaunchOptionsAsBundle(view, false);
new PackageManagerHelper(activity).startDetailsActivityForInfo(
itemInfo, sourceBounds, opts);
activity.getUserEventDispatcher().logActionOnControl(Action.Touch.TAP,
ControlType.APPINFO_TARGET, view);
};
}
}
@ -97,28 +91,29 @@ public abstract class SystemShortcut extends ItemInfo {
}
@Override
public View.OnClickListener getOnClickListener(final Launcher launcher,
final ItemInfo itemInfo) {
public View.OnClickListener getOnClickListener(
BaseDraggingActivity activity, ItemInfo itemInfo) {
boolean supportsWebUI = (itemInfo instanceof ShortcutInfo) &&
((ShortcutInfo) itemInfo).hasStatusFlag(ShortcutInfo.FLAG_SUPPORTS_WEB_UI);
boolean isInstantApp = false;
if (itemInfo instanceof com.android.launcher3.AppInfo) {
com.android.launcher3.AppInfo appInfo = (com.android.launcher3.AppInfo) itemInfo;
isInstantApp = InstantAppResolver.newInstance(launcher).isInstantApp(appInfo);
isInstantApp = InstantAppResolver.newInstance(activity).isInstantApp(appInfo);
}
boolean enabled = supportsWebUI || isInstantApp;
if (!enabled) {
return null;
}
return createOnClickListener(launcher, itemInfo);
return createOnClickListener(activity, itemInfo);
}
public View.OnClickListener createOnClickListener(Launcher launcher, ItemInfo itemInfo) {
public View.OnClickListener createOnClickListener(
BaseDraggingActivity activity, ItemInfo itemInfo) {
return view -> {
Intent intent = new PackageManagerHelper(view.getContext()).getMarketIntent(
itemInfo.getTargetComponent().getPackageName());
launcher.startActivitySafely(view, intent, itemInfo);
AbstractFloatingView.closeAllOpenViews(launcher);
activity.startActivitySafely(view, intent, itemInfo);
AbstractFloatingView.closeAllOpenViews(activity);
};
}
}

View File

@ -22,7 +22,6 @@ import android.content.pm.PackageManager;
import android.util.Log;
import com.android.launcher3.AppInfo;
import com.android.launcher3.Launcher;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
@ -47,8 +46,8 @@ public class InstantAppResolver {
return false;
}
public boolean isInstantApp(Launcher launcher, String packageName) {
PackageManager packageManager = launcher.getPackageManager();
public boolean isInstantApp(Context context, String packageName) {
PackageManager packageManager = context.getPackageManager();
try {
return isInstantApp(packageManager.getPackageInfo(packageName, 0).applicationInfo);
} catch (PackageManager.NameNotFoundException e) {

View File

@ -0,0 +1,325 @@
/*
* Copyright (C) 2018 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.launcher3.views;
import android.content.Context;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.accessibility.AccessibilityEvent;
import android.widget.FrameLayout;
import com.android.launcher3.AbstractFloatingView;
import com.android.launcher3.BaseActivity;
import com.android.launcher3.BaseDraggingActivity;
import com.android.launcher3.InsettableFrameLayout;
import com.android.launcher3.Utilities;
import com.android.launcher3.util.TouchController;
import java.util.ArrayList;
/**
* A viewgroup with utility methods for drag-n-drop and touch interception
*/
public abstract class BaseDragLayer<T extends BaseDraggingActivity> extends InsettableFrameLayout {
protected final int[] mTmpXY = new int[2];
protected final Rect mHitRect = new Rect();
protected final T mActivity;
protected TouchController[] mControllers;
protected TouchController mActiveController;
private TouchCompleteListener mTouchCompleteListener;
public BaseDragLayer(Context context, AttributeSet attrs) {
super(context, attrs);
mActivity = (T) BaseActivity.fromContext(context);
}
public boolean isEventOverView(View view, MotionEvent ev) {
getDescendantRectRelativeToSelf(view, mHitRect);
return mHitRect.contains((int) ev.getX(), (int) ev.getY());
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
int action = ev.getAction();
if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) {
if (mTouchCompleteListener != null) {
mTouchCompleteListener.onTouchComplete();
}
mTouchCompleteListener = null;
} else if (action == MotionEvent.ACTION_DOWN) {
mActivity.finishAutoCancelActionMode();
}
return findActiveController(ev);
}
protected boolean findActiveController(MotionEvent ev) {
mActiveController = null;
AbstractFloatingView topView = AbstractFloatingView.getTopOpenView(mActivity);
if (topView != null && topView.onControllerInterceptTouchEvent(ev)) {
mActiveController = topView;
return true;
}
for (TouchController controller : mControllers) {
if (controller.onControllerInterceptTouchEvent(ev)) {
mActiveController = controller;
return true;
}
}
return false;
}
@Override
public boolean onRequestSendAccessibilityEvent(View child, AccessibilityEvent event) {
// Shortcuts can appear above folder
View topView = AbstractFloatingView.getTopOpenView(mActivity);
if (topView != null) {
if (child == topView) {
return super.onRequestSendAccessibilityEvent(child, event);
}
// Skip propagating onRequestSendAccessibilityEvent for all other children
// which are not topView
return false;
}
return super.onRequestSendAccessibilityEvent(child, event);
}
@Override
public void addChildrenForAccessibility(ArrayList<View> childrenForAccessibility) {
View topView = AbstractFloatingView.getTopOpenView(mActivity);
if (topView != null) {
// Only add the top view as a child for accessibility when it is open
childrenForAccessibility.add(topView);
} else {
super.addChildrenForAccessibility(childrenForAccessibility);
}
}
@Override
public boolean onTouchEvent(MotionEvent ev) {
int action = ev.getAction();
if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) {
if (mTouchCompleteListener != null) {
mTouchCompleteListener.onTouchComplete();
}
mTouchCompleteListener = null;
}
if (mActiveController != null) {
return mActiveController.onControllerTouchEvent(ev);
} else {
// In case no child view handled the touch event, we may not get onIntercept anymore
return findActiveController(ev);
}
}
/**
* Determine the rect of the descendant in this DragLayer's coordinates
*
* @param descendant The descendant whose coordinates we want to find.
* @param r The rect into which to place the results.
* @return The factor by which this descendant is scaled relative to this DragLayer.
*/
public float getDescendantRectRelativeToSelf(View descendant, Rect r) {
mTmpXY[0] = 0;
mTmpXY[1] = 0;
float scale = getDescendantCoordRelativeToSelf(descendant, mTmpXY);
r.set(mTmpXY[0], mTmpXY[1],
(int) (mTmpXY[0] + scale * descendant.getMeasuredWidth()),
(int) (mTmpXY[1] + scale * descendant.getMeasuredHeight()));
return scale;
}
public float getLocationInDragLayer(View child, int[] loc) {
loc[0] = 0;
loc[1] = 0;
return getDescendantCoordRelativeToSelf(child, loc);
}
public float getDescendantCoordRelativeToSelf(View descendant, int[] coord) {
return getDescendantCoordRelativeToSelf(descendant, coord, false);
}
/**
* Given a coordinate relative to the descendant, find the coordinate in this DragLayer's
* coordinates.
*
* @param descendant The descendant to which the passed coordinate is relative.
* @param coord The coordinate that we want mapped.
* @param includeRootScroll Whether or not to account for the scroll of the root descendant:
* sometimes this is relevant as in a child's coordinates within the root descendant.
* @return The factor by which this descendant is scaled relative to this DragLayer. Caution
* this scale factor is assumed to be equal in X and Y, and so if at any point this
* assumption fails, we will need to return a pair of scale factors.
*/
public float getDescendantCoordRelativeToSelf(View descendant, int[] coord,
boolean includeRootScroll) {
return Utilities.getDescendantCoordRelativeToAncestor(descendant, this,
coord, includeRootScroll);
}
/**
* Inverse of {@link #getDescendantCoordRelativeToSelf(View, int[])}.
*/
public void mapCoordInSelfToDescendant(View descendant, int[] coord) {
Utilities.mapCoordInSelfToDescendant(descendant, this, coord);
}
public void getViewRectRelativeToSelf(View v, Rect r) {
int[] loc = new int[2];
getLocationInWindow(loc);
int x = loc[0];
int y = loc[1];
v.getLocationInWindow(loc);
int vX = loc[0];
int vY = loc[1];
int left = vX - x;
int top = vY - y;
r.set(left, top, left + v.getMeasuredWidth(), top + v.getMeasuredHeight());
}
@Override
public boolean dispatchUnhandledMove(View focused, int direction) {
// Consume the unhandled move if a container is open, to avoid switching pages underneath.
return AbstractFloatingView.getTopOpenView(mActivity) != null;
}
@Override
protected boolean onRequestFocusInDescendants(int direction, Rect previouslyFocusedRect) {
View topView = AbstractFloatingView.getTopOpenView(mActivity);
if (topView != null) {
return topView.requestFocus(direction, previouslyFocusedRect);
} else {
return super.onRequestFocusInDescendants(direction, previouslyFocusedRect);
}
}
@Override
public void addFocusables(ArrayList<View> views, int direction, int focusableMode) {
View topView = AbstractFloatingView.getTopOpenView(mActivity);
if (topView != null) {
topView.addFocusables(views, direction);
} else {
super.addFocusables(views, direction, focusableMode);
}
}
public void setTouchCompleteListener(TouchCompleteListener listener) {
mTouchCompleteListener = listener;
}
public interface TouchCompleteListener {
void onTouchComplete();
}
@Override
public LayoutParams generateLayoutParams(AttributeSet attrs) {
return new LayoutParams(getContext(), attrs);
}
@Override
protected LayoutParams generateDefaultLayoutParams() {
return new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
}
// Override to allow type-checking of LayoutParams.
@Override
protected boolean checkLayoutParams(ViewGroup.LayoutParams p) {
return p instanceof LayoutParams;
}
@Override
protected LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) {
return new LayoutParams(p);
}
public static class LayoutParams extends InsettableFrameLayout.LayoutParams {
public int x, y;
public boolean customPosition = false;
public LayoutParams(Context c, AttributeSet attrs) {
super(c, attrs);
}
public LayoutParams(int width, int height) {
super(width, height);
}
public LayoutParams(ViewGroup.LayoutParams lp) {
super(lp);
}
public void setWidth(int width) {
this.width = width;
}
public int getWidth() {
return width;
}
public void setHeight(int height) {
this.height = height;
}
public int getHeight() {
return height;
}
public void setX(int x) {
this.x = x;
}
public int getX() {
return x;
}
public void setY(int y) {
this.y = y;
}
public int getY() {
return y;
}
}
protected void onLayout(boolean changed, int l, int t, int r, int b) {
super.onLayout(changed, l, t, r, b);
int count = getChildCount();
for (int i = 0; i < count; i++) {
View child = getChildAt(i);
final FrameLayout.LayoutParams flp = (FrameLayout.LayoutParams) child.getLayoutParams();
if (flp instanceof LayoutParams) {
final LayoutParams lp = (LayoutParams) flp;
if (lp.customPosition) {
child.layout(lp.x, lp.y, lp.x + lp.width, lp.y + lp.height);
}
}
}
}
}

View File

@ -47,7 +47,7 @@ import com.android.launcher3.SimpleOnStylusPressListener;
import com.android.launcher3.StylusEventHelper;
import com.android.launcher3.Utilities;
import com.android.launcher3.dragndrop.DragLayer;
import com.android.launcher3.dragndrop.DragLayer.TouchCompleteListener;
import com.android.launcher3.views.BaseDragLayer.TouchCompleteListener;
import java.util.ArrayList;

View File

@ -25,7 +25,8 @@ import com.android.launcher3.util.TouchController;
public class UiFactory {
public static TouchController[] createTouchControllers(Launcher launcher) {
return new TouchController[] {new AllAppsSwipeController(launcher)};
return new TouchController[] {
launcher.getDragController(), new AllAppsSwipeController(launcher)};
}
public static AccessibilityDelegate newPageIndicatorAccessibilityDelegate() {