mirror of
https://github.com/LawnchairLauncher/lawnchair.git
synced 2026-02-19 10:48:19 +00:00
=> Also fix the widget tray in these non-default grids, and the external shortcut addition flow. The layout was broken as it was scaling with the icon size. Instead keep it fixed which looks much better, similar to how we maintain all apps. => This also fixes a small jump when dragging shortcuts external to Launcher. issue 154169001 Change-Id: Iad1e3859dd6fedccce9b5c6633e64426a4630c31
228 lines
7.1 KiB
Java
228 lines
7.1 KiB
Java
/*
|
|
* 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.widget;
|
|
|
|
import android.appwidget.AppWidgetHostView;
|
|
import android.content.Context;
|
|
import android.graphics.PointF;
|
|
import android.graphics.Rect;
|
|
import android.view.KeyEvent;
|
|
import android.view.View;
|
|
import android.view.ViewDebug;
|
|
import android.view.ViewGroup;
|
|
|
|
import com.android.launcher3.Reorderable;
|
|
import com.android.launcher3.dragndrop.DraggableView;
|
|
|
|
import java.util.ArrayList;
|
|
|
|
/**
|
|
* Extension of AppWidgetHostView with support for controlled keyboard navigation.
|
|
*/
|
|
public abstract class NavigableAppWidgetHostView extends AppWidgetHostView
|
|
implements DraggableView, Reorderable {
|
|
|
|
/**
|
|
* The scaleX and scaleY value such that the widget fits within its cellspans, scaleX = scaleY.
|
|
*/
|
|
private float mScaleToFit = 1f;
|
|
|
|
/**
|
|
* The translation values to center the widget within its cellspans.
|
|
*/
|
|
private final PointF mTranslationForCentering = new PointF(0, 0);
|
|
|
|
private final PointF mTranslationForReorderBounce = new PointF(0, 0);
|
|
private final PointF mTranslationForReorderPreview = new PointF(0, 0);
|
|
private float mScaleForReorderBounce = 1f;
|
|
|
|
@ViewDebug.ExportedProperty(category = "launcher")
|
|
private boolean mChildrenFocused;
|
|
|
|
public NavigableAppWidgetHostView(Context context) {
|
|
super(context);
|
|
}
|
|
|
|
@Override
|
|
public int getDescendantFocusability() {
|
|
return mChildrenFocused ? ViewGroup.FOCUS_BEFORE_DESCENDANTS
|
|
: ViewGroup.FOCUS_BLOCK_DESCENDANTS;
|
|
}
|
|
|
|
@Override
|
|
public boolean dispatchKeyEvent(KeyEvent event) {
|
|
if (mChildrenFocused && event.getKeyCode() == KeyEvent.KEYCODE_ESCAPE
|
|
&& event.getAction() == KeyEvent.ACTION_UP) {
|
|
mChildrenFocused = false;
|
|
requestFocus();
|
|
return true;
|
|
}
|
|
return super.dispatchKeyEvent(event);
|
|
}
|
|
|
|
@Override
|
|
public boolean onKeyDown(int keyCode, KeyEvent event) {
|
|
if (!mChildrenFocused && keyCode == KeyEvent.KEYCODE_ENTER) {
|
|
event.startTracking();
|
|
return true;
|
|
}
|
|
return super.onKeyDown(keyCode, event);
|
|
}
|
|
|
|
@Override
|
|
public boolean onKeyUp(int keyCode, KeyEvent event) {
|
|
if (event.isTracking()) {
|
|
if (!mChildrenFocused && keyCode == KeyEvent.KEYCODE_ENTER) {
|
|
mChildrenFocused = true;
|
|
ArrayList<View> focusableChildren = getFocusables(FOCUS_FORWARD);
|
|
focusableChildren.remove(this);
|
|
int childrenCount = focusableChildren.size();
|
|
switch (childrenCount) {
|
|
case 0:
|
|
mChildrenFocused = false;
|
|
break;
|
|
case 1: {
|
|
if (shouldAllowDirectClick()) {
|
|
focusableChildren.get(0).performClick();
|
|
mChildrenFocused = false;
|
|
return true;
|
|
}
|
|
// continue;
|
|
}
|
|
default:
|
|
focusableChildren.get(0).requestFocus();
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
return super.onKeyUp(keyCode, event);
|
|
}
|
|
|
|
/**
|
|
* For a widget with only a single interactive element, return true if whole widget should act
|
|
* as a single interactive element, and clicking 'enter' should activate the child element
|
|
* directly. Otherwise clicking 'enter' will only move the focus inside the widget.
|
|
*/
|
|
protected abstract boolean shouldAllowDirectClick();
|
|
|
|
@Override
|
|
protected void onFocusChanged(boolean gainFocus, int direction, Rect previouslyFocusedRect) {
|
|
if (gainFocus) {
|
|
mChildrenFocused = false;
|
|
dispatchChildFocus(false);
|
|
}
|
|
super.onFocusChanged(gainFocus, direction, previouslyFocusedRect);
|
|
}
|
|
|
|
@Override
|
|
public void requestChildFocus(View child, View focused) {
|
|
super.requestChildFocus(child, focused);
|
|
dispatchChildFocus(mChildrenFocused && focused != null);
|
|
if (focused != null) {
|
|
focused.setFocusableInTouchMode(false);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void clearChildFocus(View child) {
|
|
super.clearChildFocus(child);
|
|
dispatchChildFocus(false);
|
|
}
|
|
|
|
@Override
|
|
public boolean dispatchUnhandledMove(View focused, int direction) {
|
|
return mChildrenFocused;
|
|
}
|
|
|
|
private void dispatchChildFocus(boolean childIsFocused) {
|
|
// The host view's background changes when selected, to indicate the focus is inside.
|
|
setSelected(childIsFocused);
|
|
}
|
|
|
|
public View getView() {
|
|
return this;
|
|
}
|
|
|
|
private void updateTranslation() {
|
|
super.setTranslationX(mTranslationForReorderBounce.x + mTranslationForReorderPreview.x
|
|
+ mTranslationForCentering.x);
|
|
super.setTranslationY(mTranslationForReorderBounce.y + mTranslationForReorderPreview.y
|
|
+ mTranslationForCentering.y);
|
|
}
|
|
|
|
public void setTranslationForCentering(float x, float y) {
|
|
mTranslationForCentering.set(x, y);
|
|
updateTranslation();
|
|
}
|
|
|
|
public void setReorderBounceOffset(float x, float y) {
|
|
mTranslationForReorderBounce.set(x, y);
|
|
updateTranslation();
|
|
}
|
|
|
|
public void getReorderBounceOffset(PointF offset) {
|
|
offset.set(mTranslationForReorderBounce);
|
|
}
|
|
|
|
@Override
|
|
public void setReorderPreviewOffset(float x, float y) {
|
|
mTranslationForReorderPreview.set(x, y);
|
|
updateTranslation();
|
|
}
|
|
|
|
@Override
|
|
public void getReorderPreviewOffset(PointF offset) {
|
|
offset.set(mTranslationForReorderPreview);
|
|
}
|
|
|
|
private void updateScale() {
|
|
super.setScaleX(mScaleToFit * mScaleForReorderBounce);
|
|
super.setScaleY(mScaleToFit * mScaleForReorderBounce);
|
|
}
|
|
|
|
public void setReorderBounceScale(float scale) {
|
|
mScaleForReorderBounce = scale;
|
|
updateScale();
|
|
}
|
|
|
|
public float getReorderBounceScale() {
|
|
return mScaleForReorderBounce;
|
|
}
|
|
|
|
public void setScaleToFit(float scale) {
|
|
mScaleToFit = scale;
|
|
updateScale();
|
|
}
|
|
|
|
public float getScaleToFit() {
|
|
return mScaleToFit;
|
|
}
|
|
|
|
@Override
|
|
public int getViewType() {
|
|
return DRAGGABLE_WIDGET;
|
|
}
|
|
|
|
@Override
|
|
public void getWorkspaceVisualDragBounds(Rect bounds) {
|
|
int width = (int) (getMeasuredWidth() * mScaleToFit);
|
|
int height = (int) (getMeasuredHeight() * mScaleToFit);
|
|
|
|
bounds.set(0, 0 , width, height);
|
|
}
|
|
}
|