1 /* 2 * Copyright (C) 2010 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.appwidget.AppWidgetProviderInfo; 20 import android.content.Context; 21 import android.content.pm.PackageManager; 22 import android.content.pm.ResolveInfo; 23 import android.content.res.Resources; 24 import android.graphics.Rect; 25 import android.util.AttributeSet; 26 import android.view.MotionEvent; 27 import android.view.View; 28 import android.widget.ImageView; 29 import android.widget.LinearLayout; 30 import android.widget.TextView; 31 32 import com.android.launcher.R; 33 34 /** 35 * The linear layout used strictly for the widget/wallpaper tab of the customization tray 36 */ 37 public class PagedViewWidget extends LinearLayout { 38 static final String TAG = "PagedViewWidgetLayout"; 39 40 private static boolean sDeletePreviewsWhenDetachedFromWindow = true; 41 private static boolean sRecyclePreviewsWhenDetachedFromWindow = true; 42 43 private String mDimensionsFormatString; 44 CheckForShortPress mPendingCheckForShortPress = null; 45 ShortPressListener mShortPressListener = null; 46 boolean mShortPressTriggered = false; 47 static PagedViewWidget sShortpressTarget = null; 48 boolean mIsAppWidget; 49 private final Rect mOriginalImagePadding = new Rect(); 50 private Object mInfo; 51 private WidgetPreviewLoader mWidgetPreviewLoader; 52 53 public PagedViewWidget(Context context) { 54 this(context, null); 55 } 56 57 public PagedViewWidget(Context context, AttributeSet attrs) { 58 this(context, attrs, 0); 59 } 60 61 public PagedViewWidget(Context context, AttributeSet attrs, int defStyle) { 62 super(context, attrs, defStyle); 63 64 final Resources r = context.getResources(); 65 mDimensionsFormatString = r.getString(R.string.widget_dims_format); 66 67 setWillNotDraw(false); 68 setClipToPadding(false); 69 } 70 71 @Override 72 protected void onFinishInflate() { 73 super.onFinishInflate(); 74 75 final ImageView image = (ImageView) findViewById(R.id.widget_preview); 76 mOriginalImagePadding.left = image.getPaddingLeft(); 77 mOriginalImagePadding.top = image.getPaddingTop(); 78 mOriginalImagePadding.right = image.getPaddingRight(); 79 mOriginalImagePadding.bottom = image.getPaddingBottom(); 80 } 81 82 public static void setDeletePreviewsWhenDetachedFromWindow(boolean value) { 83 sDeletePreviewsWhenDetachedFromWindow = value; 84 } 85 86 public static void setRecyclePreviewsWhenDetachedFromWindow(boolean value) { 87 sRecyclePreviewsWhenDetachedFromWindow = value; 88 } 89 90 @Override 91 protected void onDetachedFromWindow() { 92 super.onDetachedFromWindow(); 93 94 if (sDeletePreviewsWhenDetachedFromWindow) { 95 final ImageView image = (ImageView) findViewById(R.id.widget_preview); 96 if (image != null) { 97 FastBitmapDrawable preview = (FastBitmapDrawable) image.getDrawable(); 98 if (sRecyclePreviewsWhenDetachedFromWindow && 99 mInfo != null && preview != null && preview.getBitmap() != null) { 100 mWidgetPreviewLoader.recycleBitmap(mInfo, preview.getBitmap()); 101 } 102 image.setImageDrawable(null); 103 } 104 } 105 } 106 107 public void applyFromAppWidgetProviderInfo(AppWidgetProviderInfo info, 108 int maxWidth, int[] cellSpan, WidgetPreviewLoader loader) { 109 mIsAppWidget = true; 110 mInfo = info; 111 final ImageView image = (ImageView) findViewById(R.id.widget_preview); 112 if (maxWidth > -1) { 113 image.setMaxWidth(maxWidth); 114 } 115 final TextView name = (TextView) findViewById(R.id.widget_name); 116 name.setText(info.label); 117 final TextView dims = (TextView) findViewById(R.id.widget_dims); 118 if (dims != null) { 119 int hSpan = Math.min(cellSpan[0], LauncherModel.getCellCountX()); 120 int vSpan = Math.min(cellSpan[1], LauncherModel.getCellCountY()); 121 dims.setText(String.format(mDimensionsFormatString, hSpan, vSpan)); 122 } 123 mWidgetPreviewLoader = loader; 124 } 125 126 public void applyFromResolveInfo( 127 PackageManager pm, ResolveInfo info, WidgetPreviewLoader loader) { 128 mIsAppWidget = false; 129 mInfo = info; 130 CharSequence label = info.loadLabel(pm); 131 final ImageView image = (ImageView) findViewById(R.id.widget_preview); 132 final TextView name = (TextView) findViewById(R.id.widget_name); 133 name.setText(label); 134 final TextView dims = (TextView) findViewById(R.id.widget_dims); 135 if (dims != null) { 136 dims.setText(String.format(mDimensionsFormatString, 1, 1)); 137 } 138 mWidgetPreviewLoader = loader; 139 } 140 141 public int[] getPreviewSize() { 142 final ImageView i = (ImageView) findViewById(R.id.widget_preview); 143 int[] maxSize = new int[2]; 144 maxSize[0] = i.getWidth() - mOriginalImagePadding.left - mOriginalImagePadding.right; 145 maxSize[1] = i.getHeight() - mOriginalImagePadding.top; 146 return maxSize; 147 } 148 149 void applyPreview(FastBitmapDrawable preview, int index) { 150 final PagedViewWidgetImageView image = 151 (PagedViewWidgetImageView) findViewById(R.id.widget_preview); 152 if (preview != null) { 153 image.mAllowRequestLayout = false; 154 image.setImageDrawable(preview); 155 if (mIsAppWidget) { 156 // center horizontally 157 int[] imageSize = getPreviewSize(); 158 int centerAmount = (imageSize[0] - preview.getIntrinsicWidth()) / 2; 159 image.setPadding(mOriginalImagePadding.left + centerAmount, 160 mOriginalImagePadding.top, 161 mOriginalImagePadding.right, 162 mOriginalImagePadding.bottom); 163 } 164 image.setAlpha(1f); 165 image.mAllowRequestLayout = true; 166 } 167 } 168 169 void setShortPressListener(ShortPressListener listener) { 170 mShortPressListener = listener; 171 } 172 173 interface ShortPressListener { 174 void onShortPress(View v); 175 void cleanUpShortPress(View v); 176 } 177 178 class CheckForShortPress implements Runnable { 179 public void run() { 180 if (sShortpressTarget != null) return; 181 if (mShortPressListener != null) { 182 mShortPressListener.onShortPress(PagedViewWidget.this); 183 sShortpressTarget = PagedViewWidget.this; 184 } 185 mShortPressTriggered = true; 186 } 187 } 188 189 private void checkForShortPress() { 190 if (sShortpressTarget != null) return; 191 if (mPendingCheckForShortPress == null) { 192 mPendingCheckForShortPress = new CheckForShortPress(); 193 } 194 postDelayed(mPendingCheckForShortPress, 120); 195 } 196 197 /** 198 * Remove the longpress detection timer. 199 */ 200 private void removeShortPressCallback() { 201 if (mPendingCheckForShortPress != null) { 202 removeCallbacks(mPendingCheckForShortPress); 203 } 204 } 205 206 private void cleanUpShortPress() { 207 removeShortPressCallback(); 208 if (mShortPressTriggered) { 209 if (mShortPressListener != null) { 210 mShortPressListener.cleanUpShortPress(PagedViewWidget.this); 211 } 212 mShortPressTriggered = false; 213 } 214 } 215 216 static void resetShortPressTarget() { 217 sShortpressTarget = null; 218 } 219 220 @Override 221 public boolean onTouchEvent(MotionEvent event) { 222 super.onTouchEvent(event); 223 224 switch (event.getAction()) { 225 case MotionEvent.ACTION_UP: 226 cleanUpShortPress(); 227 break; 228 case MotionEvent.ACTION_DOWN: 229 checkForShortPress(); 230 break; 231 case MotionEvent.ACTION_CANCEL: 232 cleanUpShortPress(); 233 break; 234 case MotionEvent.ACTION_MOVE: 235 break; 236 } 237 238 // We eat up the touch events here, since the PagedView (which uses the same swiping 239 // touch code as Workspace previously) uses onInterceptTouchEvent() to determine when 240 // the user is scrolling between pages. This means that if the pages themselves don't 241 // handle touch events, it gets forwarded up to PagedView itself, and it's own 242 // onTouchEvent() handling will prevent further intercept touch events from being called 243 // (it's the same view in that case). This is not ideal, but to prevent more changes, 244 // we just always mark the touch event as handled. 245 return true; 246 } 247 } 248