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