blob: 1f29990f890adbd89db7a016a9337f7249fba8d0 [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;
Daniel Sandlerd5483c32012-10-19 16:44:15 -040020import android.app.ActivityManagerNative;
Jim Miller998bb762012-05-21 13:37:27 -070021import android.app.ActivityOptions;
Jim Miller3b291872012-04-24 18:54:20 -070022import android.app.SearchManager;
Jim Millere898ac52012-04-06 17:10:57 -070023import android.content.ActivityNotFoundException;
Jim Miller3b291872012-04-24 18:54:20 -070024import android.content.ComponentName;
Jim Millere898ac52012-04-06 17:10:57 -070025import android.content.Context;
26import android.content.Intent;
Philip Milnea01a2a892012-05-29 14:46:54 -070027import android.content.res.Resources;
Daniel Sandlerd5483c32012-10-19 16:44:15 -040028import android.os.RemoteException;
Jim Miller4eeb4f62012-11-08 00:04:29 -080029import android.os.ServiceManager;
Dianne Hackbornf02b60a2012-08-16 10:48:27 -070030import android.os.UserHandle;
Philip Milnea01a2a892012-05-29 14:46:54 -070031import android.os.Vibrator;
32import android.provider.Settings;
Jim Millere898ac52012-04-06 17:10:57 -070033import android.util.AttributeSet;
Chris Wren64161cc2012-12-17 16:49:30 -050034import android.util.EventLog;
Jim Miller3b291872012-04-24 18:54:20 -070035import android.util.Slog;
Jim Miller4eeb4f62012-11-08 00:04:29 -080036import android.view.IWindowManager;
Jim Millere898ac52012-04-06 17:10:57 -070037import android.view.MotionEvent;
38import android.view.View;
39import android.view.ViewGroup;
Jim Miller20830422012-05-15 20:46:03 -070040import android.view.ViewTreeObserver;
41import android.view.ViewTreeObserver.OnPreDrawListener;
Jim Millere898ac52012-04-06 17:10:57 -070042import android.widget.FrameLayout;
Jeff Brownde7a8ea2012-06-13 18:28:57 -070043
Jim Miller955a0162012-06-11 21:06:13 -070044import com.android.internal.widget.multiwaveview.GlowPadView;
45import com.android.internal.widget.multiwaveview.GlowPadView.OnTriggerListener;
Chris Wren64161cc2012-12-17 16:49:30 -050046
47import com.android.systemui.EventLogTags;
Jim Millere898ac52012-04-06 17:10:57 -070048import com.android.systemui.R;
49import com.android.systemui.recent.StatusBarTouchProxy;
50import com.android.systemui.statusbar.BaseStatusBar;
Jim Miller9a720f52012-05-30 03:19:43 -070051import com.android.systemui.statusbar.CommandQueue;
Jim Millere898ac52012-04-06 17:10:57 -070052import com.android.systemui.statusbar.phone.PhoneStatusBar;
53import com.android.systemui.statusbar.tablet.StatusBarPanel;
54import com.android.systemui.statusbar.tablet.TabletStatusBar;
55
56public class SearchPanelView extends FrameLayout implements
Dianne Hackborn84375872012-06-01 19:03:50 -070057 StatusBarPanel, ActivityOptions.OnAnimationStartedListener {
58 private static final int SEARCH_PANEL_HOLD_DURATION = 0;
Jim Millere898ac52012-04-06 17:10:57 -070059 static final String TAG = "SearchPanelView";
60 static final boolean DEBUG = TabletStatusBar.DEBUG || PhoneStatusBar.DEBUG || false;
Chris Wren64161cc2012-12-17 16:49:30 -050061 public static final boolean DEBUG_GESTURES = true;
Jim Miller3294b6b2012-05-31 17:49:13 -070062 private static final String ASSIST_ICON_METADATA_NAME =
63 "com.android.systemui.action_assist_icon";
Jim Miller9a720f52012-05-30 03:19:43 -070064 private final Context mContext;
Jim Millere898ac52012-04-06 17:10:57 -070065 private BaseStatusBar mBar;
66 private StatusBarTouchProxy mStatusBarTouchProxy;
67
68 private boolean mShowing;
69 private View mSearchTargetsContainer;
Jim Miller955a0162012-06-11 21:06:13 -070070 private GlowPadView mGlowPadView;
Jim Miller4eeb4f62012-11-08 00:04:29 -080071 private IWindowManager mWm;
Jim Millere898ac52012-04-06 17:10:57 -070072
73 public SearchPanelView(Context context, AttributeSet attrs) {
74 this(context, attrs, 0);
75 }
76
77 public SearchPanelView(Context context, AttributeSet attrs, int defStyle) {
78 super(context, attrs, defStyle);
79 mContext = context;
Jim Miller4eeb4f62012-11-08 00:04:29 -080080 mWm = IWindowManager.Stub.asInterface(ServiceManager.getService("window"));
Jim Millere898ac52012-04-06 17:10:57 -070081 }
82
Jim Miller07994402012-05-02 14:22:27 -070083 private void startAssistActivity() {
Daniel Sandlerd5483c32012-10-19 16:44:15 -040084 if (!mBar.isDeviceProvisioned()) return;
85
Fabrice Di Meglio4d0d38b2012-05-25 11:36:03 -070086 // Close Recent Apps if needed
Daniel Sandler11cf1782012-09-27 14:03:08 -040087 mBar.animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_SEARCH_PANEL);
Jim Millerbac6d4b2012-11-08 01:20:55 -080088 boolean isKeyguardShowing = false;
Daniel Sandlerd5483c32012-10-19 16:44:15 -040089 try {
Jim Millerbac6d4b2012-11-08 01:20:55 -080090 isKeyguardShowing = mWm.isKeyguardLocked();
Daniel Sandlerd5483c32012-10-19 16:44:15 -040091 } catch (RemoteException e) {
Jim Millerbac6d4b2012-11-08 01:20:55 -080092
Daniel Sandlerd5483c32012-10-19 16:44:15 -040093 }
Jim Millerbac6d4b2012-11-08 01:20:55 -080094
95 if (isKeyguardShowing) {
96 // Have keyguard show the bouncer and launch the activity if the user succeeds.
97 try {
98 mWm.showAssistant();
99 } catch (RemoteException e) {
100 // too bad, so sad...
101 }
102 onAnimationStarted();
103 } else {
104 // Otherwise, keyguard isn't showing so launch it from here.
105 Intent intent = ((SearchManager) mContext.getSystemService(Context.SEARCH_SERVICE))
Dianne Hackbornf9c5e0f2013-01-23 14:39:13 -0800106 .getAssistIntent(mContext, true, UserHandle.USER_CURRENT);
Jim Millerbac6d4b2012-11-08 01:20:55 -0800107 if (intent == null) return;
108
109 try {
110 ActivityManagerNative.getDefault().dismissKeyguardOnNextActivity();
111 } catch (RemoteException e) {
112 // too bad, so sad...
113 }
114
115 try {
116 ActivityOptions opts = ActivityOptions.makeCustomAnimation(mContext,
117 R.anim.search_launch_enter, R.anim.search_launch_exit,
118 getHandler(), this);
119 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
120 mContext.startActivityAsUser(intent, opts.toBundle(),
121 new UserHandle(UserHandle.USER_CURRENT));
122 } catch (ActivityNotFoundException e) {
123 Slog.w(TAG, "Activity not found for " + intent.getAction());
124 onAnimationStarted();
125 }
126 }
Jim Miller07994402012-05-02 14:22:27 -0700127 }
128
Jim Miller955a0162012-06-11 21:06:13 -0700129 class GlowPadTriggerListener implements GlowPadView.OnTriggerListener {
Dianne Hackborn84375872012-06-01 19:03:50 -0700130 boolean mWaitingForLaunch;
Jim Miller998bb762012-05-21 13:37:27 -0700131
Jim Millere898ac52012-04-06 17:10:57 -0700132 public void onGrabbed(View v, int handle) {
133 }
134
135 public void onReleased(View v, int handle) {
136 }
137
138 public void onGrabbedStateChange(View v, int handle) {
Jim Millera073e572012-05-23 17:03:27 -0700139 if (!mWaitingForLaunch && OnTriggerListener.NO_HANDLE == handle) {
Jim Millere898ac52012-04-06 17:10:57 -0700140 mBar.hideSearchPanel();
141 }
142 }
143
Jim Millera073e572012-05-23 17:03:27 -0700144 public void onTrigger(View v, final int target) {
Jim Miller955a0162012-06-11 21:06:13 -0700145 final int resId = mGlowPadView.getResourceIdForTarget(target);
Jim Millera073e572012-05-23 17:03:27 -0700146 switch (resId) {
Jim Miller20039ad2012-06-15 17:26:28 -0700147 case com.android.internal.R.drawable.ic_action_assist_generic:
Jim Millera073e572012-05-23 17:03:27 -0700148 mWaitingForLaunch = true;
149 startAssistActivity();
Philip Milnea01a2a892012-05-29 14:46:54 -0700150 vibrate();
Philip Milnea01a2a892012-05-29 14:46:54 -0700151 break;
Jim Millera073e572012-05-23 17:03:27 -0700152 }
Jim Miller998bb762012-05-21 13:37:27 -0700153 }
154
155 public void onFinishFinalAnimation() {
Jim Miller3b291872012-04-24 18:54:20 -0700156 }
Dianne Hackborn84375872012-06-01 19:03:50 -0700157 }
Jim Miller955a0162012-06-11 21:06:13 -0700158 final GlowPadTriggerListener mGlowPadViewListener = new GlowPadTriggerListener();
Dianne Hackborn84375872012-06-01 19:03:50 -0700159
160 @Override
161 public void onAnimationStarted() {
162 postDelayed(new Runnable() {
163 public void run() {
Jim Miller955a0162012-06-11 21:06:13 -0700164 mGlowPadViewListener.mWaitingForLaunch = false;
Dianne Hackborn84375872012-06-01 19:03:50 -0700165 mBar.hideSearchPanel();
166 }
167 }, SEARCH_PANEL_HOLD_DURATION);
168 }
Jim Millere898ac52012-04-06 17:10:57 -0700169
170 @Override
171 protected void onFinishInflate() {
172 super.onFinishInflate();
173 mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
Jim Miller9a720f52012-05-30 03:19:43 -0700174 mSearchTargetsContainer = findViewById(R.id.search_panel_container);
Jim Millere898ac52012-04-06 17:10:57 -0700175 mStatusBarTouchProxy = (StatusBarTouchProxy) findViewById(R.id.status_bar_touch_proxy);
176 // TODO: fetch views
Jim Miller955a0162012-06-11 21:06:13 -0700177 mGlowPadView = (GlowPadView) findViewById(R.id.glow_pad_view);
178 mGlowPadView.setOnTriggerListener(mGlowPadViewListener);
Jim Miller45308b12012-06-18 19:23:39 -0700179 }
180
181 private void maybeSwapSearchIcon() {
Amith Yamasanic1d07a42012-08-14 09:32:02 -0700182 Intent intent = ((SearchManager) mContext.getSystemService(Context.SEARCH_SERVICE))
Dianne Hackbornf9c5e0f2013-01-23 14:39:13 -0800183 .getAssistIntent(mContext, false, UserHandle.USER_CURRENT);
Jim Miller45308b12012-06-18 19:23:39 -0700184 if (intent != null) {
185 ComponentName component = intent.getComponent();
186 if (component == null || !mGlowPadView.replaceTargetDrawablesIfPresent(component,
187 ASSIST_ICON_METADATA_NAME,
188 com.android.internal.R.drawable.ic_action_assist_generic)) {
189 if (DEBUG) Slog.v(TAG, "Couldn't grab icon for component " + component);
Jim Miller3294b6b2012-05-31 17:49:13 -0700190 }
Jim Miller3294b6b2012-05-31 17:49:13 -0700191 }
Jim Millere898ac52012-04-06 17:10:57 -0700192 }
193
194 private boolean pointInside(int x, int y, View v) {
195 final int l = v.getLeft();
196 final int r = v.getRight();
197 final int t = v.getTop();
198 final int b = v.getBottom();
199 return x >= l && x < r && y >= t && y < b;
200 }
201
202 public boolean isInContentArea(int x, int y) {
203 if (pointInside(x, y, mSearchTargetsContainer)) {
204 return true;
205 } else if (mStatusBarTouchProxy != null &&
206 pointInside(x, y, mStatusBarTouchProxy)) {
207 return true;
208 } else {
209 return false;
210 }
211 }
212
Jim Miller9a720f52012-05-30 03:19:43 -0700213 private final OnPreDrawListener mPreDrawListener = new ViewTreeObserver.OnPreDrawListener() {
Jim Miller20830422012-05-15 20:46:03 -0700214 public boolean onPreDraw() {
215 getViewTreeObserver().removeOnPreDrawListener(this);
Jim Miller955a0162012-06-11 21:06:13 -0700216 mGlowPadView.resumeAnimations();
Jim Miller20830422012-05-15 20:46:03 -0700217 return false;
218 }
219 };
220
Philip Milnea01a2a892012-05-29 14:46:54 -0700221 private void vibrate() {
222 Context context = getContext();
Jeff Sharkey723a7252012-10-12 14:26:31 -0700223 if (Settings.System.getIntForUser(context.getContentResolver(),
224 Settings.System.HAPTIC_FEEDBACK_ENABLED, 1, UserHandle.USER_CURRENT) != 0) {
Philip Milnea01a2a892012-05-29 14:46:54 -0700225 Resources res = context.getResources();
226 Vibrator vibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE);
227 vibrator.vibrate(res.getInteger(R.integer.config_search_panel_view_vibration_duration));
228 }
229 }
230
Jim Millerd99e7fd2012-05-08 16:30:42 -0700231 public void show(final boolean show, boolean animate) {
Jim Millera073e572012-05-23 17:03:27 -0700232 if (!show) {
233 final LayoutTransition transitioner = animate ? createLayoutTransitioner() : null;
Philip Milnea01a2a892012-05-29 14:46:54 -0700234 ((ViewGroup) mSearchTargetsContainer).setLayoutTransition(transitioner);
Jim Millere898ac52012-04-06 17:10:57 -0700235 }
Jim Millera073e572012-05-23 17:03:27 -0700236 mShowing = show;
Jim Miller20830422012-05-15 20:46:03 -0700237 if (show) {
Jim Miller45308b12012-06-18 19:23:39 -0700238 maybeSwapSearchIcon();
Jim Miller20830422012-05-15 20:46:03 -0700239 if (getVisibility() != View.VISIBLE) {
240 setVisibility(View.VISIBLE);
241 // Don't start the animation until we've created the layer, which is done
242 // right before we are drawn
Jim Miller955a0162012-06-11 21:06:13 -0700243 mGlowPadView.suspendAnimations();
244 mGlowPadView.ping();
Jim Miller20830422012-05-15 20:46:03 -0700245 getViewTreeObserver().addOnPreDrawListener(mPreDrawListener);
Philip Milnea01a2a892012-05-29 14:46:54 -0700246 vibrate();
Jim Millerd99e7fd2012-05-08 16:30:42 -0700247 }
Jim Miller20830422012-05-15 20:46:03 -0700248 setFocusable(true);
249 setFocusableInTouchMode(true);
250 requestFocus();
251 } else {
252 setVisibility(View.INVISIBLE);
253 }
Jim Millere898ac52012-04-06 17:10:57 -0700254 }
255
256 public void hide(boolean animate) {
Jim Millere898ac52012-04-06 17:10:57 -0700257 if (mBar != null) {
258 // This will indirectly cause show(false, ...) to get called
Daniel Sandler11cf1782012-09-27 14:03:08 -0400259 mBar.animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_NONE);
Jim Millerd99e7fd2012-05-08 16:30:42 -0700260 } else {
261 setVisibility(View.INVISIBLE);
Jim Millere898ac52012-04-06 17:10:57 -0700262 }
263 }
264
Jim Millere898ac52012-04-06 17:10:57 -0700265 /**
266 * We need to be aligned at the bottom. LinearLayout can't do this, so instead,
267 * let LinearLayout do all the hard work, and then shift everything down to the bottom.
268 */
269 @Override
270 protected void onLayout(boolean changed, int l, int t, int r, int b) {
271 super.onLayout(changed, l, t, r, b);
272 // setPanelHeight(mSearchTargetsContainer.getHeight());
273 }
274
275 @Override
276 public boolean dispatchHoverEvent(MotionEvent event) {
277 // Ignore hover events outside of this panel bounds since such events
278 // generate spurious accessibility events with the panel content when
279 // tapping outside of it, thus confusing the user.
280 final int x = (int) event.getX();
281 final int y = (int) event.getY();
282 if (x >= 0 && x < getWidth() && y >= 0 && y < getHeight()) {
283 return super.dispatchHoverEvent(event);
284 }
285 return true;
286 }
287
288 /**
289 * Whether the panel is showing, or, if it's animating, whether it will be
290 * when the animation is done.
291 */
292 public boolean isShowing() {
293 return mShowing;
294 }
295
296 public void setBar(BaseStatusBar bar) {
297 mBar = bar;
298 }
299
300 public void setStatusBarView(final View statusBarView) {
301 if (mStatusBarTouchProxy != null) {
302 mStatusBarTouchProxy.setStatusBar(statusBarView);
Jim Miller955a0162012-06-11 21:06:13 -0700303// mGlowPadView.setOnTouchListener(new OnTouchListener() {
Jim Millere898ac52012-04-06 17:10:57 -0700304// public boolean onTouch(View v, MotionEvent event) {
305// return statusBarView.onTouchEvent(event);
306// }
307// });
308 }
309 }
310
Chris Wren64161cc2012-12-17 16:49:30 -0500311 @Override
312 public boolean onTouchEvent(MotionEvent event) {
313 if (DEBUG_GESTURES) {
314 if (event.getActionMasked() != MotionEvent.ACTION_MOVE) {
315 EventLog.writeEvent(EventLogTags.SYSUI_SEARCHPANEL_TOUCH,
316 event.getActionMasked(), (int) event.getX(), (int) event.getY());
317 }
318 }
319 return super.onTouchEvent(event);
320 }
321
Jim Millera073e572012-05-23 17:03:27 -0700322 private LayoutTransition createLayoutTransitioner() {
323 LayoutTransition transitioner = new LayoutTransition();
Jim Millere898ac52012-04-06 17:10:57 -0700324 transitioner.setDuration(200);
325 transitioner.setStartDelay(LayoutTransition.CHANGE_DISAPPEARING, 0);
326 transitioner.setAnimator(LayoutTransition.DISAPPEARING, null);
Jim Millera073e572012-05-23 17:03:27 -0700327 return transitioner;
Jim Millere898ac52012-04-06 17:10:57 -0700328 }
Jim Miller45308b12012-06-18 19:23:39 -0700329
330 public boolean isAssistantAvailable() {
Amith Yamasanic1d07a42012-08-14 09:32:02 -0700331 return ((SearchManager) mContext.getSystemService(Context.SEARCH_SERVICE))
Dianne Hackbornf9c5e0f2013-01-23 14:39:13 -0800332 .getAssistIntent(mContext, false, UserHandle.USER_CURRENT) != null;
Jim Miller45308b12012-06-18 19:23:39 -0700333 }
Jim Millere898ac52012-04-06 17:10:57 -0700334}