diff options
author | 2018-10-15 18:10:32 +0000 | |
---|---|---|
committer | 2018-10-15 18:10:32 +0000 | |
commit | cf7715511e4e54bfe15d8a24e68403d6e2e34e7f (patch) | |
tree | b35f3dd922a366d8d538564033f0a88ad96300fd | |
parent | 0ac0be2e4f4d0394ae49e0bd3bbd3c80994869cd (diff) | |
parent | c604a10551efb025a988c653c9635c209b2a2e00 (diff) |
Merge "Adding keyboard handling to QsbHostView similar to a normal appwidget view" into ub-launcher3-master
4 files changed, 188 insertions, 103 deletions
diff --git a/res/drawable/qsb_host_view_focus_bg.xml b/res/drawable/qsb_host_view_focus_bg.xml new file mode 100644 index 0000000000..7300b6a6c3 --- /dev/null +++ b/res/drawable/qsb_host_view_focus_bg.xml @@ -0,0 +1,33 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/* +** +** Copyright 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. +*/ +--> + +<!-- Used as the widget host view background when giving focus to a child via keyboard. --> +<selector xmlns:android="http://schemas.android.com/apk/res/android"> + <item android:state_selected="true"> + <shape android:shape="rectangle"> + <stroke android:color="#fff" android:width="2dp" /> + </shape> + </item> + <item android:state_focused="true"> + <shape android:shape="rectangle"> + <solid android:color="@color/focused_background" /> + </shape> + </item> +</selector>
\ No newline at end of file diff --git a/src/com/android/launcher3/qsb/QsbWidgetHostView.java b/src/com/android/launcher3/qsb/QsbWidgetHostView.java index cff5126375..f5ecda3e30 100644 --- a/src/com/android/launcher3/qsb/QsbWidgetHostView.java +++ b/src/com/android/launcher3/qsb/QsbWidgetHostView.java @@ -16,7 +16,6 @@ package com.android.launcher3.qsb; -import android.appwidget.AppWidgetHostView; import android.content.Context; import android.view.LayoutInflater; import android.view.View; @@ -26,17 +25,20 @@ import android.widget.RemoteViews; import com.android.launcher3.Launcher; import com.android.launcher3.R; +import com.android.launcher3.widget.NavigableAppWidgetHostView; /** * Appwidget host view with QSB specific logic. */ -public class QsbWidgetHostView extends AppWidgetHostView { +public class QsbWidgetHostView extends NavigableAppWidgetHostView { @ViewDebug.ExportedProperty(category = "launcher") private int mPreviousOrientation; public QsbWidgetHostView(Context context) { super(context); + setFocusable(true); + setBackgroundResource(R.drawable.qsb_host_view_focus_bg); } @Override @@ -89,4 +91,9 @@ public class QsbWidgetHostView extends AppWidgetHostView { Launcher.getLauncher(v2.getContext()).startSearch("", false, null, true)); return v; } + + @Override + protected boolean shouldAllowDirectClick() { + return true; + } } diff --git a/src/com/android/launcher3/widget/LauncherAppWidgetHostView.java b/src/com/android/launcher3/widget/LauncherAppWidgetHostView.java index 12859c78f4..95f8daabe5 100644 --- a/src/com/android/launcher3/widget/LauncherAppWidgetHostView.java +++ b/src/com/android/launcher3/widget/LauncherAppWidgetHostView.java @@ -16,16 +16,13 @@ package com.android.launcher3.widget; -import android.appwidget.AppWidgetHostView; import android.appwidget.AppWidgetProviderInfo; import android.content.Context; import android.content.res.Configuration; import android.graphics.PointF; -import android.graphics.Rect; import android.os.Handler; import android.os.SystemClock; import android.util.SparseBooleanArray; -import android.view.KeyEvent; import android.view.LayoutInflater; import android.view.MotionEvent; import android.view.View; @@ -49,12 +46,10 @@ import com.android.launcher3.Utilities; import com.android.launcher3.dragndrop.DragLayer; import com.android.launcher3.views.BaseDragLayer.TouchCompleteListener; -import java.util.ArrayList; - /** * {@inheritDoc} */ -public class LauncherAppWidgetHostView extends AppWidgetHostView +public class LauncherAppWidgetHostView extends NavigableAppWidgetHostView implements TouchCompleteListener, View.OnLongClickListener { // Related to the auto-advancing of widgets @@ -75,9 +70,6 @@ public class LauncherAppWidgetHostView extends AppWidgetHostView private float mSlop; - @ViewDebug.ExportedProperty(category = "launcher") - private boolean mChildrenFocused; - private boolean mIsScrollable; private boolean mIsAttachedToWindow; private boolean mIsAutoAdvanceRegistered; @@ -267,98 +259,6 @@ public class LauncherAppWidgetHostView extends AppWidgetHostView } } - @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 (getTag() instanceof ItemInfo) { - ItemInfo item = (ItemInfo) getTag(); - if (item.spanX == 1 && item.spanY == 1) { - focusableChildren.get(0).performClick(); - mChildrenFocused = false; - return true; - } - } - // continue; - } - default: - focusableChildren.get(0).requestFocus(); - return true; - } - } - } - return super.onKeyUp(keyCode, event); - } - - @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 void switchToErrorView() { // Update the widget with 0 Layout id, to reset the view to error view. updateAppWidget(new RemoteViews(getAppWidgetInfo().provider.getPackageName(), 0)); @@ -502,4 +402,13 @@ public class LauncherAppWidgetHostView extends AppWidgetHostView mLauncher.removeItem(this, info, false /* deleteFromDb */); mLauncher.bindAppWidget(info); } + + @Override + protected boolean shouldAllowDirectClick() { + if (getTag() instanceof ItemInfo) { + ItemInfo item = (ItemInfo) getTag(); + return item.spanX == 1 && item.spanY == 1; + } + return false; + } } diff --git a/src/com/android/launcher3/widget/NavigableAppWidgetHostView.java b/src/com/android/launcher3/widget/NavigableAppWidgetHostView.java new file mode 100644 index 0000000000..68b1595eed --- /dev/null +++ b/src/com/android/launcher3/widget/NavigableAppWidgetHostView.java @@ -0,0 +1,136 @@ +/* + * 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.Rect; +import android.view.KeyEvent; +import android.view.View; +import android.view.ViewDebug; +import android.view.ViewGroup; + +import java.util.ArrayList; + +/** + * Extension of AppWidgetHostView with support for controlled keyboard navigation. + */ +public abstract class NavigableAppWidgetHostView extends AppWidgetHostView { + + @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); + } +} |