1 /* 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 17 package com.android.launcher2; 18 19 import android.content.Context; 20 import android.content.res.Resources; 21 import android.content.res.TypedArray; 22 import android.graphics.Bitmap; 23 import android.graphics.Canvas; 24 import android.graphics.Paint; 25 import android.graphics.PorterDuff; 26 import android.graphics.PorterDuffXfermode; 27 import android.graphics.Rect; 28 import android.graphics.drawable.Drawable; 29 import android.util.AttributeSet; 30 import android.util.DisplayMetrics; 31 import android.view.View; 32 import android.widget.FrameLayout; 33 34 import com.android.launcher.R; 35 36 public class Cling extends FrameLayout { 37 38 static final String WORKSPACE_CLING_DISMISSED_KEY = "cling.workspace.dismissed"; 39 static final String ALLAPPS_CLING_DISMISSED_KEY = "cling.allapps.dismissed"; 40 static final String FOLDER_CLING_DISMISSED_KEY = "cling.folder.dismissed"; 41 42 private static String WORKSPACE_PORTRAIT = "workspace_portrait"; 43 private static String WORKSPACE_LANDSCAPE = "workspace_landscape"; 44 private static String ALLAPPS_PORTRAIT = "all_apps_portrait"; 45 private static String ALLAPPS_LANDSCAPE = "all_apps_landscape"; 46 private static String FOLDER_PORTRAIT = "folder_portrait"; 47 private static String FOLDER_LANDSCAPE = "folder_landscape"; 48 49 private Launcher mLauncher; 50 private boolean mIsInitialized; 51 private String mDrawIdentifier; 52 private Drawable mBackground; 53 private Drawable mPunchThroughGraphic; 54 private Drawable mHandTouchGraphic; 55 private int mPunchThroughGraphicCenterRadius; 56 private int mAppIconSize; 57 private int mTabBarHeight; 58 private int mTabBarHorizontalPadding; 59 private int mButtonBarHeight; 60 private float mRevealRadius; 61 private int[] mPositionData; 62 63 private Paint mErasePaint; 64 Cling(Context context)65 public Cling(Context context) { 66 this(context, null, 0); 67 } 68 Cling(Context context, AttributeSet attrs)69 public Cling(Context context, AttributeSet attrs) { 70 this(context, attrs, 0); 71 } 72 Cling(Context context, AttributeSet attrs, int defStyle)73 public Cling(Context context, AttributeSet attrs, int defStyle) { 74 super(context, attrs, defStyle); 75 76 TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.Cling, defStyle, 0); 77 mDrawIdentifier = a.getString(R.styleable.Cling_drawIdentifier); 78 a.recycle(); 79 } 80 init(Launcher l, int[] positionData)81 void init(Launcher l, int[] positionData) { 82 if (!mIsInitialized) { 83 mLauncher = l; 84 mPositionData = positionData; 85 86 Resources r = getContext().getResources(); 87 mPunchThroughGraphic = r.getDrawable(R.drawable.cling); 88 mPunchThroughGraphicCenterRadius = 89 r.getDimensionPixelSize(R.dimen.clingPunchThroughGraphicCenterRadius); 90 mAppIconSize = r.getDimensionPixelSize(R.dimen.app_icon_size); 91 mRevealRadius = mAppIconSize * 1f; 92 mTabBarHeight = r.getDimensionPixelSize(R.dimen.apps_customize_tab_bar_height); 93 mTabBarHorizontalPadding = 94 r.getDimensionPixelSize(R.dimen.toolbar_button_horizontal_padding); 95 mButtonBarHeight = r.getDimensionPixelSize(R.dimen.button_bar_height); 96 97 mErasePaint = new Paint(); 98 mErasePaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.MULTIPLY)); 99 mErasePaint.setColor(0xFFFFFF); 100 mErasePaint.setAlpha(0); 101 102 mIsInitialized = true; 103 } 104 } 105 cleanup()106 void cleanup() { 107 mBackground = null; 108 mPunchThroughGraphic = null; 109 mHandTouchGraphic = null; 110 mIsInitialized = false; 111 } 112 getPunchThroughPosition()113 private int[] getPunchThroughPosition() { 114 if (mDrawIdentifier.equals(WORKSPACE_PORTRAIT)) { 115 return new int[]{getMeasuredWidth() / 2, getMeasuredHeight() - (mButtonBarHeight / 2)}; 116 } else if (mDrawIdentifier.equals(WORKSPACE_LANDSCAPE)) { 117 return new int[]{getMeasuredWidth() - (mButtonBarHeight / 2), getMeasuredHeight() / 2}; 118 } else if (mDrawIdentifier.equals(ALLAPPS_PORTRAIT) || 119 mDrawIdentifier.equals(ALLAPPS_LANDSCAPE)) { 120 return mPositionData; 121 } 122 return new int[]{-1, -1}; 123 } 124 125 @Override onTouchEvent(android.view.MotionEvent event)126 public boolean onTouchEvent(android.view.MotionEvent event) { 127 if (mDrawIdentifier.equals(WORKSPACE_PORTRAIT) || 128 mDrawIdentifier.equals(WORKSPACE_LANDSCAPE) || 129 mDrawIdentifier.equals(ALLAPPS_PORTRAIT) || 130 mDrawIdentifier.equals(ALLAPPS_LANDSCAPE)) { 131 int[] pos = getPunchThroughPosition(); 132 double diff = Math.sqrt(Math.pow(event.getX() - pos[0], 2) + 133 Math.pow(event.getY() - pos[1], 2)); 134 if (diff < mRevealRadius) { 135 return false; 136 } 137 } else if (mDrawIdentifier.equals(FOLDER_PORTRAIT) || 138 mDrawIdentifier.equals(FOLDER_LANDSCAPE)) { 139 Folder f = mLauncher.getWorkspace().getOpenFolder(); 140 if (f != null) { 141 Rect r = new Rect(); 142 f.getHitRect(r); 143 if (r.contains((int) event.getX(), (int) event.getY())) { 144 return false; 145 } 146 } 147 } 148 return true; 149 }; 150 151 @Override dispatchDraw(Canvas canvas)152 protected void dispatchDraw(Canvas canvas) { 153 if (mIsInitialized) { 154 DisplayMetrics metrics = new DisplayMetrics(); 155 mLauncher.getWindowManager().getDefaultDisplay().getMetrics(metrics); 156 157 // Initialize the draw buffer (to allow punching through) 158 Bitmap b = Bitmap.createBitmap(getMeasuredWidth(), getMeasuredHeight(), 159 Bitmap.Config.ARGB_8888); 160 Canvas c = new Canvas(b); 161 162 // Draw the background 163 if (mBackground == null) { 164 if (mDrawIdentifier.equals(WORKSPACE_PORTRAIT) || 165 mDrawIdentifier.equals(WORKSPACE_LANDSCAPE)) { 166 mBackground = getResources().getDrawable(R.drawable.bg_cling1); 167 } else if (mDrawIdentifier.equals(ALLAPPS_PORTRAIT) || 168 mDrawIdentifier.equals(ALLAPPS_LANDSCAPE)) { 169 mBackground = getResources().getDrawable(R.drawable.bg_cling2); 170 } else if (mDrawIdentifier.equals(FOLDER_PORTRAIT) || 171 mDrawIdentifier.equals(FOLDER_LANDSCAPE)) { 172 mBackground = getResources().getDrawable(R.drawable.bg_cling3); 173 } 174 } 175 if (mBackground != null) { 176 mBackground.setBounds(0, 0, getMeasuredWidth(), getMeasuredHeight()); 177 mBackground.draw(c); 178 } else { 179 c.drawColor(0x99000000); 180 } 181 182 int cx = -1; 183 int cy = -1; 184 float scale = mRevealRadius / mPunchThroughGraphicCenterRadius; 185 int dw = (int) (scale * mPunchThroughGraphic.getIntrinsicWidth()); 186 int dh = (int) (scale * mPunchThroughGraphic.getIntrinsicHeight()); 187 188 // Determine where to draw the punch through graphic 189 int[] pos = getPunchThroughPosition(); 190 cx = pos[0]; 191 cy = pos[1]; 192 if (cx > -1 && cy > -1) { 193 c.drawCircle(cx, cy, mRevealRadius, mErasePaint); 194 mPunchThroughGraphic.setBounds(cx - dw/2, cy - dh/2, cx + dw/2, cy + dh/2); 195 mPunchThroughGraphic.draw(c); 196 } 197 198 // Draw the hand graphic in All Apps 199 if (mDrawIdentifier.equals(ALLAPPS_PORTRAIT) || 200 mDrawIdentifier.equals(ALLAPPS_LANDSCAPE)) { 201 if (mHandTouchGraphic == null) { 202 mHandTouchGraphic = getResources().getDrawable(R.drawable.hand); 203 } 204 int offset = mAppIconSize / 4; 205 mHandTouchGraphic.setBounds(cx + offset, cy + offset, 206 cx + mHandTouchGraphic.getIntrinsicWidth() + offset, 207 cy + mHandTouchGraphic.getIntrinsicHeight() + offset); 208 mHandTouchGraphic.draw(c); 209 } 210 211 canvas.drawBitmap(b, 0, 0, null); 212 c.setBitmap(null); 213 b = null; 214 } 215 216 // Draw the rest of the cling 217 super.dispatchDraw(canvas); 218 }; 219 } 220