Initial changes to add search bar.

- Scaling touch overscroll

Change-Id: Iee0523ca32efaae3491cbf5dbf3ea2e388f9d644
This commit is contained in:
Winson Chung
2014-04-16 17:07:18 -07:00
parent d67d073b9f
commit ecd9b3031c
15 changed files with 240 additions and 37 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 625 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 431 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 866 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@@ -0,0 +1,30 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2014 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.
-->
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/search_bg_transparent">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="@string/recents_search_bar_label"
android:textColor="#99ffffff"
android:textSize="18sp"
android:textAllCaps="true" />
</FrameLayout>

View File

@@ -245,6 +245,12 @@
<!-- The amount of space a user has to scroll to dismiss any info panes. -->
<dimen name="recents_task_stack_scroll_dismiss_info_pane_distance">50dp</dimen>
<!-- The height of the search bar space. -->
<dimen name="recents_search_bar_space_height">40dp</dimen>
<!-- The search bar edge margins. -->
<dimen name="recents_search_bar_space_edge_margins">12dp</dimen>
<!-- Used to calculate the translation animation duration, the expected amount of movement
in dps over one second of time. -->
<dimen name="recents_animation_movement_in_dps_per_second">800dp</dimen>

View File

@@ -511,6 +511,8 @@
<string name="recents_empty_message">RECENTS</string>
<!-- Recents: The info panel app info button string. [CHAR LIMIT=NONE] -->
<string name="recents_app_info_button_label">Application Info</string>
<!-- Recents: Temporary string for the button in the recents search bar. [CHAR LIMIT=NONE] -->
<string name="recents_search_bar_label">search</string>
<!-- Glyph to be overlaid atop the battery when the level is extremely low. Do not translate. -->

View File

