Adding support for requesting addition of shortcut/widget

on the workspace.

Bug: 33584624
Change-Id: I664366822fe8088742faff2cce006239ab0771bc
This commit is contained in:
Sunny Goyal 2017-01-13 12:15:53 -08:00
parent 627006eeb4
commit 278359539c
13 changed files with 451 additions and 28 deletions

View File

@ -79,5 +79,13 @@
<meta-data android:name="android.nfc.disable_beam_default"
android:value="true" />
<activity android:name="com.android.launcher3.dragndrop.AddItemActivity"
android:theme="@android:style/Theme.DeviceDefault.Light.Dialog.Alert"
android:label="@string/action_add_to_workspace" >
<intent-filter>
<action android:name="android.content.pm.action.CONFIRM_PIN_ITEM" />
</intent-filter>
</activity>
</application>
</manifest>

View File

@ -0,0 +1,25 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
/*
** Copyright 2017, The Android Open Source Project
**
** Licensed under the Apache License, Version 2.0 (the "License");
** you may not use this file except in compliance with the License.
** You may obtain a copy of the License at
**
** http://www.apache.org/licenses/LICENSE-2.0
**
** Unless required by applicable law or agreed to in writing, software
** distributed under the License is distributed on an "AS IS" BASIS,
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
** See the License for the specific language governing permissions and
** limitations under the License.
*/
-->
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle" >
<stroke android:color="?android:attr/colorAccent"
android:dashGap="2dp"
android:dashWidth="4dp"
android:width="1dp" />
</shape>

View File

@ -0,0 +1,55 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
/*
** Copyright 2017, The Android Open Source Project
**
** Licensed under the Apache License, Version 2.0 (the "License");
** you may not use this file except in compliance with the License.
** You may obtain a copy of the License at
**
** http://www.apache.org/licenses/LICENSE-2.0
**
** Unless required by applicable law or agreed to in writing, software
** distributed under the License is distributed on an "AS IS" BASIS,
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
** See the License for the specific language governing permissions and
** limitations under the License.
*/
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:padding="16dp"
android:text="@string/add_item_request_drag_hint"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<TextView
android:layout_width="match_parent"
android:layout_height="100dp"
android:layout_margin="10dp"
android:gravity="center"
android:id="@+id/drag_target"
android:background="@drawable/bg_drag_box" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
style="?android:attr/buttonBarStyle"
android:gravity="end" >
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@android:string/cancel"
android:onClick="onCancelClick"
style="?android:attr/buttonBarButtonStyle" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/place_automatically"
android:onClick="onPlaceAutomaticallyClick"
style="?android:attr/buttonBarButtonStyle" />
</LinearLayout>
</LinearLayout>

View File

@ -52,6 +52,10 @@
<string name="widget_dims_format">%1$d \u00d7 %2$d</string>
<!-- Accessibility spoken message format for the dimensions of a widget in the drawer -->
<string name="widget_accessible_dims_format">%1$d wide by %2$d high</string>
<!-- Message to tell the user to press and hold a widget/icon to add it -->
<string name="add_item_request_drag_hint" translatable="false">Touch &amp; hold to place on home screen</string>
<!-- Button label to automatically add icon on home screen [CHAR_LIMIT=50] -->
<string name="place_automatically" translatable="false">Place automatically</string>
<!-- All Apps -->
<!-- Search bar text in the apps view. [CHAR_LIMIT=50] -->

View File

