Merge "Adding graphic for all apps empty search screen." into ub-launcher3-burnaby
@@ -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();
|
||||
|
||||
BIN
res/drawable-hdpi/ic_all_apps_bg_hand.png
Normal file
|
After Width: | Height: | Size: 27 KiB |
BIN
res/drawable-hdpi/ic_all_apps_bg_icon_1.png
Normal file
|
After Width: | Height: | Size: 3.6 KiB |
BIN
res/drawable-hdpi/ic_all_apps_bg_icon_2.png
Normal file
|
After Width: | Height: | Size: 3.9 KiB |
BIN
res/drawable-hdpi/ic_all_apps_bg_icon_3.png
Normal file
|
After Width: | Height: | Size: 5.5 KiB |
BIN
res/drawable-hdpi/ic_all_apps_bg_icon_4.png
Normal file
|
After Width: | Height: | Size: 4.0 KiB |
BIN
res/drawable-mdpi/ic_all_apps_bg_hand.png
Normal file
|
After Width: | Height: | Size: 16 KiB |
BIN
res/drawable-mdpi/ic_all_apps_bg_icon_1.png
Normal file
|
After Width: | Height: | Size: 2.3 KiB |
BIN
res/drawable-mdpi/ic_all_apps_bg_icon_2.png
Normal file
|
After Width: | Height: | Size: 2.5 KiB |
BIN
res/drawable-mdpi/ic_all_apps_bg_icon_3.png
Normal file
|
After Width: | Height: | Size: 3.4 KiB |
BIN
res/drawable-mdpi/ic_all_apps_bg_icon_4.png
Normal file
|
After Width: | Height: | Size: 2.6 KiB |
BIN
res/drawable-xhdpi/ic_all_apps_bg_hand.png
Normal file
|
After Width: | Height: | Size: 39 KiB |
BIN
res/drawable-xhdpi/ic_all_apps_bg_icon_1.png
Normal file
|
After Width: | Height: | Size: 5.0 KiB |
BIN
res/drawable-xhdpi/ic_all_apps_bg_icon_2.png
Normal file
|
After Width: | Height: | Size: 5.4 KiB |
BIN
res/drawable-xhdpi/ic_all_apps_bg_icon_3.png
Normal file
|
After Width: | Height: | Size: 8.0 KiB |
BIN
res/drawable-xhdpi/ic_all_apps_bg_icon_4.png
Normal file
|
After Width: | Height: | Size: 5.5 KiB |
BIN
res/drawable-xxhdpi/ic_all_apps_bg_hand.png
Normal file
|
After Width: | Height: | Size: 69 KiB |
BIN
res/drawable-xxhdpi/ic_all_apps_bg_icon_1.png
Normal file
|
After Width: | Height: | Size: 8.2 KiB |
BIN
res/drawable-xxhdpi/ic_all_apps_bg_icon_2.png
Normal file
|
After Width: | Height: | Size: 9.0 KiB |
BIN
res/drawable-xxhdpi/ic_all_apps_bg_icon_3.png
Normal file
|
After Width: | Height: | Size: 14 KiB |
BIN
res/drawable-xxhdpi/ic_all_apps_bg_icon_4.png
Normal file
|
After Width: | Height: | Size: 9.0 KiB |
BIN
res/drawable-xxxhdpi/ic_all_apps_bg_hand.png
Normal file
|
After Width: | Height: | Size: 80 KiB |
BIN
res/drawable-xxxhdpi/ic_all_apps_bg_icon_1.png
Normal file
|
After Width: | Height: | Size: 29 KiB |
BIN
res/drawable-xxxhdpi/ic_all_apps_bg_icon_2.png
Normal file
|
After Width: | Height: | Size: 11 KiB |
BIN
res/drawable-xxxhdpi/ic_all_apps_bg_icon_3.png
Normal file
|
After Width: | Height: | Size: 14 KiB |
BIN
res/drawable-xxxhdpi/ic_all_apps_bg_icon_4.png
Normal file
|
After Width: | Height: | Size: 10 KiB |
@@ -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"
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
194
src/com/android/launcher3/allapps/AllAppsBackgroundDrawable.java
Normal 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;
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
|
||||