Merge "Adding graphic for all apps empty search screen." into ub-launcher3-burnaby

This commit is contained in:
Winson Chung
2015-08-28 21:08:49 +00:00
committed by Android (Google) Code Review
34 changed files with 288 additions and 5 deletions

View File

@@ -2,6 +2,11 @@
*;
}
-keep class com.android.launcher3.allapps.AllAppsBackgroundDrawable {
public void setAlpha(int);
public int getAlpha();
}
-keep class com.android.launcher3.BaseRecyclerViewFastScrollBar {
public void setThumbWidth(int);
public int getThumbWidth();

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 69 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 80 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

View File

@@ -19,7 +19,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="start"
android:paddingTop="20dp"
android:paddingTop="@dimen/all_apps_empty_search_message_top_offset"
android:paddingBottom="8dp"
android:paddingLeft="16dp"
android:paddingRight="16dp"

View File

@@ -19,6 +19,8 @@
<dimen name="all_apps_grid_view_start_margin">0dp</dimen>
<dimen name="all_apps_grid_section_text_size">26sp</dimen>
<dimen name="all_apps_icon_top_bottom_padding">12dp</dimen>
<dimen name="all_apps_background_canvas_width">850dp</dimen>
<dimen name="all_apps_background_canvas_height">525dp</dimen>
<!-- Cling -->
<dimen name="cling_migration_logo_height">400dp</dimen>

View File

@@ -18,6 +18,8 @@
<!-- All Apps -->
<dimen name="all_apps_search_bar_height">54dp</dimen>
<dimen name="all_apps_icon_top_bottom_padding">14dp</dimen>
<dimen name="all_apps_empty_search_message_top_offset">64dp</dimen>
<dimen name="all_apps_empty_search_bg_top_offset">180dp</dimen>
<!-- QSB -->
<dimen name="toolbar_button_vertical_padding">8dip</dimen>

View File

@@ -74,6 +74,10 @@
<dimen name="all_apps_prediction_icon_top_padding">8dp</dimen>
<dimen name="all_apps_prediction_icon_bottom_padding">18dp</dimen>
<dimen name="all_apps_list_top_bottom_padding">8dp</dimen>
<dimen name="all_apps_empty_search_message_top_offset">40dp</dimen>
<dimen name="all_apps_empty_search_bg_top_offset">144dp</dimen>
<dimen name="all_apps_background_canvas_width">700dp</dimen>
<dimen name="all_apps_background_canvas_height">475dp</dimen>
<!-- Widget tray -->
<dimen name="widget_container_inset">8dp</dimen>

View File

@@ -0,0 +1,194 @@
/*
* Copyright (C) 2015 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.launcher3.allapps;
import android.animation.ObjectAnimator;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Canvas;
import android.graphics.ColorFilter;
import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.view.Gravity;
import com.android.launcher3.R;
/**
* A helper class to positon and orient a drawable to be drawn.
*/
class TransformedImageDrawable {
private Drawable mImage;
private float mXPercent;
private float mYPercent;
private int mGravity;
/**
* @param gravity If one of the Gravity center values, the x and y offset will take the width
* and height of the image into account to center the image to the offset.
*/
public TransformedImageDrawable(Resources res, int resourceId, float xPct, float yPct,
int gravity) {
mImage = res.getDrawable(resourceId);
mXPercent = xPct;
mYPercent = yPct;
mGravity = gravity;
}
public void setAlpha(int alpha) {
mImage.setAlpha(alpha);
}
public int getAlpha() {
return mImage.getAlpha();
}
public void updateBounds(Rect bounds) {
int width = mImage.getIntrinsicWidth();
int height = mImage.getIntrinsicHeight();
int left = bounds.left + (int) (mXPercent * bounds.width());
int top = bounds.top + (int) (mYPercent * bounds.height());
if ((mGravity & Gravity.CENTER_HORIZONTAL) == Gravity.CENTER_HORIZONTAL) {
left -= (width / 2);
}
if ((mGravity & Gravity.CENTER_VERTICAL) == Gravity.CENTER_VERTICAL) {
top -= (height / 2);
}
mImage.setBounds(left, top, left + width, top + height);
}
public void draw(Canvas canvas) {
int c = canvas.save(Canvas.MATRIX_SAVE_FLAG);
mImage.draw(canvas);
canvas.restoreToCount(c);
}
}
/**
* This is a custom composite drawable that has a fixed virtual size and dynamically lays out its
* children images relatively within its bounds. This way, we can reduce the memory usage of a
* single, large sparsely populated image.
*/
public class AllAppsBackgroundDrawable extends Drawable {
private final TransformedImageDrawable mHand;
private final TransformedImageDrawable[] mIcons;
private final int mWidth;
private final int mHeight;
private ObjectAnimator mBackgroundAnim;
public AllAppsBackgroundDrawable(Context context) {
Resources res = context.getResources();
mHand = new TransformedImageDrawable(res, R.drawable.ic_all_apps_bg_hand,
0.575f, 0.1f, Gravity.CENTER_HORIZONTAL);
mIcons = new TransformedImageDrawable[4];
mIcons[0] = new TransformedImageDrawable(res, R.drawable.ic_all_apps_bg_icon_1,
0.375f, 0, Gravity.CENTER_HORIZONTAL);
mIcons[1] = new TransformedImageDrawable(res, R.drawable.ic_all_apps_bg_icon_2,
0.3125f, 0.25f, Gravity.CENTER_HORIZONTAL);
mIcons[2] = new TransformedImageDrawable(res, R.drawable.ic_all_apps_bg_icon_3,
0.475f, 0.4f, Gravity.CENTER_HORIZONTAL);
mIcons[3] = new TransformedImageDrawable(res, R.drawable.ic_all_apps_bg_icon_4,
0.7f, 0.125f, Gravity.CENTER_HORIZONTAL);
mWidth = res.getDimensionPixelSize(R.dimen.all_apps_background_canvas_width);
mHeight = res.getDimensionPixelSize(R.dimen.all_apps_background_canvas_height);
}
/**
* Animates the background alpha.
*/
public void animateBgAlpha(float finalAlpha, int duration) {
int finalAlphaI = (int) (finalAlpha * 255f);
if (getAlpha() != finalAlphaI) {
mBackgroundAnim = cancelAnimator(mBackgroundAnim);
mBackgroundAnim = ObjectAnimator.ofInt(this, "alpha", finalAlphaI);
mBackgroundAnim.setDuration(duration);
mBackgroundAnim.start();
}
}
/**
* Sets the background alpha immediately.
*/
public void setBgAlpha(float finalAlpha) {
int finalAlphaI = (int) (finalAlpha * 255f);
if (getAlpha() != finalAlphaI) {
mBackgroundAnim = cancelAnimator(mBackgroundAnim);
setAlpha(finalAlphaI);
}
}
@Override
public int getIntrinsicWidth() {
return mWidth;
}
@Override
public int getIntrinsicHeight() {
return mHeight;
}
@Override
public void draw(Canvas canvas) {
mHand.draw(canvas);
for (int i = 0; i < mIcons.length; i++) {
mIcons[i].draw(canvas);
}
}
@Override
protected void onBoundsChange(Rect bounds) {
super.onBoundsChange(bounds);
mHand.updateBounds(bounds);
for (int i = 0; i < mIcons.length; i++) {
mIcons[i].updateBounds(bounds);
}
invalidateSelf();
}
@Override
public void setAlpha(int alpha) {
mHand.setAlpha(alpha);
for (int i = 0; i < mIcons.length; i++) {
mIcons[i].setAlpha(alpha);
}
invalidateSelf();
}
@Override
public int getAlpha() {
return mHand.getAlpha();
}
@Override
public void setColorFilter(ColorFilter colorFilter) {
// Do nothing
}
@Override
public int getOpacity() {
return PixelFormat.TRANSLUCENT;
}
private ObjectAnimator cancelAnimator(ObjectAnimator animator) {
if (animator != null) {
animator.removeAllListeners();
animator.cancel();
}
return null;
}
}

View File

@@ -615,13 +615,14 @@ public class AllAppsContainerView extends BaseContainerView implements DragSourc
if (apps != null) {
mApps.setOrderedFilter(apps);
mAdapter.setLastSearchQuery(query);
mAppsRecyclerView.scrollToTop();
mAppsRecyclerView.onSearchResultsChanged();
}
}
@Override
public void clearSearchResult() {
mApps.setOrderedFilter(null);
mAppsRecyclerView.onSearchResultsChanged();
// Clear the search query
mSearchQueryBuilder.clear();

View File

@@ -24,11 +24,13 @@ import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.PointF;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.support.v4.view.accessibility.AccessibilityRecordCompat;
import android.support.v4.view.accessibility.AccessibilityEventCompat;
import android.net.Uri;
import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewConfiguration;
@@ -511,14 +513,17 @@ public class AllAppsGridAdapter extends RecyclerView.Adapter<AllAppsGridAdapter.
case EMPTY_SEARCH_VIEW_TYPE:
TextView emptyViewText = (TextView) holder.mContent;
emptyViewText.setText(mEmptySearchMessage);
emptyViewText.setGravity(mApps.hasNoFilteredResults() ? Gravity.CENTER :
Gravity.START | Gravity.CENTER_VERTICAL);
break;
case SEARCH_MARKET_VIEW_TYPE:
View searchView = holder.mContent;
TextView searchView = (TextView) holder.mContent;
if (mMarketSearchIntent != null) {
searchView.setVisibility(View.VISIBLE);
searchView.setContentDescription(mMarketSearchMessage);
((TextView) searchView.findViewById(R.id.search_market_text))
.setText(mMarketSearchMessage);
searchView.setGravity(mApps.hasNoFilteredResults() ? Gravity.CENTER :
Gravity.START | Gravity.CENTER_VERTICAL);
searchView.setText(mMarketSearchMessage);
} else {
searchView.setVisibility(View.GONE);
}

View File

@@ -15,8 +15,11 @@
*/
package com.android.launcher3.allapps;
import android.animation.ObjectAnimator;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Canvas;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
@@ -26,6 +29,7 @@ import android.view.View;
import com.android.launcher3.BaseRecyclerView;
import com.android.launcher3.BaseRecyclerViewFastScrollBar;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.R;
import com.android.launcher3.Stats;
import com.android.launcher3.Utilities;
import com.android.launcher3.util.Thunk;
@@ -57,6 +61,9 @@ public class AllAppsRecyclerView extends BaseRecyclerView
private ScrollPositionState mScrollPosState = new ScrollPositionState();
private AllAppsBackgroundDrawable mEmptySearchBackground;
private int mEmptySearchBackgroundTopOffset;
public AllAppsRecyclerView(Context context) {
this(context, null);
}
@@ -72,7 +79,11 @@ public class AllAppsRecyclerView extends BaseRecyclerView
public AllAppsRecyclerView(Context context, AttributeSet attrs, int defStyleAttr,
int defStyleRes) {
super(context, attrs, defStyleAttr);
Resources res = getResources();
mScrollbar.setDetachThumbOnFastScroll();
mEmptySearchBackgroundTopOffset = res.getDimensionPixelSize(
R.dimen.all_apps_empty_search_bg_top_offset);
}
/**
@@ -121,6 +132,30 @@ public class AllAppsRecyclerView extends BaseRecyclerView
super.dispatchDraw(canvas);
}
@Override
public void onDraw(Canvas c) {
// Draw the background
if (mEmptySearchBackground != null && mEmptySearchBackground.getAlpha() > 0) {
c.clipRect(mBackgroundPadding.left, mBackgroundPadding.top,
getWidth() - mBackgroundPadding.right,
getHeight() - mBackgroundPadding.bottom);
mEmptySearchBackground.draw(c);
}
super.onDraw(c);
}
@Override
protected boolean verifyDrawable(Drawable who) {
return who == mEmptySearchBackground || super.verifyDrawable(who);
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
updateEmptySearchBackgroundBounds();
}
@Override
protected void onFinishInflate() {
super.onFinishInflate();
@@ -141,6 +176,25 @@ public class AllAppsRecyclerView extends BaseRecyclerView
}
}
public void onSearchResultsChanged() {
// Always scroll the view to the top so the user can see the changed results
scrollToTop();
if (mApps.hasNoFilteredResults()) {
if (mEmptySearchBackground == null) {
mEmptySearchBackground = new AllAppsBackgroundDrawable(getContext());
mEmptySearchBackground.setAlpha(0);
mEmptySearchBackground.setCallback(this);
updateEmptySearchBackgroundBounds();
}
mEmptySearchBackground.animateBgAlpha(1f, 150);
} else if (mEmptySearchBackground != null) {
// For the time being, we just immediately hide the background to ensure that it does
// not overlap with the results
mEmptySearchBackground.setBgAlpha(0f);
}
}
/**
* Maps the touch (from 0..1) to the adapter position that should be visible.
*/
@@ -390,4 +444,20 @@ public class AllAppsRecyclerView extends BaseRecyclerView
return 0;
}
}
/**
* Updates the bounds of the empty search background.
*/
private void updateEmptySearchBackgroundBounds() {
if (mEmptySearchBackground == null) {
return;
}
// Center the empty search background on this new view bounds
int x = (getMeasuredWidth() - mEmptySearchBackground.getIntrinsicWidth()) / 2;
int y = mEmptySearchBackgroundTopOffset;
mEmptySearchBackground.setBounds(x, y,
x + mEmptySearchBackground.getIntrinsicWidth(),
y + mEmptySearchBackground.getIntrinsicHeight());
}
}