@ -0,0 +1,42 @@
/*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.launcher3;
import android.app.Activity;
import android.content.Context;
import android.content.ContextWrapper;
import android.view.View.AccessibilityDelegate;
public abstract class BaseActivity extends Activity {
protected DeviceProfile mDeviceProfile;
public DeviceProfile getDeviceProfile() {
return mDeviceProfile;
}
public AccessibilityDelegate getAccessibilityDelegate() {
return null;
}
public static BaseActivity fromContext(Context context) {
if (context instanceof BaseActivity) {
return (BaseActivity) context;
}
return ((BaseActivity) ((ContextWrapper) context).getBaseContext());
}
}

View File

@ -498,7 +498,9 @@ public class InstallShortcutReceiver extends BroadcastReceiver {
DeepShortcutManager sm = DeepShortcutManager.getInstance(context);
List<ShortcutInfoCompat> si = sm.queryForFullDetails(
decoder.launcherIntent.getPackage(),
Arrays.asList(ShortcutInfoCompat.EXTRA_SHORTCUT_ID), decoder.user);
Arrays.asList(decoder.launcherIntent.getStringExtra(
ShortcutInfoCompat.EXTRA_SHORTCUT_ID)),
decoder.user);
if (si.isEmpty()) {
return null;
} else {

View File

@ -18,6 +18,7 @@ package com.android.launcher3;
import android.annotation.TargetApi;
import android.content.Context;
import android.content.res.Configuration;
import android.content.res.TypedArray;
import android.content.res.XmlResourceParser;
import android.graphics.Point;
@ -326,6 +327,11 @@ public class InvariantDeviceProfile {
return rank == getAllAppsButtonRank();
}
public DeviceProfile getDeviceProfile(Context context) {
return context.getResources().getConfiguration().orientation
== Configuration.ORIENTATION_LANDSCAPE ? landscapeProfile : portraitProfile;
}
private float weight(float x0, float y0, float x1, float y1, float pow) {
float d = dist(x0, y0, x1, y1);
if (Float.compare(d, 0f) == 0) {

View File

@ -22,7 +22,6 @@ import android.animation.AnimatorSet;
import android.animation.ValueAnimator;
import android.annotation.SuppressLint;
import android.annotation.TargetApi;
import android.app.Activity;
import android.app.ActivityOptions;
import android.app.AlertDialog;
import android.app.SearchManager;
@ -42,7 +41,6 @@ import android.content.SharedPreferences;
import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
import android.content.res.Configuration;
import android.database.sqlite.SQLiteDatabase;
import android.graphics.Point;
import android.graphics.Rect;
@ -136,7 +134,7 @@ import java.util.List;
/**
* Default launcher application.
*/
public class Launcher extends Activity
public class Launcher extends BaseActivity
implements LauncherExterns, View.OnClickListener, OnLongClickListener,
LauncherModel.Callbacks, View.OnTouchListener, LauncherProviderChangeListener,
AccessibilityManager.AccessibilityStateChangeListener {
@ -194,7 +192,7 @@ public class Launcher extends Activity
private boolean mIsSafeModeEnabled;
static final int APPWIDGET_HOST_ID = 1024;
public static final int APPWIDGET_HOST_ID = 1024;
public static final int EXIT_SPRINGLOADED_MODE_SHORT_TIMEOUT = 500;
private static final int ON_ACTIVITY_RESULT_ANIMATION_DELAY = 500;
private static final int ACTIVITY_START_DELAY = 1000;
@ -273,8 +271,6 @@ public class Launcher extends Activity
// it from the context.
private SharedPreferences mSharedPrefs;
private DeviceProfile mDeviceProfile;
private boolean mMoveToDefaultScreenFromNewIntent;
// This is set to the view that launched the activity that navigated the user away from
@ -359,11 +355,7 @@ public class Launcher extends Activity
LauncherAppState app = LauncherAppState.getInstance(this);
// Load configuration-specific DeviceProfile
mDeviceProfile =
getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE
? app.getInvariantDeviceProfile().landscapeProfile
: app.getInvariantDeviceProfile().portraitProfile;
mDeviceProfile = app.getInvariantDeviceProfile().getDeviceProfile(this);
if (Utilities.ATLEAST_NOUGAT && isInMultiWindowMode()) {
Display display = getWindowManager().getDefaultDisplay();
Point mwSize = new Point();
@ -1657,10 +1649,6 @@ public class Launcher extends Activity
return mSharedPrefs;
}
public DeviceProfile getDeviceProfile() {
return mDeviceProfile;
}
@Override
protected void onNewIntent(Intent intent) {
long startTime = 0;

View File

@ -272,7 +272,7 @@ public class WidgetPreviewLoader {
return null;
}
private Bitmap generatePreview(Launcher launcher, WidgetItem item, Bitmap recycle,
private Bitmap generatePreview(BaseActivity launcher, WidgetItem item, Bitmap recycle,
int previewWidth, int previewHeight) {
if (item.widgetInfo != null) {
return generateWidgetPreview(launcher, item.widgetInfo,
@ -294,7 +294,7 @@ public class WidgetPreviewLoader {
* @param preScaledWidthOut return the width of the returned bitmap
* @return
*/
public Bitmap generateWidgetPreview(Launcher launcher, LauncherAppWidgetProviderInfo info,
public Bitmap generateWidgetPreview(BaseActivity launcher, LauncherAppWidgetProviderInfo info,
int maxPreviewWidth, Bitmap preview, int[] preScaledWidthOut) {
// Load the preview image if possible
if (maxPreviewWidth < 0) maxPreviewWidth = Integer.MAX_VALUE;
@ -415,7 +415,7 @@ public class WidgetPreviewLoader {
}
private Bitmap generateShortcutPreview(
Launcher launcher, ActivityInfo info, int maxWidth, int maxHeight, Bitmap preview) {
BaseActivity launcher, ActivityInfo info, int maxWidth, int maxHeight, Bitmap preview) {
final Canvas c = new Canvas();
if (preview == null) {
preview = Bitmap.createBitmap(maxWidth, maxHeight, Config.ARGB_8888);
@ -591,7 +591,7 @@ public class WidgetPreviewLoader {
// which would gets re-written next time.
mVersions = getPackageVersion(mKey.componentName.getPackageName());
Launcher launcher = Launcher.getLauncher(mCaller.getContext());
BaseActivity launcher = BaseActivity.fromContext(mCaller.getContext());
// it's not in the db... we need to generate it
preview = generatePreview(launcher, mInfo, unusedBitmap, mPreviewWidth, mPreviewHeight);

View File

@ -0,0 +1,83 @@
/*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.launcher3.compat;
import android.appwidget.AppWidgetProviderInfo;
import android.content.Intent;
import android.content.pm.ShortcutInfo;
import android.os.Bundle;
import android.os.Parcelable;
/**
* A wrapper around platform implementation of PinItemRequestCompat until the
* updated SDK is available.
*/
public class PinItemRequestCompat {
public static final String EXTRA_PIN_ITEM_REQUEST = "android.content.pm.extra.PIN_ITEM_REQUEST";
public static final int REQUEST_TYPE_SHORTCUT = 1;
public static final int REQUEST_TYPE_APPWIDGET = 2;
private final Parcelable mObject;
private PinItemRequestCompat(Parcelable object) {
mObject = object;
}
public int getRequestType() {
return (Integer) invokeMethod("getRequestType");
}
public ShortcutInfo getShortcutInfo() {
return (ShortcutInfo) invokeMethod("getShortcutInfo");
}
public AppWidgetProviderInfo getAppWidgetProviderInfo() {
return (AppWidgetProviderInfo) invokeMethod("getAppWidgetProviderInfo");
}
public boolean isValid() {
return (Boolean) invokeMethod("isValid");
}
public boolean accept() {
return (Boolean) invokeMethod("accept");
}
public boolean accept(Bundle options) {
try {
return (Boolean) mObject.getClass().getDeclaredMethod("accept", Bundle.class)
.invoke(mObject, options);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
private Object invokeMethod(String methodName) {
try {
return mObject.getClass().getDeclaredMethod(methodName).invoke(mObject);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public static PinItemRequestCompat getPinItemRequest(Intent intent) {
Parcelable extra = intent.getParcelableExtra(EXTRA_PIN_ITEM_REQUEST);
return extra == null ? null : new PinItemRequestCompat(extra);
}
}

View File

@ -0,0 +1,207 @@
/*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.launcher3.dragndrop;
import android.annotation.TargetApi;
import android.appwidget.AppWidgetHost;
import android.appwidget.AppWidgetManager;
import android.appwidget.AppWidgetProviderInfo;
import android.content.Intent;
import android.graphics.Bitmap;
import android.os.Build;
import android.os.Bundle;
import android.text.TextUtils;
import android.view.View;
import android.widget.TextView;
import com.android.launcher3.BaseActivity;
import com.android.launcher3.FastBitmapDrawable;
import com.android.launcher3.InstallShortcutReceiver;
import com.android.launcher3.InvariantDeviceProfile;
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherAppState;
import com.android.launcher3.LauncherAppWidgetProviderInfo;
import com.android.launcher3.R;
import com.android.launcher3.compat.AppWidgetManagerCompat;
import com.android.launcher3.compat.PinItemRequestCompat;
import com.android.launcher3.graphics.LauncherIcons;
import com.android.launcher3.shortcuts.DeepShortcutManager;
import com.android.launcher3.shortcuts.ShortcutInfoCompat;
import com.android.launcher3.widget.PendingAddWidgetInfo;
import com.android.launcher3.widget.WidgetHostViewLoader;
@TargetApi(Build.VERSION_CODES.N_MR1)
public class AddItemActivity extends BaseActivity {
private static final int REQUEST_BIND_APPWIDGET = 1;
private static final String STATE_EXTRA_WIDGET_ID = "state.widget.id";
private PinItemRequestCompat mRequest;
private LauncherAppState mApp;
private InvariantDeviceProfile mIdp;
private TextView mTextView;
// Widget request specific options.
private AppWidgetHost mAppWidgetHost;
private AppWidgetManagerCompat mAppWidgetManager;
private PendingAddWidgetInfo mPendingWidgetInfo;
private int mPendingBindWidgetId;
private Bundle mWidgetOptions;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mRequest = PinItemRequestCompat.getPinItemRequest(getIntent());
if (mRequest == null) {
finish();
return;
}
setContentView(R.layout.add_item_confirmation_activity);
mTextView = (TextView) findViewById(R.id.drag_target);
mApp = LauncherAppState.getInstance(this);
mIdp = mApp.getInvariantDeviceProfile();
// Use the application context to get the device profile, as in multiwindow-mode, the
// confirmation activity might be rotated.
mDeviceProfile = mIdp.getDeviceProfile(getApplicationContext());
if (mRequest.getRequestType() == PinItemRequestCompat.REQUEST_TYPE_SHORTCUT) {
setupShortcut();
} else {
if (!setupWidget()) {
// TODO: show error toast?
finish();
}
}
}
private void setupShortcut() {
ShortcutInfoCompat shortcut = new ShortcutInfoCompat(mRequest.getShortcutInfo());
FastBitmapDrawable d = new FastBitmapDrawable(LauncherIcons.createIconBitmap(
DeepShortcutManager.getInstance(this).getShortcutIconDrawable(
shortcut, mIdp.fillResIconDpi), this));
d.setFilterBitmap(true);
mTextView.setText(TextUtils.isEmpty(shortcut.getLongLabel())
? shortcut.getShortLabel() : shortcut.getLongLabel());
mTextView.setCompoundDrawables(null, d, null, null);
}
private boolean setupWidget() {
AppWidgetProviderInfo info = mRequest.getAppWidgetProviderInfo();
LauncherAppWidgetProviderInfo widgetInfo = AppWidgetManagerCompat.getInstance(this)
.findProvider(info.provider, info.getProfile());
if (widgetInfo.minSpanX > mIdp.numColumns || widgetInfo.minSpanY > mIdp.numRows) {
// Cannot add widget
return false;
}
mAppWidgetManager = AppWidgetManagerCompat.getInstance(this);
mAppWidgetHost = new AppWidgetHost(this, Launcher.APPWIDGET_HOST_ID);
mPendingWidgetInfo = new PendingAddWidgetInfo(widgetInfo);
mPendingWidgetInfo.spanX = Math.min(mIdp.numColumns, widgetInfo.spanX);
mPendingWidgetInfo.spanY = Math.min(mIdp.numRows, widgetInfo.spanY);
mWidgetOptions = WidgetHostViewLoader.getDefaultOptionsForWidget(this, mPendingWidgetInfo);
Bitmap preview = mApp.getWidgetCache().generateWidgetPreview(this, widgetInfo,
mPendingWidgetInfo.spanX * mDeviceProfile.cellWidthPx, null, null);
FastBitmapDrawable d = new FastBitmapDrawable(preview);
d.setFilterBitmap(true);
mTextView.setText(widgetInfo.getLabel(getPackageManager()));
mTextView.setCompoundDrawables(null, d, null, null);
return true;
}
/**
* Called when the cancel button is clicked.
*/
public void onCancelClick(View v) {
finish();
}
/**
* Called when place-automatically button is clicked.
*/
public void onPlaceAutomaticallyClick(View v) {
if (mRequest.getRequestType() == PinItemRequestCompat.REQUEST_TYPE_SHORTCUT) {
InstallShortcutReceiver.queueShortcut(
new ShortcutInfoCompat(mRequest.getShortcutInfo()), this);
mRequest.accept();
finish();
return;
}
mPendingBindWidgetId = mAppWidgetHost.allocateAppWidgetId();
boolean success = mAppWidgetManager.bindAppWidgetIdIfAllowed(
mPendingBindWidgetId, mRequest.getAppWidgetProviderInfo(), mWidgetOptions);
if (success) {
acceptWidget(mPendingBindWidgetId);
return;
}
// request bind widget
Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_BIND);
intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, mPendingBindWidgetId);
intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_PROVIDER,
mPendingWidgetInfo.componentName);
intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_PROVIDER_PROFILE,
mRequest.getAppWidgetProviderInfo().getProfile());
startActivityForResult(intent, REQUEST_BIND_APPWIDGET);
}
private void acceptWidget(int widgetId) {
InstallShortcutReceiver.queueWidget(mRequest.getAppWidgetProviderInfo(), widgetId, this);
mWidgetOptions.putInt(AppWidgetManager.EXTRA_APPWIDGET_ID, widgetId);
mRequest.accept(mWidgetOptions);
finish();
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == REQUEST_BIND_APPWIDGET) {
int widgetId = data != null
? data.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, mPendingBindWidgetId)
: mPendingBindWidgetId;
if (resultCode == RESULT_OK) {
acceptWidget(widgetId);
} else {
// Simply wait it out.
mAppWidgetHost.deleteAppWidgetId(widgetId);
mPendingBindWidgetId = -1;
}
return;
}
super.onActivityResult(requestCode, resultCode, data);
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putInt(STATE_EXTRA_WIDGET_ID, mPendingBindWidgetId);
}
@Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
mPendingBindWidgetId = savedInstanceState
.getInt(STATE_EXTRA_WIDGET_ID, mPendingBindWidgetId);
}
}

View File

@ -70,7 +70,8 @@ public class AddWorkspaceItemsTask extends ExtendedModelTask {
ArrayList<Long> workspaceScreens = LauncherModel.loadWorkspaceScreensDb(context);
synchronized(dataModel) {
for (ItemInfo item : workspaceApps) {
if (item instanceof ShortcutInfo) {
if (item.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION ||
item.itemType == LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT) {
// Short-circuit this logic if the icon exists somewhere on the workspace
if (shortcutExists(dataModel, item.getIntent(), item.user)) {
continue;
@ -143,6 +144,10 @@ public class AddWorkspaceItemsTask extends ExtendedModelTask {
*/
protected boolean shortcutExists(BgDataModel dataModel, Intent intent, UserHandle user) {
final String intentWithPkg, intentWithoutPkg;
if (intent == null) {
// Skip items with null intents
return true;
}
if (intent.getComponent() != null) {
// If component is not null, an intent with null package will produce
// the same result and should also be a match.

View File

@ -17,7 +17,6 @@
package com.android.launcher3.widget;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.util.AttributeSet;
import android.util.Log;
@ -28,8 +27,8 @@ import android.view.ViewPropertyAnimator;
import android.widget.LinearLayout;
import android.widget.TextView;
import com.android.launcher3.BaseActivity;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.Launcher;
import com.android.launcher3.R;
import com.android.launcher3.SimpleOnStylusPressListener;
import com.android.launcher3.StylusEventHelper;
@ -72,7 +71,7 @@ public class WidgetCell extends LinearLayout implements OnLayoutChangeListener {
private PreviewLoadRequest mActiveRequest;
private StylusEventHelper mStylusEventHelper;
private final Launcher mLauncher;
private final BaseActivity mActivity;
public WidgetCell(Context context) {
this(context, null);
@ -85,18 +84,17 @@ public class WidgetCell extends LinearLayout implements OnLayoutChangeListener {
public WidgetCell(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
final Resources r = context.getResources();
mLauncher = Launcher.getLauncher(context);
mActivity = BaseActivity.fromContext(context);
mStylusEventHelper = new StylusEventHelper(new SimpleOnStylusPressListener(this), this);
setContainerWidth();
setWillNotDraw(false);
setClipToPadding(false);
setAccessibilityDelegate(mLauncher.getAccessibilityDelegate());
setAccessibilityDelegate(mActivity.getAccessibilityDelegate());
}
private void setContainerWidth() {
DeviceProfile profile = mLauncher.getDeviceProfile();
DeviceProfile profile = mActivity.getDeviceProfile();
cellSize = (int) (profile.cellWidthPx * WIDTH_SCALE);
mPresetPreviewSize = (int) (cellSize * PREVIEW_SCALE);
}