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