blob: 7ca69903032b92253cc14cd712aaf2c315021a3b [file] [log] [blame]
Winson Chung82f55532011-08-09 14:14:23 -07001/*
2 * Copyright (C) 2011 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
Daniel Sandler325dc232013-06-05 22:57:57 -040017package com.android.launcher3;
Winson Chung82f55532011-08-09 14:14:23 -070018
Winson Chungaf40f202013-09-18 18:26:31 -070019import android.animation.Animator;
20import android.animation.AnimatorListenerAdapter;
21import android.animation.ObjectAnimator;
Winson Chung82f55532011-08-09 14:14:23 -070022import android.content.Context;
23import android.content.res.Resources;
24import android.content.res.TypedArray;
Winson Chung7d7541e2011-09-16 20:14:36 -070025import android.graphics.Bitmap;
Winson Chung82f55532011-08-09 14:14:23 -070026import android.graphics.Canvas;
Winson Chunge6eabff2013-09-24 11:01:23 -070027import android.graphics.Color;
Winson Chung82f55532011-08-09 14:14:23 -070028import android.graphics.Paint;
Winson Chung7d7541e2011-09-16 20:14:36 -070029import android.graphics.PorterDuff;
30import android.graphics.PorterDuffXfermode;
31import android.graphics.Rect;
Winson Chung82f55532011-08-09 14:14:23 -070032import android.graphics.drawable.Drawable;
33import android.util.AttributeSet;
34import android.util.DisplayMetrics;
Svetoslav Ganov55d225d2012-05-22 15:19:14 -070035import android.view.FocusFinder;
36import android.view.MotionEvent;
37import android.view.View;
Winson Chungaf40f202013-09-18 18:26:31 -070038import android.view.animation.AccelerateInterpolator;
Winson Chung82f55532011-08-09 14:14:23 -070039import android.widget.FrameLayout;
40
Winson Chungaf40f202013-09-18 18:26:31 -070041public class Cling extends FrameLayout implements Insettable, View.OnLongClickListener {
Winson Chung82f55532011-08-09 14:14:23 -070042
Winson Chungaf40f202013-09-18 18:26:31 -070043 static final String FIRST_RUN_CLING_DISMISSED_KEY = "cling_gel.first_run.dismissed";
44 static final String WORKSPACE_CLING_DISMISSED_KEY = "cling_gel.workspace.dismissed";
45 static final String FOLDER_CLING_DISMISSED_KEY = "cling_gel.folder.dismissed";
46
47 private static String FIRST_RUN_PORTRAIT = "first_run_portrait";
48 private static String FIRST_RUN_LANDSCAPE = "first_run_landscape";
Winson Chung7d7541e2011-09-16 20:14:36 -070049
Winson Chung82f55532011-08-09 14:14:23 -070050 private static String WORKSPACE_PORTRAIT = "workspace_portrait";
51 private static String WORKSPACE_LANDSCAPE = "workspace_landscape";
Andrew Flynn2f5f9452012-05-12 17:00:35 -070052 private static String WORKSPACE_LARGE = "workspace_large";
53 private static String WORKSPACE_CUSTOM = "workspace_custom";
54
Winson Chung7d7541e2011-09-16 20:14:36 -070055 private static String FOLDER_PORTRAIT = "folder_portrait";
56 private static String FOLDER_LANDSCAPE = "folder_landscape";
Winson Chungd0160152011-11-15 15:04:42 -080057 private static String FOLDER_LARGE = "folder_large";
Winson Chung82f55532011-08-09 14:14:23 -070058
Winson Chunge6eabff2013-09-24 11:01:23 -070059 private static float FIRST_RUN_CIRCLE_BUFFER_DPS = 60;
Winson Chungaf40f202013-09-18 18:26:31 -070060 private static float WORKSPACE_INNER_CIRCLE_RADIUS_DPS = 50;
61 private static float WORKSPACE_OUTER_CIRCLE_RADIUS_DPS = 60;
62 private static float WORKSPACE_CIRCLE_Y_OFFSET_DPS = 30;
63
Winson Chung82f55532011-08-09 14:14:23 -070064 private Launcher mLauncher;
65 private boolean mIsInitialized;
66 private String mDrawIdentifier;
Winson Chung7d7541e2011-09-16 20:14:36 -070067 private Drawable mBackground;
Winson Chung82f55532011-08-09 14:14:23 -070068
Winson Chung7d7541e2011-09-16 20:14:36 -070069 private Paint mErasePaint;
Winson Chungaf40f202013-09-18 18:26:31 -070070 private Paint mBubblePaint;
71 private Paint mDotPaint;
72
73 private final Rect mInsets = new Rect();
Winson Chung7d7541e2011-09-16 20:14:36 -070074
Winson Chung82f55532011-08-09 14:14:23 -070075 public Cling(Context context) {
76 this(context, null, 0);
77 }
78
79 public Cling(Context context, AttributeSet attrs) {
80 this(context, attrs, 0);
81 }
82
83 public Cling(Context context, AttributeSet attrs, int defStyle) {
84 super(context, attrs, defStyle);
85
86 TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.Cling, defStyle, 0);
87 mDrawIdentifier = a.getString(R.styleable.Cling_drawIdentifier);
88 a.recycle();
Michael Jurka9bc8eba2012-05-21 20:36:44 -070089
90 setClickable(true);
Winson Chungaf40f202013-09-18 18:26:31 -070091
Winson Chung82f55532011-08-09 14:14:23 -070092 }
93
Winson Chung7d7541e2011-09-16 20:14:36 -070094 void init(Launcher l, int[] positionData) {
Winson Chung82f55532011-08-09 14:14:23 -070095 if (!mIsInitialized) {
96 mLauncher = l;
Winson Chungaf40f202013-09-18 18:26:31 -070097 setOnLongClickListener(this);
Winson Chung82f55532011-08-09 14:14:23 -070098
Winson Chung7d7541e2011-09-16 20:14:36 -070099 mErasePaint = new Paint();
100 mErasePaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.MULTIPLY));
101 mErasePaint.setColor(0xFFFFFF);
102 mErasePaint.setAlpha(0);
Winson Chungaf40f202013-09-18 18:26:31 -0700103 mErasePaint.setAntiAlias(true);
104
Winson Chunge6eabff2013-09-24 11:01:23 -0700105 int circleColor = getResources().getColor(
106 R.color.first_run_cling_circle_background_color);
Winson Chungaf40f202013-09-18 18:26:31 -0700107 mBubblePaint = new Paint();
Winson Chunge6eabff2013-09-24 11:01:23 -0700108 mBubblePaint.setColor(circleColor);
Winson Chungaf40f202013-09-18 18:26:31 -0700109 mBubblePaint.setAntiAlias(true);
110
111 mDotPaint = new Paint();
112 mDotPaint.setColor(0x72BBED);
113 mDotPaint.setAntiAlias(true);
Winson Chung7d7541e2011-09-16 20:14:36 -0700114
Winson Chung82f55532011-08-09 14:14:23 -0700115 mIsInitialized = true;
116 }
117 }
118
Winson Chungaf40f202013-09-18 18:26:31 -0700119 void show(boolean animate, int duration) {
120 setVisibility(View.VISIBLE);
121 setLayerType(View.LAYER_TYPE_HARDWARE, null);
122 if (mDrawIdentifier.equals(WORKSPACE_PORTRAIT) ||
123 mDrawIdentifier.equals(WORKSPACE_LANDSCAPE) ||
124 mDrawIdentifier.equals(WORKSPACE_LARGE) ||
125 mDrawIdentifier.equals(WORKSPACE_CUSTOM)) {
126 View content = getContent();
127 content.setAlpha(0f);
128 content.animate()
129 .alpha(1f)
130 .setDuration(duration)
131 .setListener(new AnimatorListenerAdapter() {
132 public void onAnimationEnd(Animator animation) {
133 };
134 })
135 .start();
136 setAlpha(1f);
137 } else {
138 if (animate) {
139 buildLayer();
140 setAlpha(0f);
141 animate()
142 .alpha(1f)
143 .setInterpolator(new AccelerateInterpolator())
144 .setDuration(duration)
145 .start();
146 } else {
147 setAlpha(1f);
148 }
149 }
150 setFocusableInTouchMode(true);
151 post(new Runnable() {
152 public void run() {
153 setFocusable(true);
154 requestFocus();
155 }
156 });
157 }
158
159 void hide(final int duration, final Runnable postCb) {
160 if (mDrawIdentifier.equals(FIRST_RUN_PORTRAIT) ||
161 mDrawIdentifier.equals(FIRST_RUN_LANDSCAPE)) {
162 View content = getContent();
163 ObjectAnimator anim = LauncherAnimUtils.ofFloat(content, "alpha", 0f);
164 anim.setDuration(duration);
165 anim.addListener(new AnimatorListenerAdapter() {
166 public void onAnimationEnd(Animator animation) {
167 // We are about to trigger the workspace cling, so don't do anything else
168 setVisibility(View.GONE);
169 postCb.run();
170 };
171 });
172 anim.start();
173 } else {
174 ObjectAnimator anim = LauncherAnimUtils.ofFloat(this, "alpha", 0f);
175 anim.setDuration(duration);
176 anim.addListener(new AnimatorListenerAdapter() {
177 public void onAnimationEnd(Animator animation) {
178 setVisibility(View.GONE);
179 postCb.run();
180 };
181 });
182 anim.start();
183 }
184 }
185
Winson Chung82f55532011-08-09 14:14:23 -0700186 void cleanup() {
Winson Chung7d7541e2011-09-16 20:14:36 -0700187 mBackground = null;
Winson Chung7d7541e2011-09-16 20:14:36 -0700188 mIsInitialized = false;
189 }
190
Winson Chungaf40f202013-09-18 18:26:31 -0700191 @Override
192 public void setInsets(Rect insets) {
193 mInsets.set(insets);
194 setPadding(insets.left, insets.top, insets.right, insets.bottom);
Michael Jurka974c3862012-05-22 22:00:31 -0700195 }
196
Winson Chungaf40f202013-09-18 18:26:31 -0700197 View getContent() {
198 return findViewById(R.id.content);
199 }
200
201 String getDrawIdentifier() {
202 return mDrawIdentifier;
Winson Chung82f55532011-08-09 14:14:23 -0700203 }
204
205 @Override
Svetoslav Ganov55d225d2012-05-22 15:19:14 -0700206 public View focusSearch(int direction) {
Michael Jurka9bc8eba2012-05-21 20:36:44 -0700207 return this.focusSearch(this, direction);
Svetoslav Ganov55d225d2012-05-22 15:19:14 -0700208 }
209
210 @Override
211 public View focusSearch(View focused, int direction) {
212 return FocusFinder.getInstance().findNextFocus(this, focused, direction);
213 }
214
215 @Override
216 public boolean onHoverEvent(MotionEvent event) {
217 return (mDrawIdentifier.equals(WORKSPACE_PORTRAIT)
218 || mDrawIdentifier.equals(WORKSPACE_LANDSCAPE)
219 || mDrawIdentifier.equals(WORKSPACE_LARGE)
Svetoslav Ganov55d225d2012-05-22 15:19:14 -0700220 || mDrawIdentifier.equals(WORKSPACE_CUSTOM));
221 }
222
223 @Override
Winson Chung82f55532011-08-09 14:14:23 -0700224 public boolean onTouchEvent(android.view.MotionEvent event) {
Winson Chungaf40f202013-09-18 18:26:31 -0700225 if (mDrawIdentifier.equals(FOLDER_PORTRAIT) ||
Winson Chungd0160152011-11-15 15:04:42 -0800226 mDrawIdentifier.equals(FOLDER_LANDSCAPE) ||
227 mDrawIdentifier.equals(FOLDER_LARGE)) {
Winson Chung7d7541e2011-09-16 20:14:36 -0700228 Folder f = mLauncher.getWorkspace().getOpenFolder();
229 if (f != null) {
230 Rect r = new Rect();
231 f.getHitRect(r);
232 if (r.contains((int) event.getX(), (int) event.getY())) {
233 return false;
234 }
235 }
236 }
Winson Chungaf40f202013-09-18 18:26:31 -0700237 return super.onTouchEvent(event);
Winson Chung82f55532011-08-09 14:14:23 -0700238 };
239
240 @Override
Winson Chungaf40f202013-09-18 18:26:31 -0700241 public boolean onLongClick(View v) {
242 if (mDrawIdentifier.equals(WORKSPACE_PORTRAIT) ||
243 mDrawIdentifier.equals(WORKSPACE_LANDSCAPE) ||
244 mDrawIdentifier.equals(WORKSPACE_LARGE)) {
245 mLauncher.dismissWorkspaceCling(null);
246 return true;
247 }
248 return false;
249 }
250
251 @Override
Winson Chung82f55532011-08-09 14:14:23 -0700252 protected void dispatchDraw(Canvas canvas) {
Winson Chung82f55532011-08-09 14:14:23 -0700253 if (mIsInitialized) {
Winson Chungaf40f202013-09-18 18:26:31 -0700254 canvas.save();
Winson Chung82f55532011-08-09 14:14:23 -0700255
Winson Chungaf40f202013-09-18 18:26:31 -0700256 // Get the background override if there is one
Winson Chung7d7541e2011-09-16 20:14:36 -0700257 if (mBackground == null) {
Winson Chungaf40f202013-09-18 18:26:31 -0700258 if (mDrawIdentifier.equals(WORKSPACE_CUSTOM)) {
Andrew Flynna743d352012-05-18 13:38:52 -0700259 mBackground = getResources().getDrawable(R.drawable.bg_cling5);
Winson Chung7d7541e2011-09-16 20:14:36 -0700260 }
261 }
Winson Chungaf40f202013-09-18 18:26:31 -0700262 // Draw the background
263 Bitmap eraseBg = null;
264 Canvas eraseCanvas = null;
Winson Chung7d7541e2011-09-16 20:14:36 -0700265 if (mBackground != null) {
266 mBackground.setBounds(0, 0, getMeasuredWidth(), getMeasuredHeight());
Winson Chungaf40f202013-09-18 18:26:31 -0700267 mBackground.draw(canvas);
268 } else if (mDrawIdentifier.equals(FOLDER_PORTRAIT) ||
269 mDrawIdentifier.equals(FOLDER_LANDSCAPE) ||
270 mDrawIdentifier.equals(FOLDER_LARGE)) {
271 canvas.drawColor(0xcc000000);
272 } else if (mDrawIdentifier.equals(WORKSPACE_PORTRAIT) ||
273 mDrawIdentifier.equals(WORKSPACE_LANDSCAPE) ||
274 mDrawIdentifier.equals(WORKSPACE_LARGE)) {
275 // Initialize the draw buffer (to allow punching through)
276 eraseBg = Bitmap.createBitmap(getMeasuredWidth(), getMeasuredHeight(),
277 Bitmap.Config.ARGB_8888);
278 eraseCanvas = new Canvas(eraseBg);
279 eraseCanvas.drawColor(0xdd000000);
Winson Chung7d7541e2011-09-16 20:14:36 -0700280 } else {
Winson Chungaf40f202013-09-18 18:26:31 -0700281 canvas.drawColor(0xdd000000);
Winson Chung7d7541e2011-09-16 20:14:36 -0700282 }
Winson Chung82f55532011-08-09 14:14:23 -0700283
Winson Chungaf40f202013-09-18 18:26:31 -0700284 // Draw everything else
285 DisplayMetrics metrics = new DisplayMetrics();
286 mLauncher.getWindowManager().getDefaultDisplay().getMetrics(metrics);
287 float alpha = getAlpha();
288 View content = getContent();
289 if (content != null) {
290 alpha *= content.getAlpha();
291 }
292 if (mDrawIdentifier.equals(FIRST_RUN_PORTRAIT) ||
293 mDrawIdentifier.equals(FIRST_RUN_LANDSCAPE)) {
294 // Draw the white circle
295 View bubbleContent = findViewById(R.id.bubble_content);
296 Rect bubbleRect = new Rect();
297 bubbleContent.getGlobalVisibleRect(bubbleRect);
298 mBubblePaint.setAlpha((int) (255 * alpha));
299 float buffer = DynamicGrid.pxFromDp(FIRST_RUN_CIRCLE_BUFFER_DPS, metrics);
300 canvas.drawCircle(metrics.widthPixels / 2,
301 bubbleRect.centerY(),
302 (bubbleContent.getMeasuredWidth() + buffer) / 2,
303 mBubblePaint);
304 } else if (mDrawIdentifier.equals(WORKSPACE_PORTRAIT) ||
305 mDrawIdentifier.equals(WORKSPACE_LANDSCAPE) ||
306 mDrawIdentifier.equals(WORKSPACE_LARGE)) {
307 int offset = DynamicGrid.pxFromDp(WORKSPACE_CIRCLE_Y_OFFSET_DPS, metrics);
308 mErasePaint.setAlpha((int) (128));
309 eraseCanvas.drawCircle(metrics.widthPixels / 2,
310 metrics.heightPixels / 2 - offset,
311 DynamicGrid.pxFromDp(WORKSPACE_OUTER_CIRCLE_RADIUS_DPS, metrics),
312 mErasePaint);
313 mErasePaint.setAlpha(0);
314 eraseCanvas.drawCircle(metrics.widthPixels / 2,
315 metrics.heightPixels / 2 - offset,
316 DynamicGrid.pxFromDp(WORKSPACE_INNER_CIRCLE_RADIUS_DPS, metrics),
317 mErasePaint);
318 canvas.drawBitmap(eraseBg, 0, 0, null);
319 eraseCanvas.setBitmap(null);
320 eraseBg = null;
Winson Chung82f55532011-08-09 14:14:23 -0700321 }
Winson Chung7d7541e2011-09-16 20:14:36 -0700322
Winson Chung7d7541e2011-09-16 20:14:36 -0700323
Winson Chungaf40f202013-09-18 18:26:31 -0700324 canvas.restore();
Winson Chung82f55532011-08-09 14:14:23 -0700325 }
Winson Chung7d7541e2011-09-16 20:14:36 -0700326
327 // Draw the rest of the cling
328 super.dispatchDraw(canvas);
Winson Chung82f55532011-08-09 14:14:23 -0700329 };
330}