Merge "Merging search bar with all apps" into ub-launcher3-burnaby-polish
This commit is contained in:
@@ -14,7 +14,25 @@
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<inset xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:drawable="@drawable/quantum_panel"
|
||||
android:insetTop="@dimen/container_bounds_minus_quantum_panel_padding_inset"
|
||||
android:insetBottom="@dimen/container_bounds_minus_quantum_panel_padding_inset" />
|
||||
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item>
|
||||
<shape android:shape="rectangle">
|
||||
<solid android:color="@color/quantum_panel_bg_color" />
|
||||
<corners
|
||||
android:topLeftRadius="2dp"
|
||||
android:topRightRadius="2dp" />
|
||||
</shape>
|
||||
</item>
|
||||
<item
|
||||
android:top="@dimen/all_apps_search_bar_bg_overflow"
|
||||
android:left="@dimen/all_apps_search_bar_bg_overflow"
|
||||
android:right="@dimen/all_apps_search_bar_bg_overflow"
|
||||
android:bottom="0dp">
|
||||
|
||||
<shape android:shape="rectangle">
|
||||
<stroke
|
||||
android:width="@dimen/all_apps_search_bar_divider_width"
|
||||
android:color="#1E000000"/>
|
||||
</shape>
|
||||
</item>
|
||||
</layer-list>
|
||||
@@ -25,6 +25,8 @@
|
||||
|
||||
<com.android.launcher3.DragLayer
|
||||
android:id="@+id/drag_layer"
|
||||
android:clipChildren="false"
|
||||
android:clipToPadding="false"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
|
||||
@@ -26,6 +26,8 @@
|
||||
|
||||
<com.android.launcher3.DragLayer
|
||||
android:id="@+id/drag_layer"
|
||||
android:clipChildren="false"
|
||||
android:clipToPadding="false"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
|
||||
@@ -25,6 +25,8 @@
|
||||
|
||||
<com.android.launcher3.DragLayer
|
||||
android:id="@+id/drag_layer"
|
||||
android:clipChildren="false"
|
||||
android:clipToPadding="false"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
|
||||
@@ -18,40 +18,72 @@
|
||||
will bake the left/right padding into that view's background itself. -->
|
||||
<com.android.launcher3.allapps.AllAppsContainerView
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:launcher="http://schemas.android.com/apk/res-auto"
|
||||
android:id="@+id/apps_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical">
|
||||
android:orientation="vertical"
|
||||
launcher:revealBackground="@drawable/quantum_panel_shape">
|
||||
|
||||
<!-- Both android:focusable and android:focusableInTouchMode are needed for
|
||||
the view to get focus change events. -->
|
||||
<FrameLayout
|
||||
android:id="@+id/search_box_container"
|
||||
<View
|
||||
android:id="@+id/reveal_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_gravity="center"
|
||||
android:focusable="false"
|
||||
android:elevation="2dp"
|
||||
android:visibility="invisible" />
|
||||
|
||||
|
||||
<com.android.launcher3.allapps.AllAppsRecyclerViewContainerView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:id="@+id/main_content"
|
||||
android:visibility="gone"
|
||||
android:layout_gravity="center"
|
||||
android:focusable="true"
|
||||
android:focusableInTouchMode="true"
|
||||
android:visibility="gone" />
|
||||
android:elevation="15dp" >
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/content"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:layout_weight="1">
|
||||
<FrameLayout
|
||||
android:id="@+id/all_apps_reveal"
|
||||
<!-- DO NOT CHANGE THE ID -->
|
||||
<com.android.launcher3.allapps.AllAppsRecyclerView
|
||||
android:id="@+id/apps_list_view"
|
||||
android:theme="@style/Theme.Light.CustomOverscroll"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_gravity="center"
|
||||
android:focusable="false"
|
||||
android:elevation="2dp"
|
||||
android:visibility="invisible" />
|
||||
<include
|
||||
layout="@layout/all_apps_container"
|
||||
android:id="@+id/all_apps_container"
|
||||
android:layout_gravity="center_horizontal|top"
|
||||
android:clipToPadding="false"
|
||||
android:focusable="true"
|
||||
android:layout_marginTop="@dimen/all_apps_search_bar_height"
|
||||
android:descendantFocusability="afterDescendants" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/search_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_gravity="center"
|
||||
android:visibility="gone" />
|
||||
</FrameLayout>
|
||||
android:layout_height="@dimen/all_apps_search_bar_height"
|
||||
android:layout_gravity="start|top"
|
||||
android:orientation="horizontal"
|
||||
android:background="@drawable/all_apps_search_bg" >
|
||||
|
||||
<com.android.launcher3.ExtendedEditText
|
||||
android:id="@+id/search_box_input"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="@android:color/transparent"
|
||||
android:focusableInTouchMode="true"
|
||||
android:gravity="fill_horizontal|center_vertical"
|
||||
android:hint="@string/all_apps_search_bar_hint"
|
||||
android:inputType="text|textNoSuggestions|textCapWords"
|
||||
android:imeOptions="actionSearch|flagNoExtractUi"
|
||||
android:maxLines="1"
|
||||
android:scrollHorizontally="true"
|
||||
android:layout_marginLeft="@dimen/container_fastscroll_thumb_max_width"
|
||||
android:layout_marginRight="@dimen/container_fastscroll_thumb_max_width"
|
||||
android:singleLine="true"
|
||||
android:textColor="#4c4c4c"
|
||||
android:textColorHint="#9c9c9c"
|
||||
android:textSize="16sp" />
|
||||
</LinearLayout>
|
||||
|
||||
</com.android.launcher3.allapps.AllAppsRecyclerViewContainerView>
|
||||
</com.android.launcher3.allapps.AllAppsContainerView>
|
||||
@@ -18,34 +18,29 @@
|
||||
will bake the left/right padding into that view's background itself. -->
|
||||
<com.android.launcher3.widget.WidgetsContainerView
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:launcher="http://schemas.android.com/apk/res-auto"
|
||||
android:id="@+id/widgets_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
android:descendantFocusability="afterDescendants">
|
||||
android:descendantFocusability="afterDescendants"
|
||||
launcher:revealBackground="@drawable/quantum_panel_shape_dark">
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/content"
|
||||
<View
|
||||
android:id="@+id/reveal_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
<FrameLayout
|
||||
android:id="@+id/widgets_reveal_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_gravity="center"
|
||||
android:focusable="false"
|
||||
android:elevation="2dp"
|
||||
android:visibility="invisible" />
|
||||
android:layout_height="match_parent"
|
||||
android:layout_gravity="center"
|
||||
android:focusable="false"
|
||||
android:elevation="2dp"
|
||||
android:visibility="invisible" />
|
||||
|
||||
<!-- DO NOT CHANGE THE ID -->
|
||||
<com.android.launcher3.widget.WidgetsRecyclerView
|
||||
android:id="@+id/widgets_list_view"
|
||||
android:theme="@style/Theme.Dark.CustomOverscroll"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_gravity="center"
|
||||
android:elevation="15dp"
|
||||
android:visibility="gone" />
|
||||
</FrameLayout>
|
||||
<com.android.launcher3.widget.WidgetsRecyclerView
|
||||
android:id="@+id/main_content"
|
||||
android:theme="@style/Theme.Dark.CustomOverscroll"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_gravity="center"
|
||||
android:elevation="15dp"
|
||||
android:visibility="gone" />
|
||||
|
||||
</com.android.launcher3.widget.WidgetsContainerView>
|
||||
@@ -83,6 +83,13 @@
|
||||
<attr name="pageIndicator" format="reference" />
|
||||
</declare-styleable>
|
||||
|
||||
<!-- BaseContainerView specific attributes. These attributes are used to customize
|
||||
AllApps view and WidgetsView in xml. -->
|
||||
<declare-styleable name="BaseContainerView">
|
||||
<!-- Drawable to use for the reveal animation -->
|
||||
<attr name="revealBackground" format="reference" />
|
||||
</declare-styleable>
|
||||
|
||||
<!-- XML attributes used by default_workspace.xml -->
|
||||
<declare-styleable name="Favorite">
|
||||
<attr name="className" format="string" />
|
||||
|
||||
@@ -77,7 +77,7 @@
|
||||
<dimen name="all_apps_grid_view_start_margin">0dp</dimen>
|
||||
<dimen name="all_apps_grid_section_y_offset">8dp</dimen>
|
||||
<dimen name="all_apps_grid_section_text_size">24sp</dimen>
|
||||
<dimen name="all_apps_search_bar_height">48dp</dimen>
|
||||
<dimen name="all_apps_search_bar_height">60dp</dimen>
|
||||
<dimen name="all_apps_search_bar_prediction_bar_padding">8dp</dimen>
|
||||
<dimen name="all_apps_icon_top_bottom_padding">8dp</dimen>
|
||||
<dimen name="all_apps_icon_width_gap">24dp</dimen>
|
||||
@@ -90,7 +90,20 @@
|
||||
<dimen name="all_apps_background_canvas_width">700dp</dimen>
|
||||
<dimen name="all_apps_background_canvas_height">475dp</dimen>
|
||||
|
||||
<!-- Widget tray -->
|
||||
<!-- Search bar in All Apps -->
|
||||
<dimen name="all_apps_header_max_elevation">4dp</dimen>
|
||||
<dimen name="all_apps_header_scroll_to_elevation">16dp</dimen>
|
||||
<dimen name="all_apps_header_shadow_height">6dp</dimen>
|
||||
|
||||
<!-- The overflow is used to create a bottom border, by drawing other three sides
|
||||
outside the bounds. Ensure that:
|
||||
all_apps_search_bar_bg_overflow < (-3 * all_apps_search_bar_divider_width)
|
||||
-6dp is picked at random, any smaller value would do.
|
||||
-->
|
||||
<dimen name="all_apps_search_bar_bg_overflow">-6dp</dimen>
|
||||
<dimen name="all_apps_search_bar_divider_width">1dp</dimen>
|
||||
|
||||
<!-- Widget tray -->
|
||||
<dimen name="widget_container_inset">8dp</dimen>
|
||||
<dimen name="widget_preview_label_vertical_padding">8dp</dimen>
|
||||
<dimen name="widget_preview_label_horizontal_padding">8dp</dimen>
|
||||
|
||||
@@ -56,7 +56,7 @@
|
||||
|
||||
<!-- All Apps -->
|
||||
<!-- Search bar text in the apps view. [CHAR_LIMIT=50] -->
|
||||
<string name="all_apps_search_bar_hint">Search Apps</string>
|
||||
<string name="all_apps_search_bar_hint">Search Apps…</string>
|
||||
<!-- Loading apps text. [CHAR_LIMIT=50] -->
|
||||
<string name="all_apps_loading_message">Loading Apps…</string>
|
||||
<!-- No-search-results text. [CHAR_LIMIT=50] -->
|
||||
|
||||
@@ -17,32 +17,38 @@
|
||||
package com.android.launcher3;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.TypedArray;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.graphics.drawable.InsetDrawable;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.Log;
|
||||
import android.widget.LinearLayout;
|
||||
import android.view.View;
|
||||
import android.widget.FrameLayout;
|
||||
|
||||
/**
|
||||
* A base container view, which supports resizing.
|
||||
*/
|
||||
public abstract class BaseContainerView extends LinearLayout implements Insettable {
|
||||
public abstract class BaseContainerView extends FrameLayout implements Insettable {
|
||||
|
||||
private final static String TAG = "BaseContainerView";
|
||||
|
||||
// The window insets
|
||||
private Rect mInsets = new Rect();
|
||||
private final Rect mInsets = new Rect();
|
||||
// The bounds of the search bar. Only the left, top, right are used to inset the
|
||||
// search bar and the height is determined by the measurement of the layout
|
||||
private Rect mFixedSearchBarBounds = new Rect();
|
||||
// The computed bounds of the search bar
|
||||
private Rect mSearchBarBounds = new Rect();
|
||||
private final Rect mFixedSearchBarBounds = new Rect();
|
||||
// The computed bounds of the container
|
||||
protected Rect mContentBounds = new Rect();
|
||||
protected final Rect mContentBounds = new Rect();
|
||||
// The computed padding to apply to the container to achieve the container bounds
|
||||
private Rect mContentPadding = new Rect();
|
||||
private final Rect mContentPadding = new Rect();
|
||||
// The inset to apply to the edges and between the search bar and the container
|
||||
private int mContainerBoundsInset;
|
||||
private boolean mHasSearchBar;
|
||||
private final int mContainerBoundsInset;
|
||||
|
||||
private final Drawable mRevealDrawable;
|
||||
|
||||
private View mRevealView;
|
||||
private View mContent;
|
||||
|
||||
public BaseContainerView(Context context) {
|
||||
this(context, null);
|
||||
@@ -55,6 +61,19 @@ public abstract class BaseContainerView extends LinearLayout implements Insettab
|
||||
public BaseContainerView(Context context, AttributeSet attrs, int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
mContainerBoundsInset = getResources().getDimensionPixelSize(R.dimen.container_bounds_inset);
|
||||
|
||||
TypedArray a = context.obtainStyledAttributes(attrs,
|
||||
R.styleable.BaseContainerView, defStyleAttr, 0);
|
||||
mRevealDrawable = a.getDrawable(R.styleable.BaseContainerView_revealBackground);
|
||||
a.recycle();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onFinishInflate() {
|
||||
super.onFinishInflate();
|
||||
|
||||
mContent = findViewById(R.id.main_content);
|
||||
mRevealView = findViewById(R.id.reveal_view);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -63,10 +82,6 @@ public abstract class BaseContainerView extends LinearLayout implements Insettab
|
||||
updateBackgroundAndPaddings();
|
||||
}
|
||||
|
||||
protected void setHasSearchBar() {
|
||||
mHasSearchBar = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the search bar bounds for this container view to match.
|
||||
*/
|
||||
@@ -92,47 +107,48 @@ public abstract class BaseContainerView extends LinearLayout implements Insettab
|
||||
*/
|
||||
protected void updateBackgroundAndPaddings() {
|
||||
Rect padding;
|
||||
Rect searchBarBounds = new Rect();
|
||||
if (!isValidSearchBarBounds(mFixedSearchBarBounds)) {
|
||||
// Use the default bounds
|
||||
padding = new Rect(mInsets.left + mContainerBoundsInset,
|
||||
(mHasSearchBar ? 0 : (mInsets.top + mContainerBoundsInset)),
|
||||
mInsets.right + mContainerBoundsInset,
|
||||
mInsets.bottom + mContainerBoundsInset);
|
||||
|
||||
// Special case -- we have the search bar, but no specific bounds, so just give it
|
||||
// the inset bounds without a height.
|
||||
searchBarBounds.set(mInsets.left + mContainerBoundsInset,
|
||||
if (isValidSearchBarBounds(mFixedSearchBarBounds)) {
|
||||
padding = new Rect(
|
||||
mFixedSearchBarBounds.left,
|
||||
mInsets.top + mContainerBoundsInset,
|
||||
getMeasuredWidth() - (mInsets.right + mContainerBoundsInset), 0);
|
||||
} else {
|
||||
// Use the search bounds, if there is a search bar, the bounds will contain
|
||||
// the offsets for the insets so we can ignore that
|
||||
padding = new Rect(mFixedSearchBarBounds.left,
|
||||
(mHasSearchBar ? 0 : (mInsets.top + mContainerBoundsInset)),
|
||||
getMeasuredWidth() - mFixedSearchBarBounds.right,
|
||||
mInsets.bottom + mContainerBoundsInset);
|
||||
|
||||
// Use the search bounds
|
||||
searchBarBounds.set(mFixedSearchBarBounds);
|
||||
mInsets.bottom + mContainerBoundsInset
|
||||
);
|
||||
} else {
|
||||
padding = new Rect(
|
||||
mInsets.left + mContainerBoundsInset,
|
||||
mInsets.top + mContainerBoundsInset,
|
||||
mInsets.right + mContainerBoundsInset,
|
||||
mInsets.bottom + mContainerBoundsInset
|
||||
);
|
||||
}
|
||||
|
||||
// If either the computed container padding has changed, or the computed search bar bounds
|
||||
// has changed, then notify the container
|
||||
if (!padding.equals(mContentPadding) || !searchBarBounds.equals(mSearchBarBounds)) {
|
||||
// The container padding changed, notify the container.
|
||||
if (!padding.equals(mContentPadding)) {
|
||||
mContentPadding.set(padding);
|
||||
mContentBounds.set(padding.left, padding.top,
|
||||
getMeasuredWidth() - padding.right,
|
||||
getMeasuredHeight() - padding.bottom);
|
||||
mSearchBarBounds.set(searchBarBounds);
|
||||
onUpdateBackgroundAndPaddings(mSearchBarBounds, padding);
|
||||
onUpdateBackgroundAndPaddings(padding);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* To be implemented by container views to update themselves when the bounds changes.
|
||||
*/
|
||||
protected abstract void onUpdateBackgroundAndPaddings(Rect searchBarBounds, Rect padding);
|
||||
private void onUpdateBackgroundAndPaddings(Rect padding) {
|
||||
// Apply the top-bottom padding to itself so that the launcher transition is
|
||||
// clipped correctly
|
||||
setPadding(0, padding.top, 0, padding.bottom);
|
||||
|
||||
InsetDrawable background = new InsetDrawable(mRevealDrawable,
|
||||
padding.left, 0, padding.right, 0);
|
||||
mRevealView.setBackground(background.getConstantState().newDrawable());
|
||||
mContent.setBackground(background);
|
||||
|
||||
Rect bgPadding = new Rect();
|
||||
background.getPadding(bgPadding);
|
||||
onUpdateBgPadding(padding, bgPadding);
|
||||
}
|
||||
|
||||
protected abstract void onUpdateBgPadding(Rect padding, Rect bgPadding);
|
||||
|
||||
/**
|
||||
* Returns whether the search bar bounds we got are considered valid.
|
||||
@@ -142,4 +158,12 @@ public abstract class BaseContainerView extends LinearLayout implements Insettab
|
||||
searchBarBounds.right <= getMeasuredWidth() &&
|
||||
searchBarBounds.bottom <= getMeasuredHeight();
|
||||
}
|
||||
|
||||
public final View getContentView() {
|
||||
return mContent;
|
||||
}
|
||||
|
||||
public final View getRevealView() {
|
||||
return mRevealView;
|
||||
}
|
||||
}
|
||||
@@ -97,6 +97,7 @@ import android.widget.Toast;
|
||||
import com.android.launcher3.DropTarget.DragObject;
|
||||
import com.android.launcher3.PagedView.PageSwitchListener;
|
||||
import com.android.launcher3.allapps.AllAppsContainerView;
|
||||
import com.android.launcher3.allapps.DefaultAppSearchController;
|
||||
import com.android.launcher3.compat.AppWidgetManagerCompat;
|
||||
import com.android.launcher3.compat.LauncherActivityInfoCompat;
|
||||
import com.android.launcher3.compat.LauncherAppsCompat;
|
||||
@@ -1408,7 +1409,7 @@ public class Launcher extends Activity
|
||||
if (mLauncherCallbacks != null && mLauncherCallbacks.getAllAppsSearchBarController() != null) {
|
||||
mAppsView.setSearchBarController(mLauncherCallbacks.getAllAppsSearchBarController());
|
||||
} else {
|
||||
mAppsView.setSearchBarController(mAppsView.newDefaultAppSearchController());
|
||||
mAppsView.setSearchBarController(new DefaultAppSearchController());
|
||||
}
|
||||
|
||||
// Setup the drag controller (drop targets have to be added in reverse order in priority)
|
||||
|
||||
@@ -80,13 +80,18 @@ import java.util.HashMap;
|
||||
*/
|
||||
public class LauncherStateTransitionAnimation {
|
||||
|
||||
private static final float FINAL_REVEAL_ALPHA_FOR_WIDGETS = 0.3f;
|
||||
|
||||
/**
|
||||
* Private callbacks made during transition setup.
|
||||
*/
|
||||
static abstract class PrivateTransitionCallbacks {
|
||||
float getMaterialRevealViewFinalAlpha(View revealView) {
|
||||
return 0;
|
||||
private static class PrivateTransitionCallbacks {
|
||||
private final float materialRevealViewFinalAlpha;
|
||||
|
||||
PrivateTransitionCallbacks(float revealAlpha) {
|
||||
materialRevealViewFinalAlpha = revealAlpha;
|
||||
}
|
||||
|
||||
float getMaterialRevealViewStartFinalRadius() {
|
||||
return 0;
|
||||
}
|
||||
@@ -97,7 +102,7 @@ public class LauncherStateTransitionAnimation {
|
||||
void onTransitionComplete() {}
|
||||
}
|
||||
|
||||
public static final String TAG = "LauncherStateTransitionAnimation";
|
||||
public static final String TAG = "LSTAnimation";
|
||||
|
||||
// Flags to determine how to set the layers on views before the transition animation
|
||||
public static final int BUILD_LAYER = 0;
|
||||
@@ -121,11 +126,7 @@ public class LauncherStateTransitionAnimation {
|
||||
final boolean animated, final boolean startSearchAfterTransition) {
|
||||
final AllAppsContainerView toView = mLauncher.getAppsView();
|
||||
final View buttonView = mLauncher.getAllAppsButton();
|
||||
PrivateTransitionCallbacks cb = new PrivateTransitionCallbacks() {
|
||||
@Override
|
||||
public float getMaterialRevealViewFinalAlpha(View revealView) {
|
||||
return 1f;
|
||||
}
|
||||
PrivateTransitionCallbacks cb = new PrivateTransitionCallbacks(1f) {
|
||||
@Override
|
||||
public float getMaterialRevealViewStartFinalRadius() {
|
||||
int allAppsButtonSize = mLauncher.getDeviceProfile().allAppsButtonVisualSize;
|
||||
@@ -152,8 +153,7 @@ public class LauncherStateTransitionAnimation {
|
||||
};
|
||||
// Only animate the search bar if animating from spring loaded mode back to all apps
|
||||
mCurrentAnimation = startAnimationToOverlay(fromWorkspaceState,
|
||||
Workspace.State.NORMAL_HIDDEN, buttonView, toView, toView.getContentView(),
|
||||
toView.getRevealView(), toView.getSearchBarView(), animated, cb);
|
||||
Workspace.State.NORMAL_HIDDEN, buttonView, toView, animated, cb);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -164,15 +164,9 @@ public class LauncherStateTransitionAnimation {
|
||||
final WidgetsContainerView toView = mLauncher.getWidgetsView();
|
||||
final View buttonView = mLauncher.getWidgetsButton();
|
||||
|
||||
PrivateTransitionCallbacks cb = new PrivateTransitionCallbacks() {
|
||||
@Override
|
||||
public float getMaterialRevealViewFinalAlpha(View revealView) {
|
||||
return 0.3f;
|
||||
}
|
||||
};
|
||||
mCurrentAnimation = startAnimationToOverlay(fromWorkspaceState,
|
||||
Workspace.State.OVERVIEW_HIDDEN, buttonView, toView, toView.getContentView(),
|
||||
toView.getRevealView(), null, animated, cb);
|
||||
Workspace.State.OVERVIEW_HIDDEN, buttonView, toView, animated,
|
||||
new PrivateTransitionCallbacks(FINAL_REVEAL_ALPHA_FOR_WIDGETS));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -200,16 +194,15 @@ public class LauncherStateTransitionAnimation {
|
||||
* Creates and starts a new animation to a particular overlay view.
|
||||
*/
|
||||
@SuppressLint("NewApi")
|
||||
private AnimatorSet startAnimationToOverlay(final Workspace.State fromWorkspaceState,
|
||||
final Workspace.State toWorkspaceState, final View buttonView, final View toView,
|
||||
final View contentView, final View revealView, final View overlaySearchBarView,
|
||||
private AnimatorSet startAnimationToOverlay(
|
||||
final Workspace.State fromWorkspaceState, final Workspace.State toWorkspaceState,
|
||||
final View buttonView, final BaseContainerView toView,
|
||||
final boolean animated, final PrivateTransitionCallbacks pCb) {
|
||||
final AnimatorSet animation = LauncherAnimUtils.createAnimatorSet();
|
||||
final Resources res = mLauncher.getResources();
|
||||
final boolean material = Utilities.ATLEAST_LOLLIPOP;
|
||||
final int revealDuration = res.getInteger(R.integer.config_overlayRevealTime);
|
||||
final int itemsAlphaStagger =
|
||||
res.getInteger(R.integer.config_overlayItemsAlphaStagger);
|
||||
final int itemsAlphaStagger = res.getInteger(R.integer.config_overlayItemsAlphaStagger);
|
||||
|
||||
final View fromView = mLauncher.getWorkspace();
|
||||
|
||||
@@ -227,13 +220,17 @@ public class LauncherStateTransitionAnimation {
|
||||
animated, layerViews);
|
||||
|
||||
// Animate the search bar
|
||||
startWorkspaceSearchBarAnimation(animation, fromWorkspaceState, toWorkspaceState,
|
||||
animated ? revealDuration : 0, overlaySearchBarView);
|
||||
startWorkspaceSearchBarAnimation(
|
||||
toWorkspaceState, animated ? revealDuration : 0, animation);
|
||||
|
||||
Animator updateTransitionStepAnim = dispatchOnLauncherTransitionStepAnim(fromView, toView);
|
||||
|
||||
final View contentView = toView.getContentView();
|
||||
|
||||
if (animated && initialized) {
|
||||
// Setup the reveal view animation
|
||||
final View revealView = toView.getRevealView();
|
||||
|
||||
int width = revealView.getMeasuredWidth();
|
||||
int height = revealView.getMeasuredHeight();
|
||||
float revealRadius = (float) Math.hypot(width / 2, height / 2);
|
||||
@@ -247,9 +244,9 @@ public class LauncherStateTransitionAnimation {
|
||||
final float revealViewToXDrift;
|
||||
final float revealViewToYDrift;
|
||||
if (material) {
|
||||
int[] buttonViewToPanelDelta = Utilities.getCenterDeltaInScreenSpace(revealView,
|
||||
buttonView, null);
|
||||
revealViewToAlpha = pCb.getMaterialRevealViewFinalAlpha(revealView);
|
||||
int[] buttonViewToPanelDelta = Utilities.getCenterDeltaInScreenSpace(
|
||||
revealView, buttonView, null);
|
||||
revealViewToAlpha = pCb.materialRevealViewFinalAlpha;
|
||||
revealViewToYDrift = buttonViewToPanelDelta[1];
|
||||
revealViewToXDrift = buttonViewToPanelDelta[0];
|
||||
} else {
|
||||
@@ -274,15 +271,6 @@ public class LauncherStateTransitionAnimation {
|
||||
layerViews.put(revealView, BUILD_AND_SET_LAYER);
|
||||
animation.play(panelAlphaAndDrift);
|
||||
|
||||
if (overlaySearchBarView != null) {
|
||||
overlaySearchBarView.setAlpha(0f);
|
||||
ObjectAnimator searchBarAlpha = ObjectAnimator.ofFloat(overlaySearchBarView, "alpha", 0f, 1f);
|
||||
searchBarAlpha.setDuration(revealDuration / 2);
|
||||
searchBarAlpha.setInterpolator(new AccelerateInterpolator(1.5f));
|
||||
layerViews.put(overlaySearchBarView, BUILD_AND_SET_LAYER);
|
||||
animation.play(searchBarAlpha);
|
||||
}
|
||||
|
||||
// Setup the animation for the content view
|
||||
contentView.setVisibility(View.VISIBLE);
|
||||
contentView.setAlpha(0f);
|
||||
@@ -430,12 +418,8 @@ public class LauncherStateTransitionAnimation {
|
||||
final Workspace.State toWorkspaceState, final int toWorkspacePage,
|
||||
final boolean animated, final Runnable onCompleteRunnable) {
|
||||
AllAppsContainerView appsView = mLauncher.getAppsView();
|
||||
PrivateTransitionCallbacks cb = new PrivateTransitionCallbacks() {
|
||||
@Override
|
||||
float getMaterialRevealViewFinalAlpha(View revealView) {
|
||||
// No alpha anim from all apps
|
||||
return 1f;
|
||||
}
|
||||
// No alpha anim from all apps
|
||||
PrivateTransitionCallbacks cb = new PrivateTransitionCallbacks(1f) {
|
||||
@Override
|
||||
float getMaterialRevealViewStartFinalRadius() {
|
||||
int allAppsButtonSize = mLauncher.getDeviceProfile().allAppsButtonVisualSize;
|
||||
@@ -463,9 +447,8 @@ public class LauncherStateTransitionAnimation {
|
||||
};
|
||||
// Only animate the search bar if animating to spring loaded mode from all apps
|
||||
mCurrentAnimation = startAnimationToWorkspaceFromOverlay(fromWorkspaceState, toWorkspaceState,
|
||||
toWorkspacePage, mLauncher.getAllAppsButton(), appsView, appsView.getContentView(),
|
||||
appsView.getRevealView(), appsView.getSearchBarView(), animated,
|
||||
onCompleteRunnable, cb);
|
||||
toWorkspacePage, mLauncher.getAllAppsButton(), appsView,
|
||||
animated, onCompleteRunnable, cb);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -475,11 +458,8 @@ public class LauncherStateTransitionAnimation {
|
||||
final Workspace.State toWorkspaceState, final int toWorkspacePage,
|
||||
final boolean animated, final Runnable onCompleteRunnable) {
|
||||
final WidgetsContainerView widgetsView = mLauncher.getWidgetsView();
|
||||
PrivateTransitionCallbacks cb = new PrivateTransitionCallbacks() {
|
||||
@Override
|
||||
float getMaterialRevealViewFinalAlpha(View revealView) {
|
||||
return 0.3f;
|
||||
}
|
||||
PrivateTransitionCallbacks cb =
|
||||
new PrivateTransitionCallbacks(FINAL_REVEAL_ALPHA_FOR_WIDGETS) {
|
||||
@Override
|
||||
public AnimatorListenerAdapter getMaterialRevealViewAnimatorListener(
|
||||
final View revealView, final View widgetsButtonView) {
|
||||
@@ -491,19 +471,20 @@ public class LauncherStateTransitionAnimation {
|
||||
};
|
||||
}
|
||||
};
|
||||
mCurrentAnimation = startAnimationToWorkspaceFromOverlay(fromWorkspaceState,
|
||||
toWorkspaceState, toWorkspacePage, mLauncher.getWidgetsButton(), widgetsView,
|
||||
widgetsView.getContentView(), widgetsView.getRevealView(), null, animated,
|
||||
onCompleteRunnable, cb);
|
||||
mCurrentAnimation = startAnimationToWorkspaceFromOverlay(
|
||||
fromWorkspaceState, toWorkspaceState,
|
||||
toWorkspacePage, mLauncher.getWidgetsButton(), widgetsView,
|
||||
animated, onCompleteRunnable, cb);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates and starts a new animation to the workspace.
|
||||
*/
|
||||
private AnimatorSet startAnimationToWorkspaceFromOverlay(final Workspace.State fromWorkspaceState,
|
||||
final Workspace.State toWorkspaceState, final int toWorkspacePage, final View buttonView,
|
||||
final View fromView, final View contentView, final View revealView,
|
||||
final View overlaySearchBarView, final boolean animated, final Runnable onCompleteRunnable,
|
||||
private AnimatorSet startAnimationToWorkspaceFromOverlay(
|
||||
final Workspace.State fromWorkspaceState, final Workspace.State toWorkspaceState,
|
||||
final int toWorkspacePage,
|
||||
final View buttonView, final BaseContainerView fromView,
|
||||
final boolean animated, final Runnable onCompleteRunnable,
|
||||
final PrivateTransitionCallbacks pCb) {
|
||||
final AnimatorSet animation = LauncherAnimUtils.createAnimatorSet();
|
||||
final Resources res = mLauncher.getResources();
|
||||
@@ -528,8 +509,8 @@ public class LauncherStateTransitionAnimation {
|
||||
toWorkspacePage, animated, layerViews);
|
||||
|
||||
// Animate the search bar
|
||||
startWorkspaceSearchBarAnimation(animation, fromWorkspaceState, toWorkspaceState,
|
||||
animated ? revealDuration : 0, overlaySearchBarView);
|
||||
startWorkspaceSearchBarAnimation(
|
||||
toWorkspaceState, animated ? revealDuration : 0, animation);
|
||||
|
||||
Animator updateTransitionStepAnim = dispatchOnLauncherTransitionStepAnim(fromView, toView);
|
||||
|
||||
@@ -540,6 +521,8 @@ public class LauncherStateTransitionAnimation {
|
||||
}
|
||||
|
||||
animation.play(updateTransitionStepAnim);
|
||||
final View revealView = fromView.getRevealView();
|
||||
final View contentView = fromView.getContentView();
|
||||
|
||||
// hideAppsCustomizeHelper is called in some cases when it is already hidden
|
||||
// don't perform all these no-op animations. In particularly, this was causing
|
||||
@@ -588,7 +571,7 @@ public class LauncherStateTransitionAnimation {
|
||||
|
||||
// Setup animation for the reveal panel alpha
|
||||
final float revealViewToAlpha = !material ? 0f :
|
||||
pCb.getMaterialRevealViewFinalAlpha(revealView);
|
||||
pCb.materialRevealViewFinalAlpha;
|
||||
if (revealViewToAlpha != 1f) {
|
||||
ObjectAnimator panelAlpha = ObjectAnimator.ofFloat(revealView, "alpha",
|
||||
1f, revealViewToAlpha);
|
||||
@@ -616,16 +599,6 @@ public class LauncherStateTransitionAnimation {
|
||||
itemsAlpha.setInterpolator(decelerateInterpolator);
|
||||
animation.play(itemsAlpha);
|
||||
|
||||
if (overlaySearchBarView != null) {
|
||||
overlaySearchBarView.setAlpha(1f);
|
||||
ObjectAnimator searchAlpha = ObjectAnimator.ofFloat(overlaySearchBarView, "alpha", 1f, 0f);
|
||||
searchAlpha.setDuration(revealDuration / 2);
|
||||
searchAlpha.setInterpolator(new AccelerateInterpolator(1.5f));
|
||||
searchAlpha.setStartDelay(material ? 0 : itemsAlphaStagger + SINGLE_FRAME_DELAY);
|
||||
layerViews.put(overlaySearchBarView, BUILD_AND_SET_LAYER);
|
||||
animation.play(searchAlpha);
|
||||
}
|
||||
|
||||
if (material) {
|
||||
// Animate the all apps button
|
||||
float finalRadius = pCb.getMaterialRevealViewStartFinalRadius();
|
||||
@@ -671,9 +644,6 @@ public class LauncherStateTransitionAnimation {
|
||||
contentView.setTranslationY(0);
|
||||
contentView.setAlpha(1);
|
||||
}
|
||||
if (overlaySearchBarView != null) {
|
||||
overlaySearchBarView.setAlpha(1f);
|
||||
}
|
||||
|
||||
// This can hold unnecessary references to views.
|
||||
cleanupAnimation();
|
||||
@@ -729,36 +699,11 @@ public class LauncherStateTransitionAnimation {
|
||||
/**
|
||||
* Coordinates the workspace search bar animation along with the launcher state animation.
|
||||
*/
|
||||
private void startWorkspaceSearchBarAnimation(AnimatorSet animation,
|
||||
final Workspace.State fromWorkspaceState, final Workspace.State toWorkspaceState, int duration,
|
||||
View overlaySearchBar) {
|
||||
private void startWorkspaceSearchBarAnimation(
|
||||
final Workspace.State toWorkspaceState, int duration, AnimatorSet animation) {
|
||||
final SearchDropTargetBar.State toSearchBarState =
|
||||
toWorkspaceState.getSearchDropTargetBarState();
|
||||
|
||||
if (overlaySearchBar != null) {
|
||||
if (mLauncher.launcherCallbacksProvidesSearch()) {
|
||||
if ((toWorkspaceState == Workspace.State.NORMAL) &&
|
||||
(fromWorkspaceState == Workspace.State.NORMAL_HIDDEN)) {
|
||||
// If we are transitioning from the overlay to the workspace, then show the
|
||||
// workspace search bar immediately and let the overlay search bar fade out on
|
||||
// top
|
||||
mLauncher.getSearchDropTargetBar().animateToState(toSearchBarState, 0);
|
||||
return;
|
||||
} else if (fromWorkspaceState == Workspace.State.NORMAL) {
|
||||
// If we are transitioning from the workspace to the overlay, then keep the
|
||||
// workspace search bar visible until the overlay search bar fades in on top
|
||||
animation.addListener(new AnimatorListenerAdapter() {
|
||||
@Override
|
||||
public void onAnimationEnd(Animator animation) {
|
||||
mLauncher.getSearchDropTargetBar().animateToState(toSearchBarState, 0);
|
||||
}
|
||||
});
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Fallback to the default search bar animation otherwise
|
||||
mLauncher.getSearchDropTargetBar().animateToState(toSearchBarState, duration);
|
||||
mLauncher.getSearchDropTargetBar().animateToState(toSearchBarState, duration, animation);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -18,12 +18,18 @@ package com.android.launcher3;
|
||||
|
||||
import android.animation.Animator;
|
||||
import android.animation.AnimatorListenerAdapter;
|
||||
import android.animation.AnimatorSet;
|
||||
import android.animation.ObjectAnimator;
|
||||
import android.animation.TimeInterpolator;
|
||||
import android.content.Context;
|
||||
import android.graphics.Rect;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
import android.view.accessibility.AccessibilityManager;
|
||||
import android.view.animation.AccelerateDecelerateInterpolator;
|
||||
import android.view.animation.AccelerateInterpolator;
|
||||
import android.view.animation.DecelerateInterpolator;
|
||||
import android.widget.FrameLayout;
|
||||
|
||||
import com.android.launcher3.util.Thunk;
|
||||
@@ -34,35 +40,32 @@ import com.android.launcher3.util.Thunk;
|
||||
*/
|
||||
public class SearchDropTargetBar extends FrameLayout implements DragController.DragListener {
|
||||
|
||||
private static final TimeInterpolator MOVE_DOWN_INTERPOLATOR = new DecelerateInterpolator(0.6f);
|
||||
private static final TimeInterpolator MOVE_UP_INTERPOLATOR = new DecelerateInterpolator(1.5f);
|
||||
private static final TimeInterpolator DEFAULT_INTERPOLATOR = new AccelerateInterpolator();
|
||||
|
||||
/** The different states that the search bar space can be in. */
|
||||
public enum State {
|
||||
INVISIBLE (0f, 0f),
|
||||
SEARCH_BAR (1f, 0f),
|
||||
DROP_TARGET (0f, 1f);
|
||||
INVISIBLE (0f, 0f, 0f),
|
||||
INVISIBLE_TRANSLATED (0f, 0f, -1f),
|
||||
SEARCH_BAR (1f, 0f, 0f),
|
||||
DROP_TARGET (0f, 1f, 0f);
|
||||
|
||||
private final float mSearchBarAlpha;
|
||||
private final float mDropTargetBarAlpha;
|
||||
private final float mTranslation;
|
||||
|
||||
State(float sbAlpha, float dtbAlpha) {
|
||||
State(float sbAlpha, float dtbAlpha, float translation) {
|
||||
mSearchBarAlpha = sbAlpha;
|
||||
mDropTargetBarAlpha = dtbAlpha;
|
||||
mTranslation = translation;
|
||||
}
|
||||
|
||||
float getSearchBarAlpha() {
|
||||
return mSearchBarAlpha;
|
||||
}
|
||||
|
||||
float getDropTargetBarAlpha() {
|
||||
return mDropTargetBarAlpha;
|
||||
}
|
||||
}
|
||||
|
||||
private static int DEFAULT_DRAG_FADE_DURATION = 175;
|
||||
|
||||
private LauncherViewPropertyAnimator mDropTargetBarAnimator;
|
||||
private LauncherViewPropertyAnimator mQSBSearchBarAnimator;
|
||||
private static final AccelerateInterpolator sAccelerateInterpolator =
|
||||
new AccelerateInterpolator();
|
||||
private AnimatorSet mCurrentAnimation;
|
||||
|
||||
private State mState = State.SEARCH_BAR;
|
||||
@Thunk View mQSB;
|
||||
@@ -117,50 +120,10 @@ public class SearchDropTargetBar extends FrameLayout implements DragController.D
|
||||
// Create the various fade animations
|
||||
mDropTargetBar.setAlpha(0f);
|
||||
AlphaUpdateListener.updateVisibility(mDropTargetBar, mAccessibilityEnabled);
|
||||
|
||||
mDropTargetBarAnimator = new LauncherViewPropertyAnimator(mDropTargetBar);
|
||||
mDropTargetBarAnimator.setInterpolator(sAccelerateInterpolator);
|
||||
mDropTargetBarAnimator.addListener(new AnimatorListenerAdapter() {
|
||||
@Override
|
||||
public void onAnimationStart(Animator animation) {
|
||||
// Ensure that the view is visible for the animation
|
||||
mDropTargetBar.setVisibility(View.VISIBLE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnimationEnd(Animator animation) {
|
||||
if (mDropTargetBar != null) {
|
||||
AlphaUpdateListener.updateVisibility(mDropTargetBar, mAccessibilityEnabled);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void setQsbSearchBar(View qsb) {
|
||||
mQSB = qsb;
|
||||
if (mQSB != null) {
|
||||
// Update the search ber animation
|
||||
mQSBSearchBarAnimator = new LauncherViewPropertyAnimator(mQSB);
|
||||
mQSBSearchBarAnimator.setInterpolator(sAccelerateInterpolator);
|
||||
mQSBSearchBarAnimator.addListener(new AnimatorListenerAdapter() {
|
||||
@Override
|
||||
public void onAnimationStart(Animator animation) {
|
||||
// Ensure that the view is visible for the animation
|
||||
if (mQSB != null) {
|
||||
mQSB.setVisibility(View.VISIBLE);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnimationEnd(Animator animation) {
|
||||
if (mQSB != null) {
|
||||
AlphaUpdateListener.updateVisibility(mQSB, mAccessibilityEnabled);
|
||||
}
|
||||
}
|
||||
});
|
||||
} else {
|
||||
mQSBSearchBarAnimator = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -168,6 +131,10 @@ public class SearchDropTargetBar extends FrameLayout implements DragController.D
|
||||
* the state is applied immediately.
|
||||
*/
|
||||
public void animateToState(State newState, int duration) {
|
||||
animateToState(newState, duration, null);
|
||||
}
|
||||
|
||||
public void animateToState(State newState, int duration, AnimatorSet animation) {
|
||||
if (mState != newState) {
|
||||
mState = newState;
|
||||
|
||||
@@ -176,30 +143,63 @@ public class SearchDropTargetBar extends FrameLayout implements DragController.D
|
||||
getContext().getSystemService(Context.ACCESSIBILITY_SERVICE);
|
||||
mAccessibilityEnabled = am.isEnabled();
|
||||
|
||||
animateViewAlpha(mQSBSearchBarAnimator, mQSB, newState.getSearchBarAlpha(),
|
||||
duration);
|
||||
animateViewAlpha(mDropTargetBarAnimator, mDropTargetBar, newState.getDropTargetBarAlpha(),
|
||||
duration);
|
||||
if (mCurrentAnimation != null) {
|
||||
mCurrentAnimation.cancel();
|
||||
mCurrentAnimation = null;
|
||||
}
|
||||
mCurrentAnimation = null;
|
||||
|
||||
if (duration > 0) {
|
||||
mCurrentAnimation = new AnimatorSet();
|
||||
mCurrentAnimation.setDuration(duration);
|
||||
|
||||
animateAlpha(mDropTargetBar, mState.mDropTargetBarAlpha, DEFAULT_INTERPOLATOR);
|
||||
} else {
|
||||
mDropTargetBar.setAlpha(mState.mDropTargetBarAlpha);
|
||||
AlphaUpdateListener.updateVisibility(mDropTargetBar, mAccessibilityEnabled);
|
||||
}
|
||||
|
||||
if (mQSB != null) {
|
||||
boolean isVertical = ((Launcher) getContext()).getDeviceProfile()
|
||||
.isVerticalBarLayout();
|
||||
float translation = isVertical ? 0 : mState.mTranslation * getMeasuredHeight();
|
||||
|
||||
if (duration > 0) {
|
||||
int translationChange = Float.compare(mQSB.getTranslationY(), translation);
|
||||
|
||||
animateAlpha(mQSB, mState.mSearchBarAlpha,
|
||||
translationChange == 0 ? DEFAULT_INTERPOLATOR
|
||||
: (translationChange < 0 ? MOVE_DOWN_INTERPOLATOR
|
||||
: MOVE_UP_INTERPOLATOR));
|
||||
|
||||
if (translationChange != 0) {
|
||||
mCurrentAnimation.play(
|
||||
ObjectAnimator.ofFloat(mQSB, View.TRANSLATION_Y, translation));
|
||||
}
|
||||
} else {
|
||||
mQSB.setTranslationY(translation);
|
||||
mQSB.setAlpha(mState.mSearchBarAlpha);
|
||||
AlphaUpdateListener.updateVisibility(mQSB, mAccessibilityEnabled);
|
||||
}
|
||||
}
|
||||
|
||||
// Start the final animation
|
||||
if (duration > 0) {
|
||||
if (animation != null) {
|
||||
animation.play(mCurrentAnimation);
|
||||
} else {
|
||||
mCurrentAnimation.start();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience method to animate the alpha of a view using hardware layers.
|
||||
*/
|
||||
private void animateViewAlpha(LauncherViewPropertyAnimator animator, View v, float alpha,
|
||||
int duration) {
|
||||
if (v == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
animator.cancel();
|
||||
private void animateAlpha(View v, float alpha, TimeInterpolator interpolator) {
|
||||
if (Float.compare(v.getAlpha(), alpha) != 0) {
|
||||
if (duration > 0) {
|
||||
animator.alpha(alpha).withLayer().setDuration(duration).start();
|
||||
} else {
|
||||
v.setAlpha(alpha);
|
||||
AlphaUpdateListener.updateVisibility(v, mAccessibilityEnabled);
|
||||
}
|
||||
ObjectAnimator anim = ObjectAnimator.ofFloat(v, View.ALPHA, alpha);
|
||||
anim.setInterpolator(interpolator);
|
||||
anim.addListener(new ViewVisiblilyUpdateHandler(v));
|
||||
mCurrentAnimation.play(anim);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -255,4 +255,24 @@ public class SearchDropTargetBar extends FrameLayout implements DragController.D
|
||||
mDeleteDropTarget.enableAccessibleDrag(enable);
|
||||
mUninstallDropTarget.enableAccessibleDrag(enable);
|
||||
}
|
||||
|
||||
private class ViewVisiblilyUpdateHandler extends AnimatorListenerAdapter {
|
||||
private final View mView;
|
||||
|
||||
ViewVisiblilyUpdateHandler(View v) {
|
||||
mView = v;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnimationStart(Animator animation) {
|
||||
// Ensure that the view is visible for the animation
|
||||
mView.setVisibility(View.VISIBLE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnimationEnd(Animator animation){
|
||||
AlphaUpdateListener.updateVisibility(mView, mAccessibilityEnabled);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -181,7 +181,7 @@ public class Workspace extends PagedView
|
||||
|
||||
enum State {
|
||||
NORMAL (SearchDropTargetBar.State.SEARCH_BAR),
|
||||
NORMAL_HIDDEN (SearchDropTargetBar.State.INVISIBLE),
|
||||
NORMAL_HIDDEN (SearchDropTargetBar.State.INVISIBLE_TRANSLATED),
|
||||
SPRING_LOADED (SearchDropTargetBar.State.DROP_TARGET),
|
||||
OVERVIEW (SearchDropTargetBar.State.INVISIBLE),
|
||||
OVERVIEW_HIDDEN (SearchDropTargetBar.State.INVISIBLE);
|
||||
|
||||
@@ -17,11 +17,9 @@ package com.android.launcher3.allapps;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.Point;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.drawable.InsetDrawable;
|
||||
import android.support.v7.widget.RecyclerView;
|
||||
import android.text.Selection;
|
||||
import android.text.SpannableStringBuilder;
|
||||
@@ -32,8 +30,7 @@ import android.view.LayoutInflater;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.view.ViewConfiguration;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.LinearLayout;
|
||||
|
||||
import com.android.launcher3.AppInfo;
|
||||
import com.android.launcher3.BaseContainerView;
|
||||
import com.android.launcher3.BubbleTextView;
|
||||
@@ -42,6 +39,7 @@ import com.android.launcher3.DeleteDropTarget;
|
||||
import com.android.launcher3.DeviceProfile;
|
||||
import com.android.launcher3.DragSource;
|
||||
import com.android.launcher3.DropTarget;
|
||||
import com.android.launcher3.ExtendedEditText;
|
||||
import com.android.launcher3.Folder;
|
||||
import com.android.launcher3.ItemInfo;
|
||||
import com.android.launcher3.Launcher;
|
||||
@@ -50,7 +48,6 @@ import com.android.launcher3.R;
|
||||
import com.android.launcher3.Utilities;
|
||||
import com.android.launcher3.Workspace;
|
||||
import com.android.launcher3.util.ComponentKey;
|
||||
import com.android.launcher3.util.Thunk;
|
||||
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.charset.CharsetEncoder;
|
||||
@@ -135,19 +132,19 @@ public class AllAppsContainerView extends BaseContainerView implements DragSourc
|
||||
private static final int MIN_ROWS_IN_MERGED_SECTION_PHONE = 3;
|
||||
private static final int MAX_NUM_MERGES_PHONE = 2;
|
||||
|
||||
@Thunk Launcher mLauncher;
|
||||
@Thunk AlphabeticalAppsList mApps;
|
||||
private AllAppsGridAdapter mAdapter;
|
||||
private RecyclerView.LayoutManager mLayoutManager;
|
||||
private RecyclerView.ItemDecoration mItemDecoration;
|
||||
private final Launcher mLauncher;
|
||||
private final AlphabeticalAppsList mApps;
|
||||
private final AllAppsGridAdapter mAdapter;
|
||||
private final RecyclerView.LayoutManager mLayoutManager;
|
||||
private final RecyclerView.ItemDecoration mItemDecoration;
|
||||
|
||||
private AllAppsRecyclerView mAppsRecyclerView;
|
||||
private AllAppsSearchBarController mSearchBarController;
|
||||
|
||||
private View mSearchContainer;
|
||||
private ExtendedEditText mSearchInput;
|
||||
private HeaderElevationController mElevationController;
|
||||
|
||||
@Thunk View mContent;
|
||||
@Thunk View mContainerView;
|
||||
@Thunk View mRevealView;
|
||||
@Thunk AllAppsRecyclerView mAppsRecyclerView;
|
||||
@Thunk AllAppsSearchBarController mSearchBarController;
|
||||
private ViewGroup mSearchBarContainerView;
|
||||
private View mSearchBarView;
|
||||
private SpannableStringBuilder mSearchQueryBuilder = null;
|
||||
|
||||
private int mSectionNamesMargin;
|
||||
@@ -159,14 +156,6 @@ public class AllAppsContainerView extends BaseContainerView implements DragSourc
|
||||
// This coordinate is relative to its parent
|
||||
private final Point mIconLastTouchPos = new Point();
|
||||
|
||||
private View.OnClickListener mSearchClickListener = new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
Intent searchIntent = (Intent) v.getTag();
|
||||
mLauncher.startActivitySafely(v, searchIntent, null);
|
||||
}
|
||||
};
|
||||
|
||||
public AllAppsContainerView(Context context) {
|
||||
this(context, null);
|
||||
}
|
||||
@@ -236,14 +225,7 @@ public class AllAppsContainerView extends BaseContainerView implements DragSourc
|
||||
throw new RuntimeException("Expected search bar controller to only be set once");
|
||||
}
|
||||
mSearchBarController = searchController;
|
||||
mSearchBarController.initialize(mApps, this);
|
||||
|
||||
// Add the new search view to the layout
|
||||
View searchBarView = searchController.getView(mSearchBarContainerView);
|
||||
mSearchBarContainerView.addView(searchBarView);
|
||||
mSearchBarContainerView.setVisibility(View.VISIBLE);
|
||||
mSearchBarView = searchBarView;
|
||||
setHasSearchBar();
|
||||
mSearchBarController.initialize(mApps, mSearchInput, mAppsRecyclerView, this);
|
||||
|
||||
updateBackgroundAndPaddings();
|
||||
}
|
||||
@@ -255,34 +237,6 @@ public class AllAppsContainerView extends BaseContainerView implements DragSourc
|
||||
mAppsRecyclerView.scrollToTop();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the content view used for the launcher transitions.
|
||||
*/
|
||||
public View getContentView() {
|
||||
return mContainerView;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the all apps search view.
|
||||
*/
|
||||
public View getSearchBarView() {
|
||||
return mSearchBarView;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the reveal view used for the launcher transitions.
|
||||
*/
|
||||
public View getRevealView() {
|
||||
return mRevealView;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an new instance of the default app search controller.
|
||||
*/
|
||||
public AllAppsSearchBarController newDefaultAppSearchController() {
|
||||
return new DefaultAppSearchController(getContext(), this, mAppsRecyclerView);
|
||||
}
|
||||
|
||||
/**
|
||||
* Focuses the search field and begins an app search.
|
||||
*/
|
||||
@@ -304,25 +258,24 @@ public class AllAppsContainerView extends BaseContainerView implements DragSourc
|
||||
@Override
|
||||
protected void onFinishInflate() {
|
||||
super.onFinishInflate();
|
||||
boolean isRtl = Utilities.isRtl(getResources());
|
||||
mAdapter.setRtl(isRtl);
|
||||
mContent = findViewById(R.id.content);
|
||||
mAdapter.setRtl(Utilities.isRtl(getResources()));
|
||||
|
||||
// This is a focus listener that proxies focus from a view into the list view. This is to
|
||||
// work around the search box from getting first focus and showing the cursor.
|
||||
View.OnFocusChangeListener focusProxyListener = new View.OnFocusChangeListener() {
|
||||
getContentView().setOnFocusChangeListener(new View.OnFocusChangeListener() {
|
||||
@Override
|
||||
public void onFocusChange(View v, boolean hasFocus) {
|
||||
if (hasFocus) {
|
||||
mAppsRecyclerView.requestFocus();
|
||||
}
|
||||
}
|
||||
};
|
||||
mSearchBarContainerView = (ViewGroup) findViewById(R.id.search_box_container);
|
||||
mSearchBarContainerView.setOnFocusChangeListener(focusProxyListener);
|
||||
mContainerView = findViewById(R.id.all_apps_container);
|
||||
mContainerView.setOnFocusChangeListener(focusProxyListener);
|
||||
mRevealView = findViewById(R.id.all_apps_reveal);
|
||||
});
|
||||
|
||||
mSearchContainer = findViewById(R.id.search_container);
|
||||
mSearchInput = (ExtendedEditText) findViewById(R.id.search_box_input);
|
||||
mElevationController = Utilities.ATLEAST_LOLLIPOP
|
||||
? new HeaderElevationController.ControllerVL(mSearchContainer)
|
||||
: new HeaderElevationController.ControllerV16(mSearchContainer);
|
||||
|
||||
// Load the all apps recycler view
|
||||
mAppsRecyclerView = (AllAppsRecyclerView) findViewById(R.id.apps_list_view);
|
||||
@@ -330,22 +283,28 @@ public class AllAppsContainerView extends BaseContainerView implements DragSourc
|
||||
mAppsRecyclerView.setLayoutManager(mLayoutManager);
|
||||
mAppsRecyclerView.setAdapter(mAdapter);
|
||||
mAppsRecyclerView.setHasFixedSize(true);
|
||||
mAppsRecyclerView.addOnScrollListener(mElevationController);
|
||||
mAppsRecyclerView.setElevationController(mElevationController);
|
||||
|
||||
if (mItemDecoration != null) {
|
||||
mAppsRecyclerView.addItemDecoration(mItemDecoration);
|
||||
}
|
||||
|
||||
// Precalculate the prediction icon and normal icon sizes
|
||||
LayoutInflater layoutInflater = LayoutInflater.from(getContext());
|
||||
final int widthMeasureSpec = MeasureSpec.makeMeasureSpec(
|
||||
getResources().getDisplayMetrics().widthPixels, MeasureSpec.AT_MOST);
|
||||
final int heightMeasureSpec = MeasureSpec.makeMeasureSpec(
|
||||
getResources().getDisplayMetrics().heightPixels, MeasureSpec.AT_MOST);
|
||||
|
||||
BubbleTextView icon = (BubbleTextView) layoutInflater.inflate(
|
||||
R.layout.all_apps_icon, this, false);
|
||||
icon.applyDummyInfo();
|
||||
icon.measure(MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE, MeasureSpec.AT_MOST),
|
||||
MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE, MeasureSpec.AT_MOST));
|
||||
icon.measure(widthMeasureSpec, heightMeasureSpec);
|
||||
BubbleTextView predIcon = (BubbleTextView) layoutInflater.inflate(
|
||||
R.layout.all_apps_prediction_bar_icon, this, false);
|
||||
predIcon.applyDummyInfo();
|
||||
predIcon.measure(MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE, MeasureSpec.AT_MOST),
|
||||
MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE, MeasureSpec.AT_MOST));
|
||||
predIcon.measure(widthMeasureSpec, heightMeasureSpec);
|
||||
mAppsRecyclerView.setPremeasuredIconHeights(predIcon.getMeasuredHeight(),
|
||||
icon.getMeasuredHeight());
|
||||
|
||||
@@ -360,8 +319,11 @@ public class AllAppsContainerView extends BaseContainerView implements DragSourc
|
||||
@Override
|
||||
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
||||
// Update the number of items in the grid before we measure the view
|
||||
int availableWidth = !mContentBounds.isEmpty() ? mContentBounds.width() :
|
||||
MeasureSpec.getSize(widthMeasureSpec);
|
||||
// TODO: mSectionNamesMargin is currently 0, but also account for it,
|
||||
// if it's enabled in the future.
|
||||
int availableWidth = (!mContentBounds.isEmpty() ? mContentBounds.width() :
|
||||
MeasureSpec.getSize(widthMeasureSpec))
|
||||
- 2 * mAppsRecyclerView.getMaxScrollbarWidth();
|
||||
DeviceProfile grid = mLauncher.getDeviceProfile();
|
||||
grid.updateAppsViewNumCols(getResources(), availableWidth);
|
||||
if (mNumAppsPerRow != grid.allAppsNumCols ||
|
||||
@@ -380,6 +342,12 @@ public class AllAppsContainerView extends BaseContainerView implements DragSourc
|
||||
mAppsRecyclerView.setNumAppsPerRow(grid, mNumAppsPerRow);
|
||||
mAdapter.setNumAppsPerRow(mNumAppsPerRow);
|
||||
mApps.setNumAppsPerRow(mNumAppsPerRow, mNumPredictedAppsPerRow, mergeAlgorithm);
|
||||
|
||||
if (mNumAppsPerRow > 0) {
|
||||
int iconSize = availableWidth / mNumAppsPerRow;
|
||||
int iconSpacing = (iconSize - grid.allAppsIconSizePx) / 2;
|
||||
mSearchInput.setPaddingRelative(iconSpacing, 0, iconSpacing, 0);
|
||||
}
|
||||
}
|
||||
|
||||
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
|
||||
@@ -391,51 +359,33 @@ public class AllAppsContainerView extends BaseContainerView implements DragSourc
|
||||
* recycler view to handle touch events (for fast scrolling) all the way to the edge.
|
||||
*/
|
||||
@Override
|
||||
protected void onUpdateBackgroundAndPaddings(Rect searchBarBounds, Rect padding) {
|
||||
boolean isRtl = Utilities.isRtl(getResources());
|
||||
|
||||
// TODO: Use quantum_panel instead of quantum_panel_shape
|
||||
InsetDrawable background = new InsetDrawable(
|
||||
getResources().getDrawable(R.drawable.quantum_panel_shape), padding.left, 0,
|
||||
padding.right, 0);
|
||||
Rect bgPadding = new Rect();
|
||||
background.getPadding(bgPadding);
|
||||
mContainerView.setBackground(background);
|
||||
mRevealView.setBackground(background.getConstantState().newDrawable());
|
||||
protected void onUpdateBgPadding(Rect padding, Rect bgPadding) {
|
||||
mAppsRecyclerView.updateBackgroundPadding(bgPadding);
|
||||
mAdapter.updateBackgroundPadding(bgPadding);
|
||||
mElevationController.updateBackgroundPadding(bgPadding);
|
||||
|
||||
// Hack: We are going to let the recycler view take the full width, so reset the padding on
|
||||
// the container to zero after setting the background and apply the top-bottom padding to
|
||||
// the content view instead so that the launcher transition clips correctly.
|
||||
mContent.setPadding(0, padding.top, 0, padding.bottom);
|
||||
mContainerView.setPadding(0, 0, 0, 0);
|
||||
getContentView().setPadding(0, 0, 0, 0);
|
||||
|
||||
// Pad the recycler view by the background padding plus the start margin (for the section
|
||||
// names)
|
||||
int startInset = Math.max(mSectionNamesMargin, mAppsRecyclerView.getMaxScrollbarWidth());
|
||||
int maxScrollBarWidth = mAppsRecyclerView.getMaxScrollbarWidth();
|
||||
int startInset = Math.max(mSectionNamesMargin, maxScrollBarWidth);
|
||||
int topBottomPadding = mRecyclerViewTopBottomPadding;
|
||||
if (isRtl) {
|
||||
mAppsRecyclerView.setPadding(padding.left + mAppsRecyclerView.getMaxScrollbarWidth(),
|
||||
if (Utilities.isRtl(getResources())) {
|
||||
mAppsRecyclerView.setPadding(padding.left + maxScrollBarWidth,
|
||||
topBottomPadding, padding.right + startInset, topBottomPadding);
|
||||
} else {
|
||||
mAppsRecyclerView.setPadding(padding.left + startInset, topBottomPadding,
|
||||
padding.right + mAppsRecyclerView.getMaxScrollbarWidth(), topBottomPadding);
|
||||
padding.right + maxScrollBarWidth, topBottomPadding);
|
||||
}
|
||||
|
||||
// Inset the search bar to fit its bounds above the container
|
||||
if (mSearchBarView != null) {
|
||||
Rect backgroundPadding = new Rect();
|
||||
if (mSearchBarView.getBackground() != null) {
|
||||
mSearchBarView.getBackground().getPadding(backgroundPadding);
|
||||
}
|
||||
LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams)
|
||||
mSearchBarContainerView.getLayoutParams();
|
||||
lp.leftMargin = searchBarBounds.left - backgroundPadding.left;
|
||||
lp.topMargin = searchBarBounds.top - backgroundPadding.top;
|
||||
lp.rightMargin = (getMeasuredWidth() - searchBarBounds.right) - backgroundPadding.right;
|
||||
mSearchBarContainerView.requestLayout();
|
||||
}
|
||||
MarginLayoutParams lp = (MarginLayoutParams) mSearchContainer.getLayoutParams();
|
||||
lp.leftMargin = padding.left;
|
||||
lp.rightMargin = padding.right;
|
||||
mSearchContainer.setLayoutParams(lp);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -53,6 +53,8 @@ public class AllAppsRecyclerView extends BaseRecyclerView
|
||||
private AllAppsBackgroundDrawable mEmptySearchBackground;
|
||||
private int mEmptySearchBackgroundTopOffset;
|
||||
|
||||
private HeaderElevationController mElevationController;
|
||||
|
||||
public AllAppsRecyclerView(Context context) {
|
||||
this(context, null);
|
||||
}
|
||||
@@ -83,6 +85,10 @@ public class AllAppsRecyclerView extends BaseRecyclerView
|
||||
mFastScrollHelper = new AllAppsFastScrollHelper(this, apps);
|
||||
}
|
||||
|
||||
public void setElevationController(HeaderElevationController elevationController) {
|
||||
mElevationController = elevationController;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the number of apps per row in this recycler view.
|
||||
*/
|
||||
@@ -116,6 +122,9 @@ public class AllAppsRecyclerView extends BaseRecyclerView
|
||||
mScrollbar.reattachThumbToScroll();
|
||||
}
|
||||
scrollToPosition(0);
|
||||
if (mElevationController != null) {
|
||||
mElevationController.reset();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -15,65 +15,179 @@
|
||||
*/
|
||||
package com.android.launcher3.allapps;
|
||||
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.graphics.Rect;
|
||||
import android.text.Editable;
|
||||
import android.text.TextWatcher;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.inputmethod.EditorInfo;
|
||||
import android.view.inputmethod.InputMethodManager;
|
||||
import android.widget.TextView;
|
||||
import android.widget.TextView.OnEditorActionListener;
|
||||
|
||||
import com.android.launcher3.ExtendedEditText;
|
||||
import com.android.launcher3.Utilities;
|
||||
import com.android.launcher3.util.ComponentKey;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* An interface to a search box that AllApps can command.
|
||||
*/
|
||||
public abstract class AllAppsSearchBarController {
|
||||
public abstract class AllAppsSearchBarController
|
||||
implements TextWatcher, OnEditorActionListener, ExtendedEditText.OnBackKeyListener {
|
||||
|
||||
private static final boolean ALLOW_SINGLE_APP_LAUNCH = true;
|
||||
|
||||
protected AllAppsRecyclerView mAppsRecyclerView;
|
||||
protected AlphabeticalAppsList mApps;
|
||||
protected Callbacks mCb;
|
||||
protected ExtendedEditText mInput;
|
||||
|
||||
protected DefaultAppSearchAlgorithm mSearchAlgorithm;
|
||||
protected InputMethodManager mInputMethodManager;
|
||||
|
||||
/**
|
||||
* Sets the references to the apps model and the search result callback.
|
||||
*/
|
||||
public final void initialize(AlphabeticalAppsList apps, Callbacks cb) {
|
||||
public final void initialize(
|
||||
AlphabeticalAppsList apps, ExtendedEditText input,
|
||||
AllAppsRecyclerView recycleView, Callbacks cb) {
|
||||
mApps = apps;
|
||||
mCb = cb;
|
||||
onInitialize();
|
||||
mAppsRecyclerView = recycleView;
|
||||
|
||||
mInput = input;
|
||||
mInput.addTextChangedListener(this);
|
||||
mInput.setOnEditorActionListener(this);
|
||||
mInput.setOnBackKeyListener(this);
|
||||
|
||||
mInputMethodManager = (InputMethodManager)
|
||||
mInput.getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
|
||||
|
||||
mSearchAlgorithm = onInitializeSearch();
|
||||
}
|
||||
|
||||
/**
|
||||
* To be overridden by subclasses. This method will get called when the controller is set,
|
||||
* before getView().
|
||||
* To be overridden by subclasses. This method will get called when the controller is set.
|
||||
*/
|
||||
protected abstract void onInitialize();
|
||||
protected DefaultAppSearchAlgorithm onInitializeSearch() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTextChanged(CharSequence s, int start, int before, int count) {
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterTextChanged(final Editable s) {
|
||||
String query = s.toString();
|
||||
if (query.isEmpty()) {
|
||||
mSearchAlgorithm.cancel(true);
|
||||
mCb.clearSearchResult();
|
||||
} else {
|
||||
mSearchAlgorithm.cancel(false);
|
||||
mSearchAlgorithm.doSearch(query, mCb);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
|
||||
// Skip if we disallow app-launch-on-enter
|
||||
if (!ALLOW_SINGLE_APP_LAUNCH) {
|
||||
return false;
|
||||
}
|
||||
// Skip if it's not the right action
|
||||
if (actionId != EditorInfo.IME_ACTION_SEARCH) {
|
||||
return false;
|
||||
}
|
||||
// Skip if there are more than one icon
|
||||
if (mApps.getNumFilteredApps() > 1) {
|
||||
return false;
|
||||
}
|
||||
// Otherwise, find the first icon, or fallback to the search-market-view and launch it
|
||||
List<AlphabeticalAppsList.AdapterItem> items = mApps.getAdapterItems();
|
||||
for (int i = 0; i < items.size(); i++) {
|
||||
AlphabeticalAppsList.AdapterItem item = items.get(i);
|
||||
switch (item.viewType) {
|
||||
case AllAppsGridAdapter.ICON_VIEW_TYPE:
|
||||
case AllAppsGridAdapter.SEARCH_MARKET_VIEW_TYPE:
|
||||
mAppsRecyclerView.getChildAt(i).performClick();
|
||||
mInputMethodManager.hideSoftInputFromWindow(mInput.getWindowToken(), 0);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onBackKey() {
|
||||
// Only hide the search field if there is no query, or if there
|
||||
// are no filtered results
|
||||
String query = Utilities.trim(mInput.getEditableText().toString());
|
||||
if (query.isEmpty() || mApps.hasNoFilteredResults()) {
|
||||
reset();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the search bar state.
|
||||
*/
|
||||
public void reset() {
|
||||
unfocusSearchField();
|
||||
mCb.clearSearchResult();
|
||||
mInput.setText("");
|
||||
mInputMethodManager.hideSoftInputFromWindow(mInput.getWindowToken(), 0);
|
||||
}
|
||||
|
||||
protected void unfocusSearchField() {
|
||||
View nextFocus = mInput.focusSearch(View.FOCUS_DOWN);
|
||||
if (nextFocus != null) {
|
||||
nextFocus.requestFocus();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the search bar view.
|
||||
* @param parent the parent to attach the search bar view to.
|
||||
*/
|
||||
public abstract View getView(ViewGroup parent);
|
||||
public View getView(ViewGroup parent) {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Focuses the search field to handle key events.
|
||||
*/
|
||||
public abstract void focusSearchField();
|
||||
public void focusSearchField() {
|
||||
mInput.requestFocus();
|
||||
mInputMethodManager.showSoftInput(mInput, InputMethodManager.SHOW_IMPLICIT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the search field is focused.
|
||||
*/
|
||||
public abstract boolean isSearchFieldFocused();
|
||||
|
||||
/**
|
||||
* Resets the search bar state.
|
||||
*/
|
||||
public abstract void reset();
|
||||
public boolean isSearchFieldFocused() {
|
||||
return mInput.isFocused();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the prediction bar should currently be visible depending on the state of
|
||||
* the search bar.
|
||||
*/
|
||||
@Deprecated
|
||||
public abstract boolean shouldShowPredictionBar();
|
||||
public boolean shouldShowPredictionBar() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback for getting search results.
|
||||
|
||||
@@ -15,261 +15,12 @@
|
||||
*/
|
||||
package com.android.launcher3.allapps;
|
||||
|
||||
import android.content.Context;
|
||||
import android.text.Editable;
|
||||
import android.text.TextWatcher;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.inputmethod.EditorInfo;
|
||||
import android.view.inputmethod.InputMethodManager;
|
||||
import android.widget.TextView;
|
||||
import com.android.launcher3.ExtendedEditText;
|
||||
import com.android.launcher3.R;
|
||||
import com.android.launcher3.Utilities;
|
||||
import com.android.launcher3.util.Thunk;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
|
||||
/**
|
||||
* The default search controller.
|
||||
*/
|
||||
final class DefaultAppSearchController extends AllAppsSearchBarController
|
||||
implements TextWatcher, TextView.OnEditorActionListener, View.OnClickListener {
|
||||
public class DefaultAppSearchController extends AllAppsSearchBarController {
|
||||
|
||||
private static final boolean ALLOW_SINGLE_APP_LAUNCH = true;
|
||||
|
||||
private static final int FADE_IN_DURATION = 175;
|
||||
private static final int FADE_OUT_DURATION = 100;
|
||||
private static final int SEARCH_TRANSLATION_X_DP = 18;
|
||||
|
||||
private final Context mContext;
|
||||
@Thunk final InputMethodManager mInputMethodManager;
|
||||
|
||||
private DefaultAppSearchAlgorithm mSearchManager;
|
||||
|
||||
private ViewGroup mContainerView;
|
||||
private View mSearchView;
|
||||
@Thunk View mSearchBarContainerView;
|
||||
private View mSearchButtonView;
|
||||
private View mDismissSearchButtonView;
|
||||
@Thunk
|
||||
ExtendedEditText mSearchBarEditView;
|
||||
@Thunk AllAppsRecyclerView mAppsRecyclerView;
|
||||
@Thunk Runnable mFocusRecyclerViewRunnable = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
mAppsRecyclerView.requestFocus();
|
||||
}
|
||||
};
|
||||
|
||||
public DefaultAppSearchController(Context context, ViewGroup containerView,
|
||||
AllAppsRecyclerView appsRecyclerView) {
|
||||
mContext = context;
|
||||
mInputMethodManager = (InputMethodManager)
|
||||
mContext.getSystemService(Context.INPUT_METHOD_SERVICE);
|
||||
mContainerView = containerView;
|
||||
mAppsRecyclerView = appsRecyclerView;
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getView(ViewGroup parent) {
|
||||
LayoutInflater inflater = LayoutInflater.from(parent.getContext());
|
||||
mSearchView = inflater.inflate(R.layout.all_apps_search_bar, parent, false);
|
||||
mSearchView.setOnClickListener(this);
|
||||
|
||||
mSearchButtonView = mSearchView.findViewById(R.id.search_button);
|
||||
mSearchBarContainerView = mSearchView.findViewById(R.id.search_container);
|
||||
mDismissSearchButtonView = mSearchBarContainerView.findViewById(R.id.dismiss_search_button);
|
||||
mDismissSearchButtonView.setOnClickListener(this);
|
||||
mSearchBarEditView = (ExtendedEditText)
|
||||
mSearchBarContainerView.findViewById(R.id.search_box_input);
|
||||
mSearchBarEditView.addTextChangedListener(this);
|
||||
mSearchBarEditView.setOnEditorActionListener(this);
|
||||
mSearchBarEditView.setOnBackKeyListener(
|
||||
new ExtendedEditText.OnBackKeyListener() {
|
||||
@Override
|
||||
public boolean onBackKey() {
|
||||
// Only hide the search field if there is no query, or if there
|
||||
// are no filtered results
|
||||
String query = Utilities.trim(
|
||||
mSearchBarEditView.getEditableText().toString());
|
||||
if (query.isEmpty() || mApps.hasNoFilteredResults()) {
|
||||
hideSearchField(true, mFocusRecyclerViewRunnable);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
});
|
||||
return mSearchView;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void focusSearchField() {
|
||||
mSearchBarEditView.requestFocus();
|
||||
showSearchField();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSearchFieldFocused() {
|
||||
return mSearchBarEditView.isFocused();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onInitialize() {
|
||||
mSearchManager = new DefaultAppSearchAlgorithm(mApps.getApps());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reset() {
|
||||
hideSearchField(false, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldShowPredictionBar() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
if (v == mSearchView) {
|
||||
showSearchField();
|
||||
} else if (v == mDismissSearchButtonView) {
|
||||
hideSearchField(true, mFocusRecyclerViewRunnable);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTextChanged(CharSequence s, int start, int before, int count) {
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterTextChanged(final Editable s) {
|
||||
String query = s.toString();
|
||||
if (query.isEmpty()) {
|
||||
mSearchManager.cancel(true);
|
||||
mCb.clearSearchResult();
|
||||
} else {
|
||||
mSearchManager.cancel(false);
|
||||
mSearchManager.doSearch(query, mCb);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
|
||||
// Skip if we disallow app-launch-on-enter
|
||||
if (!ALLOW_SINGLE_APP_LAUNCH) {
|
||||
return false;
|
||||
}
|
||||
// Skip if it's not the right action
|
||||
if (actionId != EditorInfo.IME_ACTION_SEARCH) {
|
||||
return false;
|
||||
}
|
||||
// Skip if there are more than one icon
|
||||
if (mApps.getNumFilteredApps() > 1) {
|
||||
return false;
|
||||
}
|
||||
// Otherwise, find the first icon, or fallback to the search-market-view and launch it
|
||||
List<AlphabeticalAppsList.AdapterItem> items = mApps.getAdapterItems();
|
||||
for (int i = 0; i < items.size(); i++) {
|
||||
AlphabeticalAppsList.AdapterItem item = items.get(i);
|
||||
switch (item.viewType) {
|
||||
case AllAppsGridAdapter.ICON_VIEW_TYPE:
|
||||
case AllAppsGridAdapter.SEARCH_MARKET_VIEW_TYPE:
|
||||
mAppsRecyclerView.getChildAt(i).performClick();
|
||||
mInputMethodManager.hideSoftInputFromWindow(
|
||||
mContainerView.getWindowToken(), 0);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Focuses the search field.
|
||||
*/
|
||||
private void showSearchField() {
|
||||
// Show the search bar and focus the search
|
||||
final int translationX = Utilities.pxFromDp(SEARCH_TRANSLATION_X_DP,
|
||||
mContext.getResources().getDisplayMetrics());
|
||||
mSearchBarContainerView.setVisibility(View.VISIBLE);
|
||||
mSearchBarContainerView.setAlpha(0f);
|
||||
mSearchBarContainerView.setTranslationX(translationX);
|
||||
mSearchBarContainerView.animate()
|
||||
.alpha(1f)
|
||||
.translationX(0)
|
||||
.setDuration(FADE_IN_DURATION)
|
||||
.withLayer()
|
||||
.withEndAction(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
mSearchBarEditView.requestFocus();
|
||||
mInputMethodManager.showSoftInput(mSearchBarEditView,
|
||||
InputMethodManager.SHOW_IMPLICIT);
|
||||
}
|
||||
});
|
||||
mSearchButtonView.animate()
|
||||
.alpha(0f)
|
||||
.translationX(-translationX)
|
||||
.setDuration(FADE_OUT_DURATION)
|
||||
.withLayer();
|
||||
}
|
||||
|
||||
/**
|
||||
* Unfocuses the search field.
|
||||
*/
|
||||
@Thunk void hideSearchField(boolean animated, final Runnable postAnimationRunnable) {
|
||||
mSearchManager.cancel(true);
|
||||
|
||||
final boolean resetTextField = mSearchBarEditView.getText().toString().length() > 0;
|
||||
final int translationX = Utilities.pxFromDp(SEARCH_TRANSLATION_X_DP,
|
||||
mContext.getResources().getDisplayMetrics());
|
||||
if (animated) {
|
||||
// Hide the search bar and focus the recycler view
|
||||
mSearchBarContainerView.animate()
|
||||
.alpha(0f)
|
||||
.translationX(0)
|
||||
.setDuration(FADE_IN_DURATION)
|
||||
.withLayer()
|
||||
.withEndAction(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
mSearchBarContainerView.setVisibility(View.INVISIBLE);
|
||||
if (resetTextField) {
|
||||
mSearchBarEditView.setText("");
|
||||
}
|
||||
mCb.clearSearchResult();
|
||||
if (postAnimationRunnable != null) {
|
||||
postAnimationRunnable.run();
|
||||
}
|
||||
}
|
||||
});
|
||||
mSearchButtonView.setTranslationX(-translationX);
|
||||
mSearchButtonView.animate()
|
||||
.alpha(1f)
|
||||
.translationX(0)
|
||||
.setDuration(FADE_OUT_DURATION)
|
||||
.withLayer();
|
||||
} else {
|
||||
mSearchBarContainerView.setVisibility(View.INVISIBLE);
|
||||
if (resetTextField) {
|
||||
mSearchBarEditView.setText("");
|
||||
}
|
||||
mCb.clearSearchResult();
|
||||
mSearchButtonView.setAlpha(1f);
|
||||
mSearchButtonView.setTranslationX(0f);
|
||||
if (postAnimationRunnable != null) {
|
||||
postAnimationRunnable.run();
|
||||
}
|
||||
}
|
||||
mInputMethodManager.hideSoftInputFromWindow(mContainerView.getWindowToken(), 0);
|
||||
public DefaultAppSearchAlgorithm onInitializeSearch() {
|
||||
return new DefaultAppSearchAlgorithm(mApps.getApps());
|
||||
}
|
||||
}
|
||||
|
||||
101
src/com/android/launcher3/allapps/HeaderElevationController.java
Normal file
101
src/com/android/launcher3/allapps/HeaderElevationController.java
Normal file
@@ -0,0 +1,101 @@
|
||||
package com.android.launcher3.allapps;
|
||||
|
||||
import android.annotation.TargetApi;
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.drawable.GradientDrawable;
|
||||
import android.os.Build;
|
||||
import android.support.v7.widget.RecyclerView;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.ViewOutlineProvider;
|
||||
import android.widget.FrameLayout;
|
||||
|
||||
import com.android.launcher3.R;
|
||||
|
||||
/**
|
||||
* Helper class for controlling the header elevation in response to RecyclerView scroll.
|
||||
*/
|
||||
public abstract class HeaderElevationController extends RecyclerView.OnScrollListener {
|
||||
|
||||
private int mCurrentY = 0;
|
||||
|
||||
public void reset() {
|
||||
mCurrentY = 0;
|
||||
onScroll(mCurrentY);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void onScrolled(RecyclerView recyclerView, int dx, int dy) {
|
||||
mCurrentY += dy;
|
||||
onScroll(mCurrentY);
|
||||
}
|
||||
|
||||
public void updateBackgroundPadding(Rect bgPadding) { }
|
||||
|
||||
abstract void onScroll(int scrollY);
|
||||
|
||||
public static class ControllerV16 extends HeaderElevationController {
|
||||
|
||||
private final View mShadow;
|
||||
private final float mScrollToElevation;
|
||||
|
||||
public ControllerV16(View header) {
|
||||
Resources res = header.getContext().getResources();
|
||||
mScrollToElevation = res.getDimension(R.dimen.all_apps_header_scroll_to_elevation);
|
||||
|
||||
mShadow = new View(header.getContext());
|
||||
mShadow.setBackground(new GradientDrawable(
|
||||
GradientDrawable.Orientation.TOP_BOTTOM, new int[] {0x1E000000, 0x00000000}));
|
||||
mShadow.setAlpha(0);
|
||||
|
||||
FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(
|
||||
FrameLayout.LayoutParams.MATCH_PARENT,
|
||||
res.getDimensionPixelSize(R.dimen.all_apps_header_shadow_height));
|
||||
lp.topMargin = ((FrameLayout.LayoutParams) header.getLayoutParams()).height;
|
||||
|
||||
((ViewGroup) header.getParent()).addView(mShadow, lp);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onScroll(int scrollY) {
|
||||
float elevationPct = (float) Math.min(scrollY, mScrollToElevation) /
|
||||
mScrollToElevation;
|
||||
mShadow.setAlpha(elevationPct);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateBackgroundPadding(Rect bgPadding) {
|
||||
FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) mShadow.getLayoutParams();
|
||||
lp.leftMargin = bgPadding.left;
|
||||
lp.rightMargin = bgPadding.right;
|
||||
mShadow.requestLayout();
|
||||
}
|
||||
}
|
||||
|
||||
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
|
||||
public static class ControllerVL extends HeaderElevationController {
|
||||
|
||||
private final View mHeader;
|
||||
private final float mMaxElevation;
|
||||
private final float mScrollToElevation;
|
||||
|
||||
public ControllerVL(View header) {
|
||||
mHeader = header;
|
||||
mHeader.setOutlineProvider(ViewOutlineProvider.BOUNDS);
|
||||
|
||||
Resources res = header.getContext().getResources();
|
||||
mMaxElevation = res.getDimension(R.dimen.all_apps_header_max_elevation);
|
||||
mScrollToElevation = res.getDimension(R.dimen.all_apps_header_scroll_to_elevation);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onScroll(int scrollY) {
|
||||
float elevationPct = Math.min(scrollY, mScrollToElevation) / mScrollToElevation;
|
||||
float newElevation = mMaxElevation * elevationPct;
|
||||
if (Float.compare(mHeader.getElevation(), newElevation) != 0) {
|
||||
mHeader.setElevation(newElevation);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -65,7 +65,6 @@ public class WidgetsContainerView extends BaseContainerView
|
||||
private IconCache mIconCache;
|
||||
|
||||
/* Recycler view related member variables */
|
||||
private View mContent;
|
||||
private WidgetsRecyclerView mView;
|
||||
private WidgetsListAdapter mAdapter;
|
||||
|
||||
@@ -99,8 +98,7 @@ public class WidgetsContainerView extends BaseContainerView
|
||||
@Override
|
||||
protected void onFinishInflate() {
|
||||
super.onFinishInflate();
|
||||
mContent = findViewById(R.id.content);
|
||||
mView = (WidgetsRecyclerView) findViewById(R.id.widgets_list_view);
|
||||
mView = (WidgetsRecyclerView) getContentView();
|
||||
mView.setAdapter(mAdapter);
|
||||
|
||||
// This extends the layout space so that preloading happen for the {@link RecyclerView}
|
||||
@@ -120,15 +118,6 @@ public class WidgetsContainerView extends BaseContainerView
|
||||
// Returns views used for launcher transitions.
|
||||
//
|
||||
|
||||
public View getContentView() {
|
||||
return mView;
|
||||
}
|
||||
|
||||
public View getRevealView() {
|
||||
// TODO(hyunyoungs): temporarily use apps view transition.
|
||||
return findViewById(R.id.widgets_reveal_view);
|
||||
}
|
||||
|
||||
public void scrollToTop() {
|
||||
mView.scrollToPosition(0);
|
||||
}
|
||||
@@ -338,21 +327,8 @@ public class WidgetsContainerView extends BaseContainerView
|
||||
//
|
||||
// Container rendering related.
|
||||
//
|
||||
|
||||
@Override
|
||||
protected void onUpdateBackgroundAndPaddings(Rect searchBarBounds, Rect padding) {
|
||||
// Apply the top-bottom padding to the content itself so that the launcher transition is
|
||||
// clipped correctly
|
||||
mContent.setPadding(0, padding.top, 0, padding.bottom);
|
||||
|
||||
// TODO: Use quantum_panel_dark instead of quantum_panel_shape_dark.
|
||||
InsetDrawable background = new InsetDrawable(
|
||||
getResources().getDrawable(R.drawable.quantum_panel_shape_dark), padding.left, 0,
|
||||
padding.right, 0);
|
||||
Rect bgPadding = new Rect();
|
||||
background.getPadding(bgPadding);
|
||||
mView.setBackground(background);
|
||||
getRevealView().setBackground(background.getConstantState().newDrawable());
|
||||
protected void onUpdateBgPadding(Rect padding, Rect bgPadding) {
|
||||
mView.updateBackgroundPadding(bgPadding);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user