blob: 475fb6d20214c77eb5254b266daaad6621e13424 [file] [log] [blame]
Jim Millere898ac52012-04-06 17:10:57 -07001/*
2 * Copyright (C) 2012 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.systemui;
18
Jim Millere898ac52012-04-06 17:10:57 -070019import android.animation.LayoutTransition;
Jim Miller998bb762012-05-21 13:37:27 -070020import android.app.ActivityOptions;
Jim Miller3b291872012-04-24 18:54:20 -070021import android.app.SearchManager;
Jim Millere898ac52012-04-06 17:10:57 -070022import android.content.ActivityNotFoundException;
Jim Miller3b291872012-04-24 18:54:20 -070023import android.content.ComponentName;
Jim Millere898ac52012-04-06 17:10:57 -070024import android.content.Context;
25import android.content.Intent;
Philip Milnea01a2a892012-05-29 14:46:54 -070026import android.content.res.Resources;
27import android.os.Vibrator;
28import android.provider.Settings;
Jim Millere898ac52012-04-06 17:10:57 -070029import android.util.AttributeSet;
Jim Miller3b291872012-04-24 18:54:20 -070030import android.util.Slog;
Jim Millere898ac52012-04-06 17:10:57 -070031import android.view.MotionEvent;
32import android.view.View;
33import android.view.ViewGroup;
Jim Miller20830422012-05-15 20:46:03 -070034import android.view.ViewTreeObserver;
35import android.view.ViewTreeObserver.OnPreDrawListener;
Jim Millere898ac52012-04-06 17:10:57 -070036import android.widget.FrameLayout;
Jeff Brownde7a8ea2012-06-13 18:28:57 -070037
Jim Miller955a0162012-06-11 21:06:13 -070038import com.android.internal.widget.multiwaveview.GlowPadView;
39import com.android.internal.widget.multiwaveview.GlowPadView.OnTriggerListener;
Jim Millere898ac52012-04-06 17:10:57 -070040import com.android.systemui.R;
41import com.android.systemui.recent.StatusBarTouchProxy;
42import com.android.systemui.statusbar.BaseStatusBar;
Jim Miller9a720f52012-05-30 03:19:43 -070043import com.android.systemui.statusbar.CommandQueue;
Jim Millere898ac52012-04-06 17:10:57 -070044import com.android.systemui.statusbar.phone.PhoneStatusBar;
45import com.android.systemui.statusbar.tablet.StatusBarPanel;
46import com.android.systemui.statusbar.tablet.TabletStatusBar;
47
48public class SearchPanelView extends FrameLayout implements
Dianne Hackborn84375872012-06-01 19:03:50 -070049 StatusBarPanel, ActivityOptions.OnAnimationStartedListener {
50 private static final int SEARCH_PANEL_HOLD_DURATION = 0;
Jim Millere898ac52012-04-06 17:10:57 -070051 static final String TAG = "SearchPanelView";
52 static final boolean DEBUG = TabletStatusBar.DEBUG || PhoneStatusBar.DEBUG || false;
Jim Miller3294b6b2012-05-31 17:49:13 -070053 private static final String ASSIST_ICON_METADATA_NAME =
54 "com.android.systemui.action_assist_icon";
Jim Miller9a720f52012-05-30 03:19:43 -070055 private final Context mContext;
Jim Millere898ac52012-04-06 17:10:57 -070056 private BaseStatusBar mBar;
57 private StatusBarTouchProxy mStatusBarTouchProxy;
58
59 private boolean mShowing;
60 private View mSearchTargetsContainer;
Jim Miller955a0162012-06-11 21:06:13 -070061 private GlowPadView mGlowPadView;
Jim Millere898ac52012-04-06 17:10:57 -070062
63 public SearchPanelView(Context context, AttributeSet attrs) {
64 this(context, attrs, 0);
65 }
66
67 public SearchPanelView(Context context, AttributeSet attrs, int defStyle) {
68 super(context, attrs, defStyle);
69 mContext = context;
70 }
71
Jim Miller07994402012-05-02 14:22:27 -070072 private void startAssistActivity() {
Fabrice Di Meglio4d0d38b2012-05-25 11:36:03 -070073 // Close Recent Apps if needed
Jim Miller9a720f52012-05-30 03:19:43 -070074 mBar.animateCollapse(CommandQueue.FLAG_EXCLUDE_SEARCH_PANEL);
Fabrice Di Meglio4d0d38b2012-05-25 11:36:03 -070075 // Launch Assist
Jim Miller45308b12012-06-18 19:23:39 -070076 Intent intent = SearchManager.getAssistIntent(mContext);
Jim Miller8ea8a292012-05-30 09:50:00 -070077 if (intent == null) return;
Jim Miller998bb762012-05-21 13:37:27 -070078 try {
Jim Millerc150b192012-05-17 15:47:25 -070079 ActivityOptions opts = ActivityOptions.makeCustomAnimation(mContext,
Dianne Hackborn84375872012-06-01 19:03:50 -070080 R.anim.search_launch_enter, R.anim.search_launch_exit,
81 getHandler(), this);
Jim Millerc150b192012-05-17 15:47:25 -070082 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
83 mContext.startActivity(intent, opts.toBundle());
Jim Miller998bb762012-05-21 13:37:27 -070084 } catch (ActivityNotFoundException e) {
85 Slog.w(TAG, "Activity not found for " + intent.getAction());
Dianne Hackborn84375872012-06-01 19:03:50 -070086 onAnimationStarted();
Jim Miller07994402012-05-02 14:22:27 -070087 }
88 }
89
Jim Miller955a0162012-06-11 21:06:13 -070090 class GlowPadTriggerListener implements GlowPadView.OnTriggerListener {
Dianne Hackborn84375872012-06-01 19:03:50 -070091 boolean mWaitingForLaunch;
Jim Miller998bb762012-05-21 13:37:27 -070092
Jim Millere898ac52012-04-06 17:10:57 -070093 public void onGrabbed(View v, int handle) {
94 }
95
96 public void onReleased(View v, int handle) {
97 }
98
99 public void onGrabbedStateChange(View v, int handle) {
Jim Millera073e572012-05-23 17:03:27 -0700100 if (!mWaitingForLaunch && OnTriggerListener.NO_HANDLE == handle) {
Jim Millere898ac52012-04-06 17:10:57 -0700101 mBar.hideSearchPanel();
102 }
103 }
104
Jim Millera073e572012-05-23 17:03:27 -0700105 public void onTrigger(View v, final int target) {
Jim Miller955a0162012-06-11 21:06:13 -0700106 final int resId = mGlowPadView.getResourceIdForTarget(target);
Jim Millera073e572012-05-23 17:03:27 -0700107 switch (resId) {
Jim Miller20039ad2012-06-15 17:26:28 -0700108 case com.android.internal.R.drawable.ic_action_assist_generic:
Jim Millera073e572012-05-23 17:03:27 -0700109 mWaitingForLaunch = true;
110 startAssistActivity();
Philip Milnea01a2a892012-05-29 14:46:54 -0700111 vibrate();
Philip Milnea01a2a892012-05-29 14:46:54 -0700112 break;
Jim Millera073e572012-05-23 17:03:27 -0700113 }
Jim Miller998bb762012-05-21 13:37:27 -0700114 }
115
116 public void onFinishFinalAnimation() {
Jim Miller3b291872012-04-24 18:54:20 -0700117 }
Dianne Hackborn84375872012-06-01 19:03:50 -0700118 }
Jim Miller955a0162012-06-11 21:06:13 -0700119 final GlowPadTriggerListener mGlowPadViewListener = new GlowPadTriggerListener();
Dianne Hackborn84375872012-06-01 19:03:50 -0700120
121 @Override
122 public void onAnimationStarted() {
123 postDelayed(new Runnable() {
124 public void run() {
Jim Miller955a0162012-06-11 21:06:13 -0700125 mGlowPadViewListener.mWaitingForLaunch = false;
Dianne Hackborn84375872012-06-01 19:03:50 -0700126 mBar.hideSearchPanel();
127 }
128 }, SEARCH_PANEL_HOLD_DURATION);
129 }
Jim Millere898ac52012-04-06 17:10:57 -0700130
131 @Override
132 protected void onFinishInflate() {
133 super.onFinishInflate();
134 mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
Jim Miller9a720f52012-05-30 03:19:43 -0700135 mSearchTargetsContainer = findViewById(R.id.search_panel_container);
Jim Millere898ac52012-04-06 17:10:57 -0700136 mStatusBarTouchProxy = (StatusBarTouchProxy) findViewById(R.id.status_bar_touch_proxy);
137 // TODO: fetch views
Jim Miller955a0162012-06-11 21:06:13 -0700138 mGlowPadView = (GlowPadView) findViewById(R.id.glow_pad_view);
139 mGlowPadView.setOnTriggerListener(mGlowPadViewListener);
Jim Miller45308b12012-06-18 19:23:39 -0700140 }
141
142 private void maybeSwapSearchIcon() {
143 Intent intent = SearchManager.getAssistIntent(mContext);
144 if (intent != null) {
145 ComponentName component = intent.getComponent();
146 if (component == null || !mGlowPadView.replaceTargetDrawablesIfPresent(component,
147 ASSIST_ICON_METADATA_NAME,
148 com.android.internal.R.drawable.ic_action_assist_generic)) {
149 if (DEBUG) Slog.v(TAG, "Couldn't grab icon for component " + component);
Jim Miller3294b6b2012-05-31 17:49:13 -0700150 }
Jim Miller3294b6b2012-05-31 17:49:13 -0700151 }
Jim Millere898ac52012-04-06 17:10:57 -0700152 }
153
154 private boolean pointInside(int x, int y, View v) {
155 final int l = v.getLeft();
156 final int r = v.getRight();
157 final int t = v.getTop();
158 final int b = v.getBottom();
159 return x >= l && x < r && y >= t && y < b;
160 }
161
162 public boolean isInContentArea(int x, int y) {
163 if (pointInside(x, y, mSearchTargetsContainer)) {
164 return true;
165 } else if (mStatusBarTouchProxy != null &&
166 pointInside(x, y, mStatusBarTouchProxy)) {
167 return true;
168 } else {
169 return false;
170 }
171 }
172
Jim Miller9a720f52012-05-30 03:19:43 -0700173 private final OnPreDrawListener mPreDrawListener = new ViewTreeObserver.OnPreDrawListener() {
Jim Miller20830422012-05-15 20:46:03 -0700174 public boolean onPreDraw() {
175 getViewTreeObserver().removeOnPreDrawListener(this);
Jim Miller955a0162012-06-11 21:06:13 -0700176 mGlowPadView.resumeAnimations();
Jim Miller20830422012-05-15 20:46:03 -0700177 return false;
178 }
179 };
180
Philip Milnea01a2a892012-05-29 14:46:54 -0700181 private void vibrate() {
182 Context context = getContext();
183 if (Settings.System.getInt(context.getContentResolver(),
184 Settings.System.HAPTIC_FEEDBACK_ENABLED, 1) != 0) {
185 Resources res = context.getResources();
186 Vibrator vibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE);
187 vibrator.vibrate(res.getInteger(R.integer.config_search_panel_view_vibration_duration));
188 }
189 }
190
Jim Millerd99e7fd2012-05-08 16:30:42 -0700191 public void show(final boolean show, boolean animate) {
Jim Millera073e572012-05-23 17:03:27 -0700192 if (!show) {
193 final LayoutTransition transitioner = animate ? createLayoutTransitioner() : null;
Philip Milnea01a2a892012-05-29 14:46:54 -0700194 ((ViewGroup) mSearchTargetsContainer).setLayoutTransition(transitioner);
Jim Millere898ac52012-04-06 17:10:57 -0700195 }
Jim Millera073e572012-05-23 17:03:27 -0700196 mShowing = show;
Jim Miller20830422012-05-15 20:46:03 -0700197 if (show) {
Jim Miller45308b12012-06-18 19:23:39 -0700198 maybeSwapSearchIcon();
Jim Miller20830422012-05-15 20:46:03 -0700199 if (getVisibility() != View.VISIBLE) {
200 setVisibility(View.VISIBLE);
201 // Don't start the animation until we've created the layer, which is done
202 // right before we are drawn
Jim Miller955a0162012-06-11 21:06:13 -0700203 mGlowPadView.suspendAnimations();
204 mGlowPadView.ping();
Jim Miller20830422012-05-15 20:46:03 -0700205 getViewTreeObserver().addOnPreDrawListener(mPreDrawListener);
Philip Milnea01a2a892012-05-29 14:46:54 -0700206 vibrate();
Jim Millerd99e7fd2012-05-08 16:30:42 -0700207 }
Jim Miller20830422012-05-15 20:46:03 -0700208 setFocusable(true);
209 setFocusableInTouchMode(true);
210 requestFocus();
211 } else {
212 setVisibility(View.INVISIBLE);
213 }
Jim Millere898ac52012-04-06 17:10:57 -0700214 }
215
216 public void hide(boolean animate) {
Jim Millere898ac52012-04-06 17:10:57 -0700217 if (mBar != null) {
218 // This will indirectly cause show(false, ...) to get called
Jim Miller9a720f52012-05-30 03:19:43 -0700219 mBar.animateCollapse(CommandQueue.FLAG_EXCLUDE_NONE);
Jim Millerd99e7fd2012-05-08 16:30:42 -0700220 } else {
221 setVisibility(View.INVISIBLE);
Jim Millere898ac52012-04-06 17:10:57 -0700222 }
223 }
224
Jim Millere898ac52012-04-06 17:10:57 -0700225 /**
226 * We need to be aligned at the bottom. LinearLayout can't do this, so instead,
227 * let LinearLayout do all the hard work, and then shift everything down to the bottom.
228 */
229 @Override
230 protected void onLayout(boolean changed, int l, int t, int r, int b) {
231 super.onLayout(changed, l, t, r, b);
232 // setPanelHeight(mSearchTargetsContainer.getHeight());
233 }
234
235 @Override
236 public boolean dispatchHoverEvent(MotionEvent event) {
237 // Ignore hover events outside of this panel bounds since such events
238 // generate spurious accessibility events with the panel content when
239 // tapping outside of it, thus confusing the user.
240 final int x = (int) event.getX();
241 final int y = (int) event.getY();
242 if (x >= 0 && x < getWidth() && y >= 0 && y < getHeight()) {
243 return super.dispatchHoverEvent(event);
244 }
245 return true;
246 }
247
248 /**
249 * Whether the panel is showing, or, if it's animating, whether it will be
250 * when the animation is done.
251 */
252 public boolean isShowing() {
253 return mShowing;
254 }
255
256 public void setBar(BaseStatusBar bar) {
257 mBar = bar;
258 }
259
260 public void setStatusBarView(final View statusBarView) {
261 if (mStatusBarTouchProxy != null) {
262 mStatusBarTouchProxy.setStatusBar(statusBarView);
Jim Miller955a0162012-06-11 21:06:13 -0700263// mGlowPadView.setOnTouchListener(new OnTouchListener() {
Jim Millere898ac52012-04-06 17:10:57 -0700264// public boolean onTouch(View v, MotionEvent event) {
265// return statusBarView.onTouchEvent(event);
266// }
267// });
268 }
269 }
270
Jim Millera073e572012-05-23 17:03:27 -0700271 private LayoutTransition createLayoutTransitioner() {
272 LayoutTransition transitioner = new LayoutTransition();
Jim Millere898ac52012-04-06 17:10:57 -0700273 transitioner.setDuration(200);
274 transitioner.setStartDelay(LayoutTransition.CHANGE_DISAPPEARING, 0);
275 transitioner.setAnimator(LayoutTransition.DISAPPEARING, null);
Jim Millera073e572012-05-23 17:03:27 -0700276 return transitioner;
Jim Millere898ac52012-04-06 17:10:57 -0700277 }
Jim Miller45308b12012-06-18 19:23:39 -0700278
279 public boolean isAssistantAvailable() {
280 return SearchManager.getAssistIntent(mContext) != null;
281 }
Jim Millere898ac52012-04-06 17:10:57 -0700282}