@@ -29,6 +29,7 @@ public class Constants {
public static final boolean EnableTaskFiltering = true;
public static final boolean EnableTaskStackClipping = false;
public static final boolean EnableInfoPane = true;
public static final boolean EnableSearchButton = false;
// This disables the bitmap and icon caches
public static final boolean DisableBackgroundCache = false;
@@ -84,6 +85,9 @@ public class Constants {
public static final int TaskStackOverscrollRange = 150;
public static final int FilterStartDelay = 25;
// The amount to inverse scale the movement if we are overscrolling
public static final float TouchOverscrollScaleFactor = 3f;
// The padding will be applied to the smallest dimension, and then applied to all sides
public static final float StackPaddingPct = 0.15f;
// The overlap height relative to the task height

View File

@@ -44,6 +44,8 @@ public class RecentsConfiguration {
public int taskStackMaxDim;
public int taskViewInfoPaneAnimDuration;
public int taskViewRoundedCornerRadiusPx;
public int searchBarSpaceHeightPx;
public int searchBarSpaceEdgeMarginsPx;
public boolean launchedWithThumbnailAnimation;
@@ -92,6 +94,9 @@ public class RecentsConfiguration {
res.getInteger(R.integer.recents_animate_task_view_info_pane_duration);
taskViewRoundedCornerRadiusPx =
res.getDimensionPixelSize(R.dimen.recents_task_view_rounded_corners_radius);
searchBarSpaceHeightPx = res.getDimensionPixelSize(R.dimen.recents_search_bar_space_height);
searchBarSpaceEdgeMarginsPx =
res.getDimensionPixelSize(R.dimen.recents_search_bar_space_edge_margins);
}
/** Updates the system insets */
@@ -99,6 +104,26 @@ public class RecentsConfiguration {
systemInsets.set(insets);
}
/** Returns the search bar bounds in the specified orientation */
public void getSearchBarBounds(int width, int height,
Rect searchBarSpaceBounds, Rect searchBarBounds) {
// Return empty rects if search is not enabled
if (!Constants.DebugFlags.App.EnableSearchButton) {
searchBarSpaceBounds.set(0, 0, 0, 0);
searchBarBounds.set(0, 0, 0, 0);
return;
}
// Calculate the search bar bounds, and account for the system insets
int edgeMarginPx = searchBarSpaceEdgeMarginsPx;
int availableWidth = width - systemInsets.left - systemInsets.right;
searchBarSpaceBounds.set(0, 0, availableWidth, 2 * edgeMarginPx + searchBarSpaceHeightPx);
// Inset from the search bar space to get the search bar bounds
searchBarBounds.set(searchBarSpaceBounds);
searchBarBounds.inset(edgeMarginPx, edgeMarginPx);
}
/** Converts from DPs to PXs */
public int pxFromDp(float size) {
return Math.round(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,

View File

@@ -66,22 +66,33 @@ class SystemUIMessageHandler extends Handler {
Bundle replyData = new Bundle();
TaskViewTransform transform;
// Get the search bar bounds so that we can account for its height in the children
Rect searchBarSpaceBounds = new Rect();
Rect searchBarBounds = new Rect();
RecentsConfiguration config = RecentsConfiguration.getInstance();
config.getSearchBarBounds(windowRect.width(), windowRect.height(),
searchBarSpaceBounds, searchBarBounds);
// Calculate the target task rect for when there is one task
// NOTE: Since the nav bar height is already accounted for in the windowRect, don't
// pass in a bottom inset
stack.addTask(new Task());
tsv.computeRects(windowRect.width(), windowRect.height() - systemInsets.top, 0);
tsv.computeRects(windowRect.width(), windowRect.height() - systemInsets.top -
systemInsets.bottom - searchBarSpaceBounds.height(), 0);
tsv.boundScroll();
transform = tsv.getStackTransform(0, tsv.getStackScroll());
transform.rect.offset(0, searchBarSpaceBounds.height());
replyData.putParcelable(AlternateRecentsComponent.KEY_SINGLE_TASK_STACK_RECT,
new Rect(transform.rect));
// Also calculate the target task rect when there are multiple tasks
stack.addTask(new Task());
tsv.computeRects(windowRect.width(), windowRect.height() - systemInsets.top, 0);
tsv.computeRects(windowRect.width(), windowRect.height() - systemInsets.top -
systemInsets.bottom - searchBarSpaceBounds.height(), 0);
tsv.setStackScrollRaw(Integer.MAX_VALUE);
tsv.boundScroll();
transform = tsv.getStackTransform(1, tsv.getStackScroll());
transform.rect.offset(0, searchBarSpaceBounds.height());
replyData.putParcelable(AlternateRecentsComponent.KEY_MULTIPLE_TASK_STACK_RECT,
new Rect(transform.rect));

View File

@@ -19,6 +19,8 @@ package com.android.systemui.recents;
import android.app.ActivityManager;
import android.app.ActivityOptions;
import android.app.AppGlobals;
import android.app.SearchManager;
import android.content.ActivityNotFoundException;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
@@ -26,11 +28,15 @@ import android.content.pm.ActivityInfo;
import android.content.pm.IPackageManager;
import android.content.pm.PackageManager;
import android.graphics.Bitmap;
import android.graphics.Rect;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.os.RemoteException;
import android.os.UserHandle;
import android.os.UserManager;
import android.text.TextUtils;
import android.util.Log;
import java.util.ArrayList;
import java.util.List;
@@ -45,6 +51,7 @@ public class SystemServicesProxy {
PackageManager mPm;
IPackageManager mIpm;
UserManager mUm;
SearchManager mSm;
String mPackage;
Bitmap mDummyIcon;
@@ -55,6 +62,7 @@ public class SystemServicesProxy {
mPm = context.getPackageManager();
mUm = (UserManager) context.getSystemService(Context.USER_SERVICE);
mIpm = AppGlobals.getPackageManager();
mSm = (SearchManager) context.getSystemService(Context.SEARCH_SERVICE);
mPackage = context.getPackageName();
if (Constants.DebugFlags.App.EnableSystemServicesProxy) {
@@ -199,4 +207,28 @@ public class SystemServicesProxy {
}
return icon;
}
/**
* Composes an intent to launch the global search activity.
*/
public Intent getGlobalSearchIntent(Rect sourceBounds) {
if (mSm == null) return null;
// Try and get the global search activity
ComponentName globalSearchActivity = mSm.getGlobalSearchActivity();
if (globalSearchActivity == null) return null;
// Bundle the source of the search
Bundle appSearchData = new Bundle();
appSearchData.putString("source", mPackage);
// Compose the intent and Start the search activity
Intent intent = new Intent(SearchManager.INTENT_ACTION_GLOBAL_SEARCH);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.setComponent(globalSearchActivity);
intent.putExtra(SearchManager.APP_DATA, appSearchData);
intent.setSourceBounds(sourceBounds);
return intent;
}
}

View File

@@ -27,8 +27,11 @@ import android.graphics.Rect;
import android.net.Uri;
import android.os.UserHandle;
import android.provider.Settings;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.FrameLayout;
import android.widget.TextView;
import com.android.systemui.recents.Console;
import com.android.systemui.recents.Constants;
import com.android.systemui.recents.RecentsConfiguration;
@@ -36,6 +39,7 @@ import com.android.systemui.recents.RecentsTaskLoader;
import com.android.systemui.recents.model.SpaceNode;
import com.android.systemui.recents.model.Task;
import com.android.systemui.recents.model.TaskStack;
import com.android.systemui.R;
import java.util.ArrayList;
@@ -53,11 +57,16 @@ public class RecentsView extends FrameLayout implements TaskStackView.TaskStackV
// The space partitioning root of this container
SpaceNode mBSP;
// Search bar view
View mSearchBar;
// Recents view callbacks
RecentsViewCallbacks mCb;
LayoutInflater mInflater;
public RecentsView(Context context) {
super(context);
mInflater = LayoutInflater.from(context);
setWillNotDraw(false);
}
@@ -71,12 +80,22 @@ public class RecentsView extends FrameLayout implements TaskStackView.TaskStackV
mBSP = n;
// Create and add all the stacks for this partition of space.
boolean hasTasks = false;
removeAllViews();
ArrayList<TaskStack> stacks = mBSP.getStacks();
for (TaskStack stack : stacks) {
TaskStackView stackView = new TaskStackView(getContext(), stack);
stackView.setCallbacks(this);
addView(stackView);
hasTasks |= (stack.getTaskCount() > 0);
}
// Create the search bar (and hide it if we have no recent tasks)
if (Constants.DebugFlags.App.EnableSearchButton) {
createSearchBar();
if (!hasTasks) {
mSearchBar.setVisibility(View.GONE);
}
}
}
@@ -85,29 +104,45 @@ public class RecentsView extends FrameLayout implements TaskStackView.TaskStackV
// Get the first stack view
int childCount = getChildCount();
for (int i = 0; i < childCount; i++) {
TaskStackView stackView = (TaskStackView) getChildAt(i);
TaskStack stack = stackView.mStack;
ArrayList<Task> tasks = stack.getTasks();
View child = getChildAt(i);
if (child instanceof TaskStackView) {
TaskStackView stackView = (TaskStackView) child;
TaskStack stack = stackView.mStack;
ArrayList<Task> tasks = stack.getTasks();
// Get the first task in the stack
if (!tasks.isEmpty()) {
Task task = tasks.get(tasks.size() - 1);
TaskView tv = null;
// Get the first task in the stack
if (!tasks.isEmpty()) {
Task task = tasks.get(tasks.size() - 1);
TaskView tv = null;
// Try and use the first child task view as the source of the launch animation
if (stackView.getChildCount() > 0) {
TaskView stv = (TaskView) stackView.getChildAt(stackView.getChildCount() - 1);
if (stv.getTask() == task) {
tv = stv;
// Try and use the first child task view as the source of the launch animation
if (stackView.getChildCount() > 0) {
TaskView stv = (TaskView) stackView.getChildAt(stackView.getChildCount() - 1);
if (stv.getTask() == task) {
tv = stv;
}
}
onTaskLaunched(stackView, tv, stack, task);
return true;
}
onTaskLaunched(stackView, tv, stack, task);
return true;
}
}
return false;
}
/** Creates and adds the search bar */
void createSearchBar() {
// Create a temporary search bar
mSearchBar = mInflater.inflate(R.layout.recents_search_bar, this, false);
mSearchBar.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
onSearchTriggered();
}
});
addView(mSearchBar);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int width = MeasureSpec.getSize(widthMeasureSpec);
@@ -120,16 +155,26 @@ public class RecentsView extends FrameLayout implements TaskStackView.TaskStackV
Console.logTraceTime(Constants.DebugFlags.App.TimeRecentsStartup,
Constants.DebugFlags.App.TimeRecentsStartupKey, "RecentsView.onMeasure");
// We measure our stack views sans the status bar. It will handle the nav bar itself.
// Get the search bar bounds so that we can account for its height in the children
Rect searchBarSpaceBounds = new Rect();
Rect searchBarBounds = new Rect();
RecentsConfiguration config = RecentsConfiguration.getInstance();
config.getSearchBarBounds(getMeasuredWidth(), getMeasuredHeight(),
searchBarSpaceBounds, searchBarBounds);
if (mSearchBar != null) {
mSearchBar.measure(MeasureSpec.makeMeasureSpec(searchBarSpaceBounds.width(), widthMode),
MeasureSpec.makeMeasureSpec(searchBarSpaceBounds.height(), heightMode));
}
// We measure our stack views sans the status bar. It will handle the nav bar itself.
int childWidth = width - config.systemInsets.right;
int childHeight = height - config.systemInsets.top;
int childHeight = height - config.systemInsets.top - searchBarSpaceBounds.height();
// Measure each child
int childCount = getChildCount();
for (int i = 0; i < childCount; i++) {
final View child = getChildAt(i);
if (child.getVisibility() != GONE) {
View child = getChildAt(i);
if (child instanceof TaskStackView && child.getVisibility() != GONE) {
child.measure(MeasureSpec.makeMeasureSpec(childWidth, widthMode),
MeasureSpec.makeMeasureSpec(childHeight, heightMode));
}
@@ -145,18 +190,30 @@ public class RecentsView extends FrameLayout implements TaskStackView.TaskStackV
Console.logTraceTime(Constants.DebugFlags.App.TimeRecentsStartup,
Constants.DebugFlags.App.TimeRecentsStartupKey, "RecentsView.onLayout");
// We offset our stack views by the status bar height. It will handle the nav bar itself.
// Get the search bar bounds so that we can account for its height in the children
Rect searchBarSpaceBounds = new Rect();
Rect searchBarBounds = new Rect();
RecentsConfiguration config = RecentsConfiguration.getInstance();
top += config.systemInsets.top;
config.getSearchBarBounds(getMeasuredWidth(), getMeasuredHeight(),
searchBarSpaceBounds, searchBarBounds);
if (mSearchBar != null) {
mSearchBar.layout(config.systemInsets.left + searchBarSpaceBounds.left,
config.systemInsets.top + searchBarSpaceBounds.top,
config.systemInsets.left + mSearchBar.getMeasuredWidth(),
config.systemInsets.top + mSearchBar.getMeasuredHeight());
}
// We offset our stack views by the status bar height. It will handle the nav bar itself.
top += config.systemInsets.top + searchBarSpaceBounds.height();
// Layout each child
// XXX: Based on the space node for that task view
int childCount = getChildCount();
for (int i = 0; i < childCount; i++) {
final View child = getChildAt(i);
if (child.getVisibility() != GONE) {
final int width = child.getMeasuredWidth();
final int height = child.getMeasuredHeight();
View child = getChildAt(i);
if (child instanceof TaskStackView && child.getVisibility() != GONE) {
int width = child.getMeasuredWidth();
int height = child.getMeasuredHeight();
child.layout(left, top, left + width, top + height);
}
}
@@ -188,9 +245,12 @@ public class RecentsView extends FrameLayout implements TaskStackView.TaskStackV
// Get the first stack view
int childCount = getChildCount();
for (int i = 0; i < childCount; i++) {
TaskStackView stackView = (TaskStackView) getChildAt(i);
if (stackView.closeOpenInfoPanes()) {
return true;
View child = getChildAt(i);
if (child instanceof TaskStackView) {
TaskStackView stackView = (TaskStackView) child;
if (stackView.closeOpenInfoPanes()) {
return true;
}
}
}
}
@@ -315,4 +375,24 @@ public class RecentsView extends FrameLayout implements TaskStackView.TaskStackV
TaskStackBuilder.create(getContext())
.addNextIntentWithParentStack(intent).startActivities();
}
public void onSearchTriggered() {
// Get the search bar source bounds
Rect searchBarSpaceBounds = new Rect();
Rect searchBarBounds = new Rect();
RecentsConfiguration config = RecentsConfiguration.getInstance();
config.getSearchBarBounds(getMeasuredWidth(), getMeasuredHeight(),
searchBarSpaceBounds, searchBarBounds);
// Get the search intent and start it
Intent searchIntent = RecentsTaskLoader.getInstance().getSystemServicesProxy()
.getGlobalSearchIntent(searchBarBounds);
if (searchIntent != null) {
try {
getContext().startActivity(searchIntent);
} catch (ActivityNotFoundException anfe) {
Console.logError(getContext(), "Could not start Search activity");
}
}
}
}

View File

@@ -70,10 +70,8 @@ class TaskInfoView extends FrameLayout {
/** Updates the positions of each of the items to fit in the rect specified */
void updateContents(Rect visibleRect) {
// Offset the app info button
LayoutParams lp = (LayoutParams) mAppInfoButton.getLayoutParams();
lp.topMargin = visibleRect.top +
(visibleRect.height() - mAppInfoButton.getMeasuredHeight()) / 2;
requestLayout();
mAppInfoButton.setTranslationY(visibleRect.top +
(visibleRect.height() - mAppInfoButton.getMeasuredHeight()) / 2);
}
/** Sets the circular clip radius on this panel */

View File

@@ -395,9 +395,12 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
return false;
}
/** Returns whether the current scroll is out of bounds */
/** Returns whether the specified scroll is out of bounds */
boolean isScrollOutOfBounds(int scroll) {
return (scroll < mMinScroll) || (scroll > mMaxScroll);
}
boolean isScrollOutOfBounds() {
return (getStackScroll() < 0) || (getStackScroll() > mMaxScroll);
return isScrollOutOfBounds(getStackScroll());
}
/** Updates the min and max virtual scroll bounds */
@@ -556,7 +559,14 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
int smallestDimension = Math.min(width, height);
int padding = (int) (Constants.Values.TaskStackView.StackPaddingPct * smallestDimension / 2f);
mStackRect.inset(padding, padding);
if (Constants.DebugFlags.App.EnableSearchButton) {
// Don't need to pad the top since we have some padding on the search bar already
mStackRect.left += padding;
mStackRect.right -= padding;
mStackRect.bottom -= padding;
} else {
mStackRect.inset(padding, padding);
}
mStackRectSansPeek.set(mStackRect);
mStackRectSansPeek.top += Constants.Values.TaskStackView.StackPeekHeightPct * mStackRect.height();
@@ -1275,7 +1285,12 @@ class TaskStackViewTouchHandler implements SwipeHelper.Callback {
}
}
if (mIsScrolling) {
mSv.setStackScroll(mSv.getStackScroll() + deltaY);
int curStackScroll = mSv.getStackScroll();
if (mSv.isScrollOutOfBounds(curStackScroll + deltaY)) {
// Scale the touch if we are overscrolling
deltaY /= Constants.Values.TaskStackView.TouchOverscrollScaleFactor;
}
mSv.setStackScroll(curStackScroll + deltaY);
if (mSv.isScrollOutOfBounds()) {
mVelocityTracker.clear();
}