Merge "Fix issue where overview panel was taking clicks because it was visible (issue 10732462)" into jb-ub-now-indigo-rose
diff --git a/Android.mk b/Android.mk
index 016d151..10c9f24 100644
--- a/Android.mk
+++ b/Android.mk
@@ -21,7 +21,13 @@
LOCAL_STATIC_JAVA_LIBRARIES := android-support-v13
-LOCAL_SRC_FILES := $(call all-java-files-under, src) $(call all-renderscript-files-under, src)
+LOCAL_SRC_FILES := $(call all-java-files-under, src) $(call all-renderscript-files-under, src) \
+ $(call all-proto-files-under, protos)
+
+LOCAL_PROTOC_OPTIMIZE_TYPE := nano
+
+LOCAL_PROTOC_FLAGS := --proto_path=$(LOCAL_PATH)/protos
+
LOCAL_SDK_VERSION := 17
LOCAL_PACKAGE_NAME := Launcher3
diff --git a/protos/backup.proto b/protos/backup.proto
new file mode 100644
index 0000000..3780bc5
--- /dev/null
+++ b/protos/backup.proto
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2013 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 launcher_backup;
+
+option java_package = "com.android.launcher3.backup";
+option java_outer_classname = "BackupProtos";
+
+message Key {
+ enum Type {
+ FAVORITE = 1;
+ SCREEN = 2;
+ IMAGE = 3;
+ }
+ required Type type = 1;
+ optional string name = 2; // keep this short
+ optional int64 id = 3;
+ optional int64 checksum = 4;
+}
+
+message CheckedMessage {
+ required bytes payload = 1;
+ required int64 checksum = 2;
+}
+
+message Journal {
+ required int32 app_version = 1;
+ required int64 t = 2;
+ optional int64 bytes = 3;
+ optional int32 rows = 4;
+ repeated Key key = 5;
+}
+
+message Favorite {
+ required int64 id = 1;
+ required int32 itemType = 2;
+ optional string title = 3;
+ optional int32 container = 4;
+ optional int32 screen = 5;
+ optional int32 cellX = 6;
+ optional int32 cellY = 7;
+ optional int32 spanX = 8;
+ optional int32 spanY = 9;
+ optional int32 displayMode = 10;
+ optional int32 appWidgetId = 11;
+ optional string appWidgetProvider = 12;
+ optional string intent = 13;
+ optional string uri = 14;
+ optional int32 iconType = 15;
+ optional string iconPackage = 16;
+ optional string iconResource = 17;
+ optional bytes icon = 18;
+ }
+
+message Screen {
+ required int64 id = 1;
+ optional int32 rank = 2;
+ }
+
+message Resource {
+ required int32 dpi = 2;
+ required bytes data = 3;
+ }
diff --git a/res/layout-land/first_run_cling.xml b/res/layout-land/first_run_cling.xml
index f827380..3b21e14 100644
--- a/res/layout-land/first_run_cling.xml
+++ b/res/layout-land/first_run_cling.xml
@@ -34,9 +34,10 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
+ android:layout_marginBottom="10dp"
android:text="@string/first_run_cling_title"
- android:textColor="#49C0EC"
- android:textSize="32sp" />
+ android:textColor="#FFFFFFFF"
+ android:textSize="30sp" />
<TextView
style="@style/ClingAltTitleText"
android:layout_width="wrap_content"
@@ -47,22 +48,28 @@
</LinearLayout>
<TextView
style="@style/ClingHintText"
+ android:id="@+id/search_bar_hint"
android:layout_width="160dp"
android:layout_height="wrap_content"
android:layout_gravity="top|end"
android:layout_marginEnd="10dp"
android:layout_marginTop="80dp"
- android:text="@string/first_run_cling_search_bar_hint"
- android:visibility="gone" />
+ android:visibility="gone"
+ android:drawableTop="@drawable/cling_arrow_up"
+ android:drawablePadding="5dp"
+ android:text="@string/first_run_cling_search_bar_hint" />
<TextView
style="@style/ClingHintText"
+ android:id="@+id/custom_content_hint"
android:layout_width="160dp"
android:layout_height="wrap_content"
android:layout_gravity="top"
android:layout_marginStart="10dp"
android:layout_marginTop="100dp"
- android:text="@string/first_run_cling_custom_content_hint"
- android:visibility="gone" />
+ android:visibility="gone"
+ android:drawableStart="@drawable/cling_arrow_left"
+ android:drawablePadding="10dp"
+ android:text="@string/first_run_cling_custom_content_hint" />
<TextView
style="@style/ClingHintText"
android:layout_width="160dp"
@@ -70,8 +77,9 @@
android:layout_gravity="bottom|end"
android:layout_marginEnd="10dp"
android:layout_marginBottom="100dp"
- android:text="@string/first_run_cling_create_screens_hint"
- android:visibility="gone" />
+ android:drawableEnd="@drawable/cling_arrow_right"
+ android:drawablePadding="5dp"
+ android:text="@string/first_run_cling_create_screens_hint" />
</FrameLayout>
<Button
style="@style/ClingButton"
diff --git a/res/layout-port/first_run_cling.xml b/res/layout-port/first_run_cling.xml
index cdc49b9..3b21e14 100644
--- a/res/layout-port/first_run_cling.xml
+++ b/res/layout-port/first_run_cling.xml
@@ -36,7 +36,7 @@
android:layout_gravity="center_horizontal"
android:layout_marginBottom="10dp"
android:text="@string/first_run_cling_title"
- android:textColor="#49C0EC"
+ android:textColor="#FFFFFFFF"
android:textSize="30sp" />
<TextView
style="@style/ClingAltTitleText"
@@ -48,19 +48,27 @@
</LinearLayout>
<TextView
style="@style/ClingHintText"
+ android:id="@+id/search_bar_hint"
android:layout_width="160dp"
android:layout_height="wrap_content"
android:layout_gravity="top|end"
android:layout_marginEnd="10dp"
android:layout_marginTop="80dp"
+ android:visibility="gone"
+ android:drawableTop="@drawable/cling_arrow_up"
+ android:drawablePadding="5dp"
android:text="@string/first_run_cling_search_bar_hint" />
<TextView
style="@style/ClingHintText"
+ android:id="@+id/custom_content_hint"
android:layout_width="160dp"
android:layout_height="wrap_content"
android:layout_gravity="top"
android:layout_marginStart="10dp"
android:layout_marginTop="100dp"
+ android:visibility="gone"
+ android:drawableStart="@drawable/cling_arrow_left"
+ android:drawablePadding="10dp"
android:text="@string/first_run_cling_custom_content_hint" />
<TextView
style="@style/ClingHintText"
@@ -70,6 +78,7 @@
android:layout_marginEnd="10dp"
android:layout_marginBottom="100dp"
android:drawableEnd="@drawable/cling_arrow_right"
+ android:drawablePadding="5dp"
android:text="@string/first_run_cling_create_screens_hint" />
</FrameLayout>
<Button
diff --git a/res/layout/apps_customize_pane.xml b/res/layout/apps_customize_pane.xml
index b01add9..e488601 100644
--- a/res/layout/apps_customize_pane.xml
+++ b/res/layout/apps_customize_pane.xml
@@ -16,7 +16,7 @@
<com.android.launcher3.AppsCustomizeTabHost
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:launcher="http://schemas.android.com/apk/res-auto/com.android.launcher3"
- android:background="#FF000000">
+ android:background="#80FFFFFF">
<LinearLayout
android:id="@+id/apps_customize_content"
android:orientation="vertical"
diff --git a/res/layout/apps_customize_widget.xml b/res/layout/apps_customize_widget.xml
index ad677e9..f2d2342 100644
--- a/res/layout/apps_customize_widget.xml
+++ b/res/layout/apps_customize_widget.xml
@@ -35,8 +35,7 @@
android:paddingStart="@dimen/app_widget_preview_padding_left"
android:paddingEnd="@dimen/app_widget_preview_padding_right"
android:scaleType="matrix"
- android:background="@drawable/widget_container_holo" />
-
+ android:background="@drawable/screenpanel" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
@@ -57,7 +56,10 @@
android:textColor="#FFFFFFFF"
android:textSize="13sp"
- android:textAlignment="viewStart" />
+ android:textAlignment="viewStart"
+ android:fontFamily="sans-serif-condensed"
+ android:shadowRadius="2.0"
+ android:shadowColor="#B0000000" />
<!-- The original dimensions of the widget (can't be the same text as above due to different
style. -->
@@ -70,8 +72,11 @@
android:layout_weight="0"
android:gravity="start"
- android:textColor="#FF555555"
- android:textSize="12sp" />
+ android:textColor="#FFAAAAAA"
+ android:textSize="12sp"
+ android:fontFamily="sans-serif-condensed"
+ android:shadowRadius="2.0"
+ android:shadowColor="#B0000000" />
</LinearLayout>
diff --git a/res/values/colors.xml b/res/values/colors.xml
index 48a06fc..43a856d 100644
--- a/res/values/colors.xml
+++ b/res/values/colors.xml
@@ -35,4 +35,6 @@
<color name="wallpaper_picker_translucent_gray">#66000000</color>
<color name="folder_items_text_color">#FF333333</color>
<color name="outline_color">#FFFFFFFF</color>
+
+ <color name="first_run_cling_circle_background_color">#FF83AEE8</color>
</resources>
diff --git a/res/values/styles.xml b/res/values/styles.xml
index e6bb935..9f2a105 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -94,10 +94,11 @@
</style>
<style name="WorkspaceIcon.AppsCustomize">
- <item name="android:shadowRadius">0.0</item> <!-- Don't use text shadow -->
<item name="android:background">@null</item>
<item name="android:textColor">@color/apps_customize_icon_text_color</item>
<item name="android:drawablePadding">4dp</item>
+ <item name="android:shadowRadius">4.0</item>
+ <item name="android:shadowColor">#FF000000</item>
</style>
<style name="QSBBar">
diff --git a/src/com/android/launcher3/AppsCustomizePagedView.java b/src/com/android/launcher3/AppsCustomizePagedView.java
index 213e50a..dd870e4 100644
--- a/src/com/android/launcher3/AppsCustomizePagedView.java
+++ b/src/com/android/launcher3/AppsCustomizePagedView.java
@@ -499,13 +499,7 @@
if (mPressedIcon != null) {
mPressedIcon.lockDrawableState();
}
-
- // NOTE: We want all transitions from launcher to act as if the wallpaper were enabled
- // to be consistent. So re-enable the flag here, and we will re-disable it as necessary
- // when Launcher resumes and we are still in AllApps.
- mLauncher.updateWallpaperVisibility(true);
mLauncher.startActivitySafely(v, appInfo.intent, appInfo);
-
} else if (v instanceof PagedViewWidget) {
// Let the user know that they have to long press to add a widget
if (mWidgetInstructionToast != null) {
diff --git a/src/com/android/launcher3/AppsCustomizeTabHost.java b/src/com/android/launcher3/AppsCustomizeTabHost.java
index f034183..bfcf92a 100644
--- a/src/com/android/launcher3/AppsCustomizeTabHost.java
+++ b/src/com/android/launcher3/AppsCustomizeTabHost.java
@@ -22,6 +22,7 @@
import android.animation.ObjectAnimator;
import android.content.Context;
import android.content.res.Resources;
+import android.graphics.Color;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.view.LayoutInflater;
@@ -81,13 +82,6 @@
setOnTabChangedListener(this);
}
- void selectAppsTab() {
- setContentTypeImmediate(AppsCustomizePagedView.ContentType.Applications);
- }
- void selectWidgetsTab() {
- setContentTypeImmediate(AppsCustomizePagedView.ContentType.Widgets);
- }
-
@Override
public void setInsets(Rect insets) {
mInsets.set(insets);
@@ -203,6 +197,9 @@
}
private void onTabChangedEnd(AppsCustomizePagedView.ContentType type) {
+ int bgAlpha = (int) (255 * (getResources().getInteger(
+ R.integer.config_appsCustomizeSpringLoadedBgAlpha) / 100f));
+ setBackgroundColor(Color.argb(bgAlpha, 0, 0, 0));
mAppsCustomizePane.setContentType(type);
}
diff --git a/src/com/android/launcher3/CellLayout.java b/src/com/android/launcher3/CellLayout.java
index 30ca737..22492ac 100644
--- a/src/com/android/launcher3/CellLayout.java
+++ b/src/com/android/launcher3/CellLayout.java
@@ -949,9 +949,11 @@
int heightSpecMode = MeasureSpec.getMode(heightMeasureSpec);
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
+ int childWidthSize = widthSize - (getPaddingLeft() + getPaddingRight());
+ int childHeightSize = heightSize - (getPaddingTop() + getPaddingBottom());
if (mFixedCellWidth < 0 || mFixedCellHeight < 0) {
- int cw = grid.calculateCellWidth(widthSize, mCountX);
- int ch = grid.calculateCellHeight(heightSize, mCountY);
+ int cw = grid.calculateCellWidth(childWidthSize, mCountX);
+ int ch = grid.calculateCellHeight(childHeightSize, mCountY);
if (cw != mCellWidth || ch != mCellHeight) {
mCellWidth = cw;
mCellHeight = ch;
@@ -960,8 +962,8 @@
}
}
- int newWidth = widthSize;
- int newHeight = heightSize;
+ int newWidth = childWidthSize;
+ int newHeight = childHeightSize;
if (mFixedWidth > 0 && mFixedHeight > 0) {
newWidth = mFixedWidth;
newHeight = mFixedHeight;
@@ -973,8 +975,8 @@
int numHeightGaps = mCountY - 1;
if (mOriginalWidthGap < 0 || mOriginalHeightGap < 0) {
- int hSpace = widthSize - getPaddingLeft() - getPaddingRight();
- int vSpace = heightSize - getPaddingTop() - getPaddingBottom();
+ int hSpace = childWidthSize;
+ int vSpace = childHeightSize;
int hFreeSpace = hSpace - (mCountX * mCellWidth);
int vFreeSpace = vSpace - (mCountY * mCellHeight);
mWidthGap = Math.min(mMaxGap, numWidthGaps > 0 ? (hFreeSpace / numWidthGaps) : 0);
@@ -990,15 +992,19 @@
int maxHeight = 0;
for (int i = 0; i < count; i++) {
View child = getChildAt(i);
- int childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(newWidth - getPaddingLeft() -
- getPaddingRight(), MeasureSpec.EXACTLY);
- int childheightMeasureSpec = MeasureSpec.makeMeasureSpec(newHeight - getPaddingTop() -
- getPaddingBottom(), MeasureSpec.EXACTLY);
+ int childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(newWidth,
+ MeasureSpec.EXACTLY);
+ int childheightMeasureSpec = MeasureSpec.makeMeasureSpec(newHeight,
+ MeasureSpec.EXACTLY);
child.measure(childWidthMeasureSpec, childheightMeasureSpec);
maxWidth = Math.max(maxWidth, child.getMeasuredWidth());
maxHeight = Math.max(maxHeight, child.getMeasuredHeight());
}
- setMeasuredDimension(maxWidth, maxHeight);
+ if (mFixedWidth > 0 && mFixedHeight > 0) {
+ setMeasuredDimension(maxWidth, maxHeight);
+ } else {
+ setMeasuredDimension(widthSize, heightSize);
+ }
}
@Override
@@ -1006,8 +1012,11 @@
int count = getChildCount();
for (int i = 0; i < count; i++) {
View child = getChildAt(i);
- child.layout(getPaddingLeft(), getPaddingTop(),
- r - l - getPaddingRight(), b - t - getPaddingBottom());
+ int left = getPaddingLeft();
+ int top = getPaddingTop();
+ child.layout(left, top,
+ left + r - l,
+ top + b - t);
}
}
diff --git a/src/com/android/launcher3/Cling.java b/src/com/android/launcher3/Cling.java
index 963702a..7ca6990 100644
--- a/src/com/android/launcher3/Cling.java
+++ b/src/com/android/launcher3/Cling.java
@@ -24,6 +24,7 @@
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.Canvas;
+import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
@@ -55,7 +56,7 @@
private static String FOLDER_LANDSCAPE = "folder_landscape";
private static String FOLDER_LARGE = "folder_large";
- private static float FIRST_RUN_CIRCLE_BUFFER_DPS = 40;
+ private static float FIRST_RUN_CIRCLE_BUFFER_DPS = 60;
private static float WORKSPACE_INNER_CIRCLE_RADIUS_DPS = 50;
private static float WORKSPACE_OUTER_CIRCLE_RADIUS_DPS = 60;
private static float WORKSPACE_CIRCLE_Y_OFFSET_DPS = 30;
@@ -101,8 +102,10 @@
mErasePaint.setAlpha(0);
mErasePaint.setAntiAlias(true);
+ int circleColor = getResources().getColor(
+ R.color.first_run_cling_circle_background_color);
mBubblePaint = new Paint();
- mBubblePaint.setColor(0xFFFFFF);
+ mBubblePaint.setColor(circleColor);
mBubblePaint.setAntiAlias(true);
mDotPaint = new Paint();
diff --git a/src/com/android/launcher3/DynamicGrid.java b/src/com/android/launcher3/DynamicGrid.java
index 664a99c..495e930 100644
--- a/src/com/android/launcher3/DynamicGrid.java
+++ b/src/com/android/launcher3/DynamicGrid.java
@@ -290,8 +290,7 @@
Rect getWorkspacePadding(int orientation) {
Rect padding = new Rect();
- if (orientation == CellLayout.LANDSCAPE &&
- transposeLayoutWithOrientation) {
+ if (isVerticalBarLayout()) {
// Pad the left and right of the workspace with search/hotseat bar sizes
padding.set(searchBarSpaceHeightPx, edgeMarginPx,
hotseatBarHeightPx, edgeMarginPx);
@@ -321,6 +320,17 @@
return padding;
}
+ // The rect returned will be extended to below the system ui that covers the workspace
+ Rect getHotseatRect() {
+ if (isVerticalBarLayout()) {
+ return new Rect(availableWidthPx - hotseatBarHeightPx, 0,
+ Integer.MAX_VALUE, availableHeightPx);
+ } else {
+ return new Rect(0, availableHeightPx - hotseatBarHeightPx,
+ availableWidthPx, Integer.MAX_VALUE);
+ }
+ }
+
int calculateCellWidth(int width, int countX) {
return width / countX;
}
@@ -338,11 +348,14 @@
return isLargeTablet;
}
+ boolean isVerticalBarLayout() {
+ return isLandscape && transposeLayoutWithOrientation;
+ }
+
public void layout(Launcher launcher) {
FrameLayout.LayoutParams lp;
Resources res = launcher.getResources();
- boolean hasVerticalBarLayout = isLandscape &&
- res.getBoolean(R.bool.hotseat_transpose_layout_with_orientation);
+ boolean hasVerticalBarLayout = isVerticalBarLayout();
// Layout the search bar space
View searchBarSpace = launcher.findViewById(R.id.qsb_bar);
@@ -430,7 +443,7 @@
lp.gravity = Gravity.BOTTOM;
lp.width = LayoutParams.MATCH_PARENT;
lp.height = hotseatBarHeightPx;
- hotseat.setPadding(2 * edgeMarginPx, 0,
+ hotseat.findViewById(R.id.layout).setPadding(2 * edgeMarginPx, 0,
2 * edgeMarginPx, 0);
}
hotseat.setLayoutParams(lp);
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index 3bbb39e..8959e7e 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -274,6 +274,7 @@
private boolean mVisible = false;
private boolean mAttached = false;
private static final boolean DISABLE_CLINGS = true;
+ private static final boolean DISABLE_CUSTOM_CLINGS = true;
private static LocaleConfiguration sLocaleConfiguration = null;
@@ -895,11 +896,6 @@
@Override
protected void onPause() {
- // NOTE: We want all transitions from launcher to act as if the wallpaper were enabled
- // to be consistent. So re-enable the flag here, and we will re-disable it as necessary
- // when Launcher resumes and we are still in AllApps.
- updateWallpaperVisibility(true);
-
// Ensure that items added to Launcher are queued until Launcher returns
InstallShortcutReceiver.enableInstallQueue();
@@ -2646,16 +2642,6 @@
view.setPivotY(view.getHeight() / 2.0f);
}
- void disableWallpaperIfInAllApps() {
- // Only disable it if we are in all apps
- if (isAllAppsVisible()) {
- if (mAppsCustomizeTabHost != null &&
- !mAppsCustomizeTabHost.isTransitioning()) {
- updateWallpaperVisibility(false);
- }
- }
- }
-
private void setWorkspaceBackground(boolean workspace) {
mLauncherView.setBackground(workspace ?
mWorkspaceBackgroundDrawable : null);
@@ -2815,7 +2801,6 @@
@Override
public void onAnimationStart(Animator animation) {
- updateWallpaperVisibility(true);
// Prepare the position
toView.setTranslationX(0.0f);
toView.setTranslationY(0.0f);
@@ -2827,10 +2812,6 @@
dispatchOnLauncherTransitionEnd(fromView, animated, false);
dispatchOnLauncherTransitionEnd(toView, animated, false);
- if (!animationCancelled) {
- updateWallpaperVisibility(false);
- }
-
// Hide the search bar
if (mSearchDropTargetBar != null) {
mSearchDropTargetBar.hideSearchBar(false);
@@ -2904,7 +2885,6 @@
dispatchOnLauncherTransitionPrepare(toView, animated, false);
dispatchOnLauncherTransitionStart(toView, animated, false);
dispatchOnLauncherTransitionEnd(toView, animated, false);
- updateWallpaperVisibility(false);
}
}
@@ -2941,7 +2921,6 @@
}
setPivotsForZoom(fromView, scaleFactor);
- updateWallpaperVisibility(true);
showHotseat(animated);
if (animated) {
final LauncherViewPropertyAnimator scaleAnim =
@@ -2973,7 +2952,6 @@
mStateAnimation.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
- updateWallpaperVisibility(true);
fromView.setVisibility(View.GONE);
dispatchOnLauncherTransitionEnd(fromView, animated, true);
dispatchOnLauncherTransitionEnd(toView, animated, true);
@@ -3011,30 +2989,13 @@
}
}
- @Override
- public void onWindowFocusChanged(boolean hasFocus) {
- if (!hasFocus) {
- // When another window occludes launcher (like the notification shade, or recents),
- // ensure that we enable the wallpaper flag so that transitions are done correctly.
- updateWallpaperVisibility(true);
- } else {
- // When launcher has focus again, disable the wallpaper if we are in AllApps
- mWorkspace.postDelayed(new Runnable() {
- @Override
- public void run() {
- disableWallpaperIfInAllApps();
- }
- }, 500);
- }
- }
-
void showWorkspace(boolean animated) {
showWorkspace(animated, null);
}
void showWorkspace(boolean animated, Runnable onCompleteRunnable) {
if (mState != State.WORKSPACE) {
- boolean wasInSpringLoadedMode = (mState == State.APPS_CUSTOMIZE_SPRING_LOADED);
+ boolean wasInSpringLoadedMode = (mState != State.WORKSPACE);
mWorkspace.setVisibility(View.VISIBLE);
hideAppsCustomizeHelper(State.WORKSPACE, animated, false, onCompleteRunnable);
@@ -4166,16 +4127,33 @@
// If we're not using the default workspace layout, replace workspace cling
// with a custom workspace cling (usually specified in an overlay)
// For now, only do this on tablets
- if (mSharedPrefs.getInt(LauncherProvider.DEFAULT_WORKSPACE_RESOURCE_ID, 0) != 0 &&
- getResources().getBoolean(R.bool.config_useCustomClings)) {
- // Use a custom cling
- View cling = findViewById(R.id.workspace_cling);
- ViewGroup clingParent = (ViewGroup) cling.getParent();
- int clingIndex = clingParent.indexOfChild(cling);
- clingParent.removeViewAt(clingIndex);
- View customCling = mInflater.inflate(R.layout.custom_workspace_cling, clingParent, false);
- clingParent.addView(customCling, clingIndex);
- customCling.setId(R.id.workspace_cling);
+ if (!DISABLE_CUSTOM_CLINGS) {
+ if (mSharedPrefs.getInt(LauncherProvider.DEFAULT_WORKSPACE_RESOURCE_ID, 0) != 0 &&
+ getResources().getBoolean(R.bool.config_useCustomClings)) {
+ // Use a custom cling
+ View cling = findViewById(R.id.workspace_cling);
+ ViewGroup clingParent = (ViewGroup) cling.getParent();
+ int clingIndex = clingParent.indexOfChild(cling);
+ clingParent.removeViewAt(clingIndex);
+ View customCling = mInflater.inflate(R.layout.custom_workspace_cling, clingParent, false);
+ clingParent.addView(customCling, clingIndex);
+ customCling.setId(R.id.workspace_cling);
+ }
+ }
+ Cling cling = (Cling) findViewById(R.id.first_run_cling);
+ if (cling != null) {
+ String sbHintStr = getFirstRunClingSearchBarHint();
+ String ccHintStr = getFirstRunCustomContentHint();
+ if (!sbHintStr.isEmpty()) {
+ TextView sbHint = (TextView) cling.findViewById(R.id.search_bar_hint);
+ sbHint.setText(sbHintStr);
+ sbHint.setVisibility(View.VISIBLE);
+ }
+ if (!ccHintStr.isEmpty()) {
+ TextView ccHint = (TextView) cling.findViewById(R.id.custom_content_hint);
+ ccHint.setText(ccHintStr);
+ ccHint.setVisibility(View.VISIBLE);
+ }
}
initCling(R.id.first_run_cling, null, false, true);
} else {
@@ -4183,6 +4161,13 @@
}
}
+ protected String getFirstRunClingSearchBarHint() {
+ return "";
+ }
+ protected String getFirstRunCustomContentHint() {
+ return "";
+ }
+
public void showFirstRunWorkspaceCling() {
// Enable the clings only if they have not been dismissed before
if (isClingsEnabled() &&
diff --git a/src/com/android/launcher3/LauncherBackupAgent.java b/src/com/android/launcher3/LauncherBackupAgent.java
new file mode 100644
index 0000000..bb15ca1
--- /dev/null
+++ b/src/com/android/launcher3/LauncherBackupAgent.java
@@ -0,0 +1,655 @@
+/*
+ * Copyright (C) 2013 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 com.google.protobuf.nano.InvalidProtocolBufferNanoException;
+import com.google.protobuf.nano.MessageNano;
+
+import com.android.launcher3.LauncherSettings.ChangeLogColumns;
+import com.android.launcher3.LauncherSettings.Favorites;
+import com.android.launcher3.LauncherSettings.WorkspaceScreens;
+import com.android.launcher3.backup.BackupProtos;
+import com.android.launcher3.backup.BackupProtos.CheckedMessage;
+import com.android.launcher3.backup.BackupProtos.Favorite;
+import com.android.launcher3.backup.BackupProtos.Journal;
+import com.android.launcher3.backup.BackupProtos.Key;
+import com.android.launcher3.backup.BackupProtos.Screen;
+
+import android.app.backup.BackupAgent;
+import android.app.backup.BackupDataInput;
+import android.app.backup.BackupDataOutput;
+import android.app.backup.BackupManager;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.database.Cursor;
+import android.os.ParcelFileDescriptor;
+import android.provider.BaseColumns;
+import android.text.TextUtils;
+import android.util.Base64;
+import android.util.Log;
+
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.zip.CRC32;
+
+/**
+ * Persist the launcher home state across calamities.
+ */
+public class LauncherBackupAgent extends BackupAgent {
+
+ private static final String TAG = "LauncherBackupAgent";
+ private static final boolean DEBUG = false;
+
+ private static final int MAX_JOURNAL_SIZE = 1000000;
+
+ private static BackupManager sBackupManager;
+
+ private static final String[] FAVORITE_PROJECTION = {
+ Favorites._ID, // 0
+ Favorites.APPWIDGET_ID, // 1
+ Favorites.APPWIDGET_PROVIDER, // 2
+ Favorites.CELLX, // 3
+ Favorites.CELLY, // 4
+ Favorites.CONTAINER, // 5
+ Favorites.ICON, // 6
+ Favorites.ICON_PACKAGE, // 7
+ Favorites.ICON_RESOURCE, // 8
+ Favorites.ICON_TYPE, // 9
+ Favorites.ITEM_TYPE, // 10
+ Favorites.INTENT, // 11
+ Favorites.SCREEN, // 12
+ Favorites.SPANX, // 13
+ Favorites.SPANY, // 14
+ Favorites.TITLE, // 15
+ };
+
+ private static final int ID_INDEX = 0;
+ private static final int APPWIDGET_ID_INDEX = 1;
+ private static final int APPWIDGET_PROVIDER_INDEX = 2;
+ private static final int CELLX_INDEX = 3;
+ private static final int CELLY_INDEX = 4;
+ private static final int CONTAINER_INDEX = 5;
+ private static final int ICON_INDEX = 6;
+ private static final int ICON_PACKAGE_INDEX = 7;
+ private static final int ICON_RESOURCE_INDEX = 8;
+ private static final int ICON_TYPE_INDEX = 9;
+ private static final int ITEM_TYPE_INDEX = 10;
+ private static final int INTENT_INDEX = 11;
+ private static final int SCREEN_INDEX = 12;
+ private static final int SPANX_INDEX = 13 ;
+ private static final int SPANY_INDEX = 14;
+ private static final int TITLE_INDEX = 15;
+
+ private static final String[] SCREEN_PROJECTION = {
+ WorkspaceScreens._ID, // 0
+ WorkspaceScreens.SCREEN_RANK // 1
+ };
+
+ private static final int SCREEN_RANK_INDEX = 1;
+
+ private static final String[] ID_ONLY_PROJECTION = {
+ BaseColumns._ID
+ };
+
+
+ /**
+ * Notify the backup manager that out database is dirty.
+ *
+ * <P>This does not force an immediate backup.
+ *
+ * @param context application context
+ */
+ public static void dataChanged(Context context) {
+ if (sBackupManager == null) {
+ sBackupManager = new BackupManager(context);
+ }
+ sBackupManager.dataChanged();
+ }
+
+ /**
+ * Back up launcher data so we can restore the user's state on a new device.
+ *
+ * <P>The journal is a timestamp and a list of keys that were saved as of that time.
+ *
+ * <P>Keys may come back in any order, so each key/value is one complete row of the database.
+ *
+ * @param oldState notes from the last backup
+ * @param data incremental key/value pairs to persist off-device
+ * @param newState notes for the next backup
+ * @throws IOException
+ */
+ @Override
+ public void onBackup(ParcelFileDescriptor oldState, BackupDataOutput data,
+ ParcelFileDescriptor newState)
+ throws IOException {
+ Log.v(TAG, "onBackup");
+
+ Journal in = readJournal(oldState);
+ Journal out = new Journal();
+
+ long lastBackupTime = in.t;
+ out.t = System.currentTimeMillis();
+ out.rows = 0;
+ out.bytes = 0;
+
+ Log.v(TAG, "lastBackupTime=" + lastBackupTime);
+
+ ArrayList<Key> keys = new ArrayList<Key>();
+ backupFavorites(in, data, out, keys);
+ backupScreens(in, data, out, keys);
+
+ out.key = keys.toArray(BackupProtos.Key.EMPTY_ARRAY);
+ writeJournal(newState, out);
+ Log.v(TAG, "onBackup: wrote " + out.bytes + "b in " + out.rows + " rows.");
+
+ Log.v(TAG, "onBackup: finished");
+ }
+
+ /**
+ * Restore home screen from the restored data stream.
+ *
+ * <P>Keys may arrive in any order.
+ *
+ * @param data the key/value pairs from the server
+ * @param versionCode the version of the app that generated the data
+ * @param newState notes for the next backup
+ * @throws IOException
+ */
+ @Override
+ public void onRestore(BackupDataInput data, int versionCode, ParcelFileDescriptor newState)
+ throws IOException {
+ Log.v(TAG, "onRestore");
+ int numRows = 0;
+ Journal out = new Journal();
+
+ ArrayList<Key> keys = new ArrayList<Key>();
+ byte[] buffer = new byte[512];
+ while (data.readNextHeader()) {
+ numRows++;
+ String backupKey = data.getKey();
+ int dataSize = data.getDataSize();
+ if (buffer.length < dataSize) {
+ buffer = new byte[dataSize];
+ }
+ Key key = null;
+ int bytesRead = data.readEntityData(buffer, 0, dataSize);
+ if (DEBUG) {
+ Log.d(TAG, "read " + bytesRead + " of " + dataSize + " available");
+ }
+ try {
+ key = backupKeyToKey(backupKey);
+ switch (key.type) {
+ case Key.FAVORITE:
+ restoreFavorite(key, buffer, dataSize, keys);
+ break;
+
+ case Key.SCREEN:
+ restoreScreen(key, buffer, dataSize, keys);
+ break;
+
+ default:
+ Log.w(TAG, "unknown restore entity type: " + key.type);
+ break;
+ }
+ } catch (KeyParsingException e) {
+ Log.w(TAG, "ignoring unparsable backup key: " + backupKey);
+ }
+ }
+
+ // clear the output journal time, to force a full backup to
+ // will catch any changes the restore process might have made
+ out.t = 0;
+ out.key = keys.toArray(BackupProtos.Key.EMPTY_ARRAY);
+ writeJournal(newState, out);
+ Log.v(TAG, "onRestore: read " + numRows + " rows");
+ }
+
+ /**
+ * Write all modified favorites to the data stream.
+ *
+ *
+ * @param in notes from last backup
+ * @param data output stream for key/value pairs
+ * @param out notes about this backup
+ * @param keys keys to mark as clean in the notes for next backup
+ * @throws IOException
+ */
+ private void backupFavorites(Journal in, BackupDataOutput data, Journal out,
+ ArrayList<Key> keys)
+ throws IOException {
+ // read the old ID set
+ Set<String> savedIds = new HashSet<String>();
+ for(int i = 0; i < in.key.length; i++) {
+ Key key = in.key[i];
+ if (key.type == Key.FAVORITE) {
+ savedIds.add(keyToBackupKey(key));
+ }
+ }
+ if (DEBUG) Log.d(TAG, "favorite savedIds.size()=" + savedIds.size());
+
+ // persist things that have changed since the last backup
+ ContentResolver cr = getContentResolver();
+ String where = ChangeLogColumns.MODIFIED + " > ?";
+ String[] args = {Long.toString(in.t)};
+ String updateOrder = ChangeLogColumns.MODIFIED;
+ Cursor updated = cr.query(Favorites.CONTENT_URI, FAVORITE_PROJECTION,
+ where, args, updateOrder);
+ if (DEBUG) Log.d(TAG, "favorite updated.getCount()=" + updated.getCount());
+ try {
+ updated.moveToPosition(-1);
+ while(updated.moveToNext()) {
+ final long id = updated.getLong(ID_INDEX);
+ Key key = getKey(Key.FAVORITE, id);
+ byte[] blob = packFavorite(updated);
+ String backupKey = keyToBackupKey(key);
+ data.writeEntityHeader(backupKey, blob.length);
+ data.writeEntityData(blob, blob.length);
+ out.rows++;
+ out.bytes += blob.length;
+ Log.v(TAG, "saving favorite " + backupKey + ": " + id + "/" + blob.length);
+ if(DEBUG) Log.d(TAG, "wrote " +
+ Base64.encodeToString(blob, 0, blob.length, Base64.NO_WRAP));
+ // remember that is was a new column, so we don't delete it.
+ savedIds.add(backupKey);
+ }
+ } finally {
+ updated.close();
+ }
+ if (DEBUG) Log.d(TAG, "favorite savedIds.size()=" + savedIds.size());
+
+ // build the current ID set
+ String idOrder = BaseColumns._ID;
+ Cursor idCursor = cr.query(Favorites.CONTENT_URI, ID_ONLY_PROJECTION,
+ null, null, idOrder);
+ Set<String> currentIds = new HashSet<String>(idCursor.getCount());
+ try {
+ idCursor.moveToPosition(-1);
+ while(idCursor.moveToNext()) {
+ Key key = getKey(Key.FAVORITE, idCursor.getLong(ID_INDEX));
+ currentIds.add(keyToBackupKey(key));
+ // save the IDs for next time
+ keys.add(key);
+ }
+ } finally {
+ idCursor.close();
+ }
+ if (DEBUG) Log.d(TAG, "favorite currentIds.size()=" + currentIds.size());
+
+ // these IDs must have been deleted
+ savedIds.removeAll(currentIds);
+ for (String deleted : savedIds) {
+ Log.v(TAG, "dropping favorite " + deleted);
+ data.writeEntityHeader(deleted, -1);
+ out.rows++;
+ }
+ }
+
+ /**
+ * Read a favorite from the stream.
+ *
+ * <P>Keys arrive in any order, so screens and containers may not exist yet.
+ *
+ * @param key identifier for the row
+ * @param buffer the serialized proto from the stream, may be larger than dataSize
+ * @param dataSize the size of the proto from the stream
+ * @param keys keys to mark as clean in the notes for next backup
+ */
+ private void restoreFavorite(Key key, byte[] buffer, int dataSize, ArrayList<Key> keys) {
+ Log.v(TAG, "unpacking favorite " + key.id + " (" + dataSize + " bytes)");
+ if (DEBUG) Log.d(TAG, "read (" + buffer.length + "): " +
+ Base64.encodeToString(buffer, 0, dataSize, Base64.NO_WRAP));
+
+ try {
+ Favorite favorite = unpackFavorite(buffer, 0, dataSize);
+ if (DEBUG) Log.d(TAG, "unpacked " + favorite.itemType);
+ } catch (InvalidProtocolBufferNanoException e) {
+ Log.w(TAG, "failed to decode proto", e);
+ }
+ }
+
+ /**
+ * Write all modified screens to the data stream.
+ *
+ *
+ * @param in notes from last backup
+ * @param data output stream for key/value pairs
+ * @param out notes about this backup
+ * @param keys keys to mark as clean in the notes for next backup @throws IOException
+ */
+ private void backupScreens(Journal in, BackupDataOutput data, Journal out,
+ ArrayList<Key> keys)
+ throws IOException {
+ // read the old ID set
+ Set<String> savedIds = new HashSet<String>();
+ for(int i = 0; i < in.key.length; i++) {
+ Key key = in.key[i];
+ if (key.type == Key.SCREEN) {
+ savedIds.add(keyToBackupKey(key));
+ }
+ }
+ if (DEBUG) Log.d(TAG, "screens savedIds.size()=" + savedIds.size());
+
+ // persist things that have changed since the last backup
+ ContentResolver cr = getContentResolver();
+ String where = ChangeLogColumns.MODIFIED + " > ?";
+ String[] args = {Long.toString(in.t)};
+ String updateOrder = ChangeLogColumns.MODIFIED;
+ Cursor updated = cr.query(WorkspaceScreens.CONTENT_URI, SCREEN_PROJECTION,
+ where, args, updateOrder);
+ updated.moveToPosition(-1);
+ if (DEBUG) Log.d(TAG, "screens updated.getCount()=" + updated.getCount());
+ try {
+ while(updated.moveToNext()) {
+ final long id = updated.getLong(ID_INDEX);
+ Key key = getKey(Key.SCREEN, id);
+ byte[] blob = packScreen(updated);
+ String backupKey = keyToBackupKey(key);
+ data.writeEntityHeader(backupKey, blob.length);
+ data.writeEntityData(blob, blob.length);
+ out.rows++;
+ out.bytes += blob.length;
+ Log.v(TAG, "saving screen " + backupKey + ": " + id + "/" + blob.length);
+ if(DEBUG) Log.d(TAG, "wrote " +
+ Base64.encodeToString(blob, 0, blob.length, Base64.NO_WRAP));
+ // remember that is was a new column, so we don't delete it.
+ savedIds.add(backupKey);
+ }
+ } finally {
+ updated.close();
+ }
+ if (DEBUG) Log.d(TAG, "screen savedIds.size()=" + savedIds.size());
+
+ // build the current ID set
+ String idOrder = BaseColumns._ID;
+ Cursor idCursor = cr.query(WorkspaceScreens.CONTENT_URI, ID_ONLY_PROJECTION,
+ null, null, idOrder);
+ idCursor.moveToPosition(-1);
+ Set<String> currentIds = new HashSet<String>(idCursor.getCount());
+ try {
+ while(idCursor.moveToNext()) {
+ Key key = getKey(Key.SCREEN, idCursor.getLong(ID_INDEX));
+ currentIds.add(keyToBackupKey(key));
+ // save the IDs for next time
+ keys.add(key);
+ }
+ } finally {
+ idCursor.close();
+ }
+ if (DEBUG) Log.d(TAG, "screen currentIds.size()=" + currentIds.size());
+
+ // these IDs must have been deleted
+ savedIds.removeAll(currentIds);
+ for(String deleted: savedIds) {
+ Log.v(TAG, "dropping screen " + deleted);
+ data.writeEntityHeader(deleted, -1);
+ out.rows++;
+ }
+ }
+
+ /**
+ * Read a screen from the stream.
+ *
+ * <P>Keys arrive in any order, so children of this screen may already exist.
+ *
+ * @param key identifier for the row
+ * @param buffer the serialized proto from the stream, may be larger than dataSize
+ * @param dataSize the size of the proto from the stream
+ * @param keys keys to mark as clean in the notes for next backup
+ */
+ private void restoreScreen(Key key, byte[] buffer, int dataSize, ArrayList<Key> keys) {
+ Log.v(TAG, "unpacking screen " + key.id);
+ if (DEBUG) Log.d(TAG, "read (" + buffer.length + "): " +
+ Base64.encodeToString(buffer, 0, dataSize, Base64.NO_WRAP));
+ try {
+ Screen screen = unpackScreen(buffer, 0, dataSize);
+ if (DEBUG) Log.d(TAG, "unpacked " + screen.rank);
+ } catch (InvalidProtocolBufferNanoException e) {
+ Log.w(TAG, "failed to decode proto", e);
+ }
+ }
+
+ /** create a new key object.
+ *
+ * <P> Keys contain their own checksum instead of using
+ * the heavy-weight CheckedMessage wrapper.
+ */
+ private Key getKey(int type, long id) {
+ Key key = new Key();
+ key.type = type;
+ key.id = id;
+ key.checksum = checkKey(key);
+ return key;
+ }
+
+ /** keys need to be strings, serialize and encode. */
+ private String keyToBackupKey(Key key) {
+ return Base64.encodeToString(Key.toByteArray(key), Base64.NO_WRAP | Base64.NO_PADDING);
+ }
+
+ /** keys need to be strings, decode and parse. */
+ private Key backupKeyToKey(String backupKey) throws KeyParsingException {
+ try {
+ Key key = Key.parseFrom(Base64.decode(backupKey, Base64.DEFAULT));
+ if (key.checksum != checkKey(key)) {
+ key = null;
+ throw new KeyParsingException("invalid key read from stream" + backupKey);
+ }
+ return key;
+ } catch (InvalidProtocolBufferNanoException e) {
+ throw new KeyParsingException(e);
+ } catch (IllegalArgumentException e) {
+ throw new KeyParsingException(e);
+ }
+ }
+
+ /** Compute the checksum over the important bits of a key. */
+ private long checkKey(Key key) {
+ CRC32 checksum = new CRC32();
+ checksum.update(key.type);
+ checksum.update((int) (key.id & 0xffff));
+ checksum.update((int) ((key.id >> 32) & 0xffff));
+ if (!TextUtils.isEmpty(key.name)) {
+ checksum.update(key.name.getBytes());
+ }
+ return checksum.getValue();
+ }
+
+ /** Serialize a Favorite for persistence, including a checksum wrapper. */
+ private byte[] packFavorite(Cursor c) {
+ Favorite favorite = new Favorite();
+ favorite.id = c.getLong(ID_INDEX);
+ favorite.screen = c.getInt(SCREEN_INDEX);
+ favorite.container = c.getInt(CONTAINER_INDEX);
+ favorite.cellX = c.getInt(CELLX_INDEX);
+ favorite.cellY = c.getInt(CELLY_INDEX);
+ favorite.spanX = c.getInt(SPANX_INDEX);
+ favorite.spanY = c.getInt(SPANY_INDEX);
+ favorite.iconType = c.getInt(ICON_TYPE_INDEX);
+ if (favorite.iconType == Favorites.ICON_TYPE_RESOURCE) {
+ String iconPackage = c.getString(ICON_PACKAGE_INDEX);
+ if (!TextUtils.isEmpty(iconPackage)) {
+ favorite.iconPackage = iconPackage;
+ }
+ String iconResource = c.getString(ICON_RESOURCE_INDEX);
+ if (!TextUtils.isEmpty(iconResource)) {
+ favorite.iconResource = iconResource;
+ }
+ }
+ if (favorite.iconType == Favorites.ICON_TYPE_BITMAP) {
+ byte[] blob = c.getBlob(ICON_INDEX);
+ if (blob != null && blob.length > 0) {
+ favorite.icon = blob;
+ }
+ }
+ String title = c.getString(TITLE_INDEX);
+ if (!TextUtils.isEmpty(title)) {
+ favorite.title = title;
+ }
+ String intent = c.getString(INTENT_INDEX);
+ if (!TextUtils.isEmpty(intent)) {
+ favorite.intent = intent;
+ }
+ favorite.itemType = c.getInt(ITEM_TYPE_INDEX);
+ if (favorite.itemType == Favorites.ITEM_TYPE_APPWIDGET) {
+ favorite.appWidgetId = c.getInt(APPWIDGET_ID_INDEX);
+ String appWidgetProvider = c.getString(APPWIDGET_PROVIDER_INDEX);
+ if (!TextUtils.isEmpty(appWidgetProvider)) {
+ favorite.appWidgetProvider = appWidgetProvider;
+ }
+ }
+
+ return writeCheckedBytes(favorite);
+ }
+
+ /** Deserialize a Favorite from persistence, after verifying checksum wrapper. */
+ private Favorite unpackFavorite(byte[] buffer, int offset, int dataSize)
+ throws InvalidProtocolBufferNanoException {
+ Favorite favorite = new Favorite();
+ MessageNano.mergeFrom(favorite, readCheckedBytes(buffer, offset, dataSize));
+ return favorite;
+ }
+
+ /** Serialize a Screen for persistence, including a checksum wrapper. */
+ private byte[] packScreen(Cursor c) {
+ Screen screen = new Screen();
+ screen.id = c.getLong(ID_INDEX);
+ screen.rank = c.getInt(SCREEN_RANK_INDEX);
+
+ return writeCheckedBytes(screen);
+ }
+
+ /** Deserialize a Screen from persistence, after verifying checksum wrapper. */
+ private Screen unpackScreen(byte[] buffer, int offset, int dataSize)
+ throws InvalidProtocolBufferNanoException {
+ Screen screen = new Screen();
+ MessageNano.mergeFrom(screen, readCheckedBytes(buffer, offset, dataSize));
+ return screen;
+ }
+
+ /**
+ * Read the old journal from the input file.
+ *
+ * In the event of any error, just pretend we didn't have a journal,
+ * in that case, do a full backup.
+ *
+ * @param oldState the read-0only file descriptor pointing to the old journal
+ * @return a Journal protocol bugffer
+ */
+ private Journal readJournal(ParcelFileDescriptor oldState) {
+ int fileSize = (int) oldState.getStatSize();
+ int remaining = fileSize;
+ byte[] buffer = null;
+ Journal journal = new Journal();
+ if (remaining < MAX_JOURNAL_SIZE) {
+ FileInputStream inStream = new FileInputStream(oldState.getFileDescriptor());
+ int offset = 0;
+
+ buffer = new byte[remaining];
+ while (remaining > 0) {
+ int bytesRead = 0;
+ try {
+ bytesRead = inStream.read(buffer, offset, remaining);
+ } catch (IOException e) {
+ Log.w(TAG, "failed to read the journal", e);
+ buffer = null;
+ remaining = 0;
+ }
+ if (bytesRead > 0) {
+ remaining -= bytesRead;
+ } else {
+ // act like there is not journal
+ Log.w(TAG, "failed to read the journal");
+ buffer = null;
+ remaining = 0;
+ }
+ }
+
+ if (buffer != null) {
+ try {
+ MessageNano.mergeFrom(journal, readCheckedBytes(buffer, 0, fileSize));
+ } catch (InvalidProtocolBufferNanoException e) {
+ Log.d(TAG, "failed to read the journal", e);
+ journal.clear();
+ }
+ }
+
+ try {
+ inStream.close();
+ } catch (IOException e) {
+ Log.d(TAG, "failed to close the journal", e);
+ }
+ }
+ return journal;
+ }
+
+ /**
+ * Write the new journal to the output file.
+ *
+ * In the event of any error, just pretend we didn't have a journal,
+ * in that case, do a full backup.
+
+ * @param newState the write-only file descriptor pointing to the new journal
+ * @param journal a Journal protocol buffer
+ */
+ private void writeJournal(ParcelFileDescriptor newState, Journal journal) {
+ FileOutputStream outStream = null;
+ try {
+ outStream = new FileOutputStream(newState.getFileDescriptor());
+ outStream.write(writeCheckedBytes(journal));
+ outStream.close();
+ } catch (IOException e) {
+ Log.d(TAG, "failed to write backup journal", e);
+ }
+ }
+
+ /** Wrap a proto in a CheckedMessage and compute the checksum. */
+ private byte[] writeCheckedBytes(MessageNano proto) {
+ CheckedMessage wrapper = new CheckedMessage();
+ wrapper.payload = MessageNano.toByteArray(proto);
+ CRC32 checksum = new CRC32();
+ checksum.update(wrapper.payload);
+ wrapper.checksum = checksum.getValue();
+ return MessageNano.toByteArray(wrapper);
+ }
+
+ /** Unwrap a proto message from a CheckedMessage, verifying the checksum. */
+ private byte[] readCheckedBytes(byte[] buffer, int offset, int dataSize)
+ throws InvalidProtocolBufferNanoException {
+ CheckedMessage wrapper = new CheckedMessage();
+ MessageNano.mergeFrom(wrapper, buffer, offset, dataSize);
+ CRC32 checksum = new CRC32();
+ checksum.update(wrapper.payload);
+ if (wrapper.checksum != checksum.getValue()) {
+ throw new InvalidProtocolBufferNanoException("checksum does not match");
+ }
+ return wrapper.payload;
+ }
+
+ private class KeyParsingException extends Throwable {
+ private KeyParsingException(Throwable cause) {
+ super(cause);
+ }
+
+ public KeyParsingException(String reason) {
+ super(reason);
+ }
+ }
+}
diff --git a/src/com/android/launcher3/LauncherProvider.java b/src/com/android/launcher3/LauncherProvider.java
index fa61b11..471d2d2 100644
--- a/src/com/android/launcher3/LauncherProvider.java
+++ b/src/com/android/launcher3/LauncherProvider.java
@@ -49,6 +49,7 @@
import android.util.Log;
import android.util.Xml;
+import com.android.launcher3.LauncherSettings.BaseLauncherColumns;
import com.android.launcher3.LauncherSettings.Favorites;
import org.xmlpull.v1.XmlPullParser;
@@ -65,7 +66,7 @@
private static final String DATABASE_NAME = "launcher.db";
- private static final int DATABASE_VERSION = 14;
+ private static final int DATABASE_VERSION = 15;
static final String OLD_AUTHORITY = "com.android.launcher2.settings";
static final String AUTHORITY = "com.android.launcher3.settings";
@@ -146,6 +147,7 @@
SqlArguments args = new SqlArguments(uri);
SQLiteDatabase db = mOpenHelper.getWritableDatabase();
+ addModifiedTime(initialValues);
final long rowId = dbInsertAndCheck(mOpenHelper, db, args.table, null, initialValues);
if (rowId <= 0) return null;
@@ -164,6 +166,7 @@
try {
int numValues = values.length;
for (int i = 0; i < numValues; i++) {
+ addModifiedTime(values[i]);
if (dbInsertAndCheck(mOpenHelper, db, args.table, null, values[i]) < 0) {
return 0;
}
@@ -192,6 +195,7 @@
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
SqlArguments args = new SqlArguments(uri, selection, selectionArgs);
+ addModifiedTime(values);
SQLiteDatabase db = mOpenHelper.getWritableDatabase();
int count = db.update(args.table, values, args.where, args.args);
if (count > 0) sendNotify(uri);
@@ -204,6 +208,13 @@
if (notify == null || "true".equals(notify)) {
getContext().getContentResolver().notifyChange(uri, null);
}
+
+ // always notify the backup agent
+ LauncherBackupAgent.dataChanged(getContext());
+ }
+
+ private void addModifiedTime(ContentValues values) {
+ values.put(LauncherSettings.ChangeLogColumns.MODIFIED, System.currentTimeMillis());
}
public long generateNewItemId() {
@@ -343,7 +354,8 @@
"icon BLOB," +
"uri TEXT," +
"displayMode INTEGER," +
- "appWidgetProvider TEXT" +
+ "appWidgetProvider TEXT," +
+ "modified INTEGER NOT NULL DEFAULT 0" +
");");
addWorkspacesTable(db);
@@ -384,7 +396,8 @@
private void addWorkspacesTable(SQLiteDatabase db) {
db.execSQL("CREATE TABLE " + TABLE_WORKSPACE_SCREENS + " (" +
LauncherSettings.WorkspaceScreens._ID + " INTEGER," +
- LauncherSettings.WorkspaceScreens.SCREEN_RANK + " INTEGER" +
+ LauncherSettings.WorkspaceScreens.SCREEN_RANK + " INTEGER," +
+ LauncherSettings.ChangeLogColumns.MODIFIED + " INTEGER NOT NULL DEFAULT 0" +
");");
}
@@ -643,6 +656,25 @@
}
}
+
+ if (version < 15) {
+ db.beginTransaction();
+ try {
+ // Insert new column for holding update timestamp
+ db.execSQL("ALTER TABLE favorites " +
+ "ADD COLUMN modified INTEGER NOT NULL DEFAULT 0;");
+ db.execSQL("ALTER TABLE workspaceScreens " +
+ "ADD COLUMN modified INTEGER NOT NULL DEFAULT 0;");
+ db.setTransactionSuccessful();
+ version = 15;
+ } catch (SQLException ex) {
+ // Old version remains, which means we wipe old data
+ Log.e(TAG, ex.getMessage(), ex);
+ } finally {
+ db.endTransaction();
+ }
+ }
+
if (version != DATABASE_VERSION) {
Log.w(TAG, "Destroying all old data.");
db.execSQL("DROP TABLE IF EXISTS " + TABLE_FAVORITES);
diff --git a/src/com/android/launcher3/LauncherSettings.java b/src/com/android/launcher3/LauncherSettings.java
index ada09e9..988e5ef 100644
--- a/src/com/android/launcher3/LauncherSettings.java
+++ b/src/com/android/launcher3/LauncherSettings.java
@@ -23,7 +23,16 @@
* Settings related utilities.
*/
class LauncherSettings {
- static interface BaseLauncherColumns extends BaseColumns {
+ /** Columns required on table staht will be subject to backup and restore. */
+ static interface ChangeLogColumns extends BaseColumns {
+ /**
+ * The time of the last update to this row.
+ * <P>Type: INTEGER</P>
+ */
+ static final String MODIFIED = "modified";
+ }
+
+ static interface BaseLauncherColumns extends ChangeLogColumns {
/**
* Descriptive name of the gesture that can be displayed to the user.
* <P>Type: TEXT</P>
@@ -95,7 +104,7 @@
*
* Tracks the order of workspace screens.
*/
- static final class WorkspaceScreens implements BaseColumns {
+ static final class WorkspaceScreens implements ChangeLogColumns {
/**
* The content:// style URL for this table
*/
diff --git a/src/com/android/launcher3/LiveWallpaperListAdapter.java b/src/com/android/launcher3/LiveWallpaperListAdapter.java
index a6facaa..9d0f48b 100644
--- a/src/com/android/launcher3/LiveWallpaperListAdapter.java
+++ b/src/com/android/launcher3/LiveWallpaperListAdapter.java
@@ -17,12 +17,10 @@
package com.android.launcher3;
import android.app.WallpaperInfo;
+import android.app.WallpaperManager;
import android.content.Context;
import android.content.Intent;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
-import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.ResolveInfo;
import android.graphics.drawable.Drawable;
import android.os.AsyncTask;
@@ -52,7 +50,7 @@
private final LayoutInflater mInflater;
private final PackageManager mPackageManager;
- private List<LiveWallpaperInfo> mWallpapers;
+ private List<LiveWallpaperTile> mWallpapers;
@SuppressWarnings("unchecked")
public LiveWallpaperListAdapter(Context context) {
@@ -63,20 +61,11 @@
new Intent(WallpaperService.SERVICE_INTERFACE),
PackageManager.GET_META_DATA);
- mWallpapers = generatePlaceholderViews(list.size());
+ mWallpapers = new ArrayList<LiveWallpaperTile>();
new LiveWallpaperEnumerator(context).execute(list);
}
- private List<LiveWallpaperInfo> generatePlaceholderViews(int amount) {
- ArrayList<LiveWallpaperInfo> list = new ArrayList<LiveWallpaperInfo>(amount);
- for (int i = 0; i < amount; i++) {
- LiveWallpaperInfo info = new LiveWallpaperInfo();
- list.add(info);
- }
- return list;
- }
-
public int getCount() {
if (mWallpapers == null) {
return 0;
@@ -84,7 +73,7 @@
return mWallpapers.size();
}
- public Object getItem(int position) {
+ public LiveWallpaperTile getItem(int position) {
return mWallpapers.get(position);
}
@@ -103,31 +92,42 @@
WallpaperPickerActivity.setWallpaperItemPaddingToZero((FrameLayout) view);
- LiveWallpaperInfo wallpaperInfo = mWallpapers.get(position);
+ LiveWallpaperTile wallpaperInfo = mWallpapers.get(position);
ImageView image = (ImageView) view.findViewById(R.id.wallpaper_image);
ImageView icon = (ImageView) view.findViewById(R.id.wallpaper_icon);
- if (wallpaperInfo.thumbnail != null) {
- image.setImageDrawable(wallpaperInfo.thumbnail);
+ if (wallpaperInfo.mThumbnail != null) {
+ image.setImageDrawable(wallpaperInfo.mThumbnail);
icon.setVisibility(View.GONE);
} else {
- icon.setImageDrawable(wallpaperInfo.info.loadIcon(mPackageManager));
+ icon.setImageDrawable(wallpaperInfo.mInfo.loadIcon(mPackageManager));
icon.setVisibility(View.VISIBLE);
}
TextView label = (TextView) view.findViewById(R.id.wallpaper_item_label);
- label.setText(wallpaperInfo.info.loadLabel(mPackageManager));
+ label.setText(wallpaperInfo.mInfo.loadLabel(mPackageManager));
return view;
}
- public class LiveWallpaperInfo {
- public Drawable thumbnail;
- public WallpaperInfo info;
- public Intent intent;
+ public static class LiveWallpaperTile extends WallpaperPickerActivity.WallpaperTileInfo {
+ private Drawable mThumbnail;
+ private WallpaperInfo mInfo;
+ public LiveWallpaperTile(Drawable thumbnail, WallpaperInfo info, Intent intent) {
+ mThumbnail = thumbnail;
+ mInfo = info;
+ }
+ public void onClick(WallpaperPickerActivity a) {
+ Intent preview = new Intent(WallpaperManager.ACTION_CHANGE_LIVE_WALLPAPER);
+ preview.putExtra(WallpaperManager.EXTRA_LIVE_WALLPAPER_COMPONENT,
+ mInfo.getComponent());
+ a.onLiveWallpaperPickerLaunch();
+ Utilities.startActivityForResultSafely(
+ a, preview, WallpaperPickerActivity.PICK_LIVE_WALLPAPER);
+ }
}
private class LiveWallpaperEnumerator extends
- AsyncTask<List<ResolveInfo>, LiveWallpaperInfo, Void> {
+ AsyncTask<List<ResolveInfo>, LiveWallpaperTile, Void> {
private Context mContext;
private int mWallpaperPosition;
@@ -168,12 +168,12 @@
continue;
}
- LiveWallpaperInfo wallpaper = new LiveWallpaperInfo();
- wallpaper.intent = new Intent(WallpaperService.SERVICE_INTERFACE);
- wallpaper.intent.setClassName(info.getPackageName(), info.getServiceName());
- wallpaper.info = info;
Drawable thumb = info.loadThumbnail(packageManager);
+ Intent launchIntent = new Intent(WallpaperService.SERVICE_INTERFACE);
+ launchIntent.setClassName(info.getPackageName(), info.getServiceName());
+ LiveWallpaperTile wallpaper = new LiveWallpaperTile(thumb, info, launchIntent);
+
// TODO: generate a default thumb
/*
final Resources res = mContext.getResources();
@@ -211,7 +211,6 @@
thumb = new BitmapDrawable(res, thumbnail);
}*/
- wallpaper.thumbnail = thumb;
publishProgress(wallpaper);
}
@@ -219,9 +218,9 @@
}
@Override
- protected void onProgressUpdate(LiveWallpaperInfo...infos) {
- for (LiveWallpaperInfo info : infos) {
- info.thumbnail.setDither(true);
+ protected void onProgressUpdate(LiveWallpaperTile...infos) {
+ for (LiveWallpaperTile info : infos) {
+ info.mThumbnail.setDither(true);
if (mWallpaperPosition < mWallpapers.size()) {
mWallpapers.set(mWallpaperPosition, info);
} else {
diff --git a/src/com/android/launcher3/PagedViewIcon.java b/src/com/android/launcher3/PagedViewIcon.java
index fa9ec5a..c6d5e49 100644
--- a/src/com/android/launcher3/PagedViewIcon.java
+++ b/src/com/android/launcher3/PagedViewIcon.java
@@ -18,6 +18,9 @@
import android.content.Context;
import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Region;
+import android.graphics.Region.Op;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.widget.TextView;
@@ -99,4 +102,27 @@
setAlpha(1f);
}
}
+
+ @Override
+ public void draw(Canvas canvas) {
+ // If text is transparent, don't draw any shadow
+ if (getCurrentTextColor() == getResources().getColor(android.R.color.transparent)) {
+ getPaint().clearShadowLayer();
+ super.draw(canvas);
+ return;
+ }
+
+ // We enhance the shadow by drawing the shadow twice
+ getPaint().setShadowLayer(BubbleTextView.SHADOW_LARGE_RADIUS, 0.0f,
+ BubbleTextView.SHADOW_Y_OFFSET, BubbleTextView.SHADOW_LARGE_COLOUR);
+ super.draw(canvas);
+ canvas.save(Canvas.CLIP_SAVE_FLAG);
+ canvas.clipRect(getScrollX(), getScrollY() + getExtendedPaddingTop(),
+ getScrollX() + getWidth(),
+ getScrollY() + getHeight(), Region.Op.INTERSECT);
+ getPaint().setShadowLayer(BubbleTextView.SHADOW_SMALL_RADIUS, 0.0f, 0.0f,
+ BubbleTextView.SHADOW_SMALL_COLOUR);
+ super.draw(canvas);
+ canvas.restore();
+ }
}
diff --git a/src/com/android/launcher3/SavedWallpaperImages.java b/src/com/android/launcher3/SavedWallpaperImages.java
index 9766a8a..f00f62f 100644
--- a/src/com/android/launcher3/SavedWallpaperImages.java
+++ b/src/com/android/launcher3/SavedWallpaperImages.java
@@ -16,6 +16,7 @@
package com.android.launcher3;
+import android.app.Activity;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
@@ -27,6 +28,13 @@
import android.graphics.drawable.Drawable;
import android.util.Log;
import android.util.Pair;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.BaseAdapter;
+import android.widget.ListAdapter;
+
+import com.android.photos.BitmapRegionTileSource;
import java.io.ByteArrayOutputStream;
import java.io.File;
@@ -35,21 +43,49 @@
import java.util.ArrayList;
-public class SavedWallpaperImages {
+public class SavedWallpaperImages extends BaseAdapter implements ListAdapter {
private static String TAG = "Launcher3.SavedWallpaperImages";
private ImageDb mDb;
- ArrayList<Integer> mIds;
- ArrayList<Drawable> mThumbs;
+ ArrayList<SavedWallpaperTile> mImages;
Context mContext;
+ LayoutInflater mLayoutInflater;
- public SavedWallpaperImages(Context context) {
+ public static class SavedWallpaperTile extends WallpaperPickerActivity.WallpaperTileInfo {
+ private int mDbId;
+ private Drawable mThumb;
+ public SavedWallpaperTile(int dbId, Drawable thumb) {
+ mDbId = dbId;
+ mThumb = thumb;
+ }
+ public void onClick(WallpaperPickerActivity a) {
+ String imageFilename = a.getSavedImages().getImageFilename(mDbId);
+ File file = new File(a.getFilesDir(), imageFilename);
+ CropView v = a.getCropView();
+ v.setTileSource(new BitmapRegionTileSource(a, file.getAbsolutePath(), 1024, 0), null);
+ v.moveToLeft();
+ v.setTouchEnabled(false);
+ }
+ public void onSave(WallpaperPickerActivity a) {
+ boolean finishActivityWhenDone = true;
+ String imageFilename = a.getSavedImages().getImageFilename(mDbId);
+ a.setWallpaper(imageFilename, finishActivityWhenDone);
+ }
+ public void onDelete(WallpaperPickerActivity a) {
+ a.getSavedImages().deleteImage(mDbId);
+ }
+ public boolean isSelectable() {
+ return true;
+ }
+ }
+
+ public SavedWallpaperImages(Activity context) {
mDb = new ImageDb(context);
mContext = context;
+ mLayoutInflater = context.getLayoutInflater();
}
public void loadThumbnailsAndImageIdList() {
- mIds = new ArrayList<Integer>();
- mThumbs = new ArrayList<Drawable>();
+ mImages = new ArrayList<SavedWallpaperTile>();
SQLiteDatabase db = mDb.getReadableDatabase();
Cursor result = db.query(ImageDb.TABLE_NAME,
new String[] { ImageDb.COLUMN_ID,
@@ -66,19 +102,31 @@
File file = new File(mContext.getFilesDir(), filename);
Bitmap thumb = BitmapFactory.decodeFile(file.getAbsolutePath());
if (thumb != null) {
- mIds.add(result.getInt(0));
- mThumbs.add(new BitmapDrawable(thumb));
+ mImages.add(new SavedWallpaperTile(result.getInt(0), new BitmapDrawable(thumb)));
}
}
result.close();
}
- public ArrayList<Drawable> getThumbnails() {
- return mThumbs;
+ public int getCount() {
+ return mImages.size();
}
- public ArrayList<Integer> getImageIds() {
- return mIds;
+ public SavedWallpaperTile getItem(int position) {
+ return mImages.get(position);
+ }
+
+ public long getItemId(int position) {
+ return position;
+ }
+
+ public View getView(int position, View convertView, ViewGroup parent) {
+ Drawable thumbDrawable = mImages.get(position).mThumb;
+ if (thumbDrawable == null) {
+ Log.e(TAG, "Error decoding thumbnail for wallpaper #" + position);
+ }
+ return WallpaperPickerActivity.createImageTileView(
+ mLayoutInflater, position, convertView, parent, thumbDrawable);
}
public String getImageFilename(int id) {
diff --git a/src/com/android/launcher3/ThirdPartyWallpaperPickerListAdapter.java b/src/com/android/launcher3/ThirdPartyWallpaperPickerListAdapter.java
index 9fd0d0a..ab2f5d7 100644
--- a/src/com/android/launcher3/ThirdPartyWallpaperPickerListAdapter.java
+++ b/src/com/android/launcher3/ThirdPartyWallpaperPickerListAdapter.java
@@ -41,6 +41,21 @@
private List<ResolveInfo> mThirdPartyWallpaperPickers = new ArrayList<ResolveInfo>();
+ public static class ThirdPartyWallpaperTile extends WallpaperPickerActivity.WallpaperTileInfo {
+ private ResolveInfo mResolveInfo;
+ public ThirdPartyWallpaperTile(ResolveInfo resolveInfo) {
+ mResolveInfo = resolveInfo;
+ }
+ public void onClick(WallpaperPickerActivity a) {
+ final ComponentName itemComponentName = new ComponentName(
+ mResolveInfo.activityInfo.packageName, mResolveInfo.activityInfo.name);
+ Intent launchIntent = new Intent(Intent.ACTION_SET_WALLPAPER);
+ launchIntent.setComponent(itemComponentName);
+ Utilities.startActivityForResultSafely(
+ a, launchIntent, WallpaperPickerActivity.PICK_WALLPAPER_THIRD_PARTY_ACTIVITY);
+ }
+ }
+
public ThirdPartyWallpaperPickerListAdapter(Context context) {
mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
mPackageManager = context.getPackageManager();
@@ -88,7 +103,7 @@
return mThirdPartyWallpaperPickers.size();
}
- public Object getItem(int position) {
+ public ResolveInfo getItem(int position) {
return mThirdPartyWallpaperPickers.get(position);
}
diff --git a/src/com/android/launcher3/WallpaperCropActivity.java b/src/com/android/launcher3/WallpaperCropActivity.java
index f359480..bc8df6c 100644
--- a/src/com/android/launcher3/WallpaperCropActivity.java
+++ b/src/com/android/launcher3/WallpaperCropActivity.java
@@ -162,7 +162,6 @@
}
protected void setWallpaper(String filePath, final boolean finishActivityWhenDone) {
-
BitmapCropTask cropTask = new BitmapCropTask(this,
filePath, null, 0, 0, true, false, null);
final Point bounds = cropTask.getImageBounds();
@@ -200,7 +199,7 @@
}
}
};
- BitmapCropTask cropTask = new BitmapCropTask(res, resId,
+ BitmapCropTask cropTask = new BitmapCropTask(this, res, resId,
crop, outSize.x, outSize.y,
true, false, onEndCrop);
cropTask.execute();
@@ -287,7 +286,7 @@
}
}
};
- BitmapCropTask cropTask = new BitmapCropTask(uri,
+ BitmapCropTask cropTask = new BitmapCropTask(this, uri,
cropRect, outWidth, outHeight, true, false, onEndCrop);
if (onBitmapCroppedHandler != null) {
cropTask.setOnBitmapCropped(onBitmapCroppedHandler);
@@ -299,7 +298,7 @@
public void onBitmapCropped(byte[] imageBytes);
}
- protected class BitmapCropTask extends AsyncTask<Void, Void, Boolean> {
+ protected static class BitmapCropTask extends AsyncTask<Void, Void, Boolean> {
Uri mInUri = null;
Context mContext;
String mInFilePath;
@@ -309,7 +308,6 @@
RectF mCropBounds = null;
int mOutWidth, mOutHeight;
int mRotation = 0; // for now
- protected final WallpaperManager mWPManager;
String mOutputFormat = "jpg"; // for now
boolean mSetWallpaper;
boolean mSaveCroppedBitmap;
@@ -324,7 +322,6 @@
boolean setWallpaper, boolean saveCroppedBitmap, Runnable onEndRunnable) {
mContext = c;
mInFilePath = filePath;
- mWPManager = WallpaperManager.getInstance(getApplicationContext());
init(cropBounds, outWidth, outHeight, setWallpaper, saveCroppedBitmap, onEndRunnable);
}
@@ -332,24 +329,23 @@
RectF cropBounds, int outWidth, int outHeight,
boolean setWallpaper, boolean saveCroppedBitmap, Runnable onEndRunnable) {
mInImageBytes = imageBytes;
- mWPManager = WallpaperManager.getInstance(getApplicationContext());
init(cropBounds, outWidth, outHeight, setWallpaper, saveCroppedBitmap, onEndRunnable);
}
- public BitmapCropTask(Uri inUri,
+ public BitmapCropTask(Context c, Uri inUri,
RectF cropBounds, int outWidth, int outHeight,
boolean setWallpaper, boolean saveCroppedBitmap, Runnable onEndRunnable) {
+ mContext = c;
mInUri = inUri;
- mWPManager = WallpaperManager.getInstance(getApplicationContext());
init(cropBounds, outWidth, outHeight, setWallpaper, saveCroppedBitmap, onEndRunnable);
}
- public BitmapCropTask(Resources res, int inResId,
+ public BitmapCropTask(Context c, Resources res, int inResId,
RectF cropBounds, int outWidth, int outHeight,
boolean setWallpaper, boolean saveCroppedBitmap, Runnable onEndRunnable) {
+ mContext = c;
mInResId = inResId;
mResources = res;
- mWPManager = WallpaperManager.getInstance(getApplicationContext());
init(cropBounds, outWidth, outHeight, setWallpaper, saveCroppedBitmap, onEndRunnable);
}
@@ -385,7 +381,7 @@
try {
if (mInUri != null) {
mInStream = new BufferedInputStream(
- getContentResolver().openInputStream(mInUri));
+ mContext.getContentResolver().openInputStream(mInUri));
} else if (mInFilePath != null) {
mInStream = mContext.openFileInput(mInFilePath);
} else if (mInImageBytes != null) {
@@ -426,16 +422,17 @@
regenerateInputStream();
- if (mNoCrop && mInStream != null) {
+ WallpaperManager wallpaperManager = null;
+ if (mSetWallpaper) {
+ wallpaperManager = WallpaperManager.getInstance(mContext.getApplicationContext());
+ }
+ if (mSetWallpaper && mNoCrop && mInStream != null) {
try {
- mWPManager.setStream(mInStream);
+ wallpaperManager.setStream(mInStream);
} catch (IOException e) {
Log.w(LOGTAG, "cannot write stream to wallpaper", e);
failure = true;
}
- if (mOnEndRunnable != null) {
- mOnEndRunnable.run();
- }
return !failure;
}
if (mInStream != null) {
@@ -534,26 +531,18 @@
ByteArrayOutputStream tmpOut = new ByteArrayOutputStream(2048);
if (crop.compress(cf, DEFAULT_COMPRESS_QUALITY, tmpOut)) {
// If we need to set to the wallpaper, set it
- if (mSetWallpaper && mWPManager != null) {
- if (mWPManager == null) {
- Log.w(LOGTAG, "no wallpaper manager");
- failure = true;
- } else {
- try {
- byte[] outByteArray = tmpOut.toByteArray();
- mWPManager.setStream(new ByteArrayInputStream(outByteArray));
- if (mOnBitmapCroppedHandler != null) {
- mOnBitmapCroppedHandler.onBitmapCropped(outByteArray);
- }
- } catch (IOException e) {
- Log.w(LOGTAG, "cannot write stream to wallpaper", e);
- failure = true;
+ if (mSetWallpaper && wallpaperManager != null) {
+ try {
+ byte[] outByteArray = tmpOut.toByteArray();
+ wallpaperManager.setStream(new ByteArrayInputStream(outByteArray));
+ if (mOnBitmapCroppedHandler != null) {
+ mOnBitmapCroppedHandler.onBitmapCropped(outByteArray);
}
+ } catch (IOException e) {
+ Log.w(LOGTAG, "cannot write stream to wallpaper", e);
+ failure = true;
}
}
- if (mOnEndRunnable != null) {
- mOnEndRunnable.run();
- }
} else {
Log.w(LOGTAG, "cannot compress bitmap");
failure = true;
@@ -569,8 +558,9 @@
@Override
protected void onPostExecute(Boolean result) {
- setResult(Activity.RESULT_OK);
- finish();
+ if (mOnEndRunnable != null) {
+ mOnEndRunnable.run();
+ }
}
}
diff --git a/src/com/android/launcher3/WallpaperPickerActivity.java b/src/com/android/launcher3/WallpaperPickerActivity.java
index 868b1df..5f35cde 100644
--- a/src/com/android/launcher3/WallpaperPickerActivity.java
+++ b/src/com/android/launcher3/WallpaperPickerActivity.java
@@ -21,12 +21,10 @@
import android.app.Activity;
import android.app.WallpaperInfo;
import android.app.WallpaperManager;
-import android.content.ComponentName;
+import android.content.Context;
import android.content.Intent;
-import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
-import android.content.pm.ResolveInfo;
import android.content.res.Resources;
import android.database.Cursor;
import android.database.DataSetObserver;
@@ -35,6 +33,7 @@
import android.graphics.PorterDuff;
import android.graphics.Rect;
import android.graphics.RectF;
+import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.LevelListDrawable;
import android.net.Uri;
@@ -47,7 +46,6 @@
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
-import android.view.SubMenu;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
@@ -57,26 +55,20 @@
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ListAdapter;
-import android.widget.SpinnerAdapter;
import com.android.photos.BitmapRegionTileSource;
-import java.io.File;
+import java.io.IOException;
import java.util.ArrayList;
-import java.util.List;
public class WallpaperPickerActivity extends WallpaperCropActivity {
static final String TAG = "Launcher.WallpaperPickerActivity";
- private static final int IMAGE_PICK = 5;
- private static final int PICK_WALLPAPER_THIRD_PARTY_ACTIVITY = 6;
- private static final int PICK_LIVE_WALLPAPER = 7;
+ public static final int IMAGE_PICK = 5;
+ public static final int PICK_WALLPAPER_THIRD_PARTY_ACTIVITY = 6;
+ public static final int PICK_LIVE_WALLPAPER = 7;
private static final String TEMP_WALLPAPER_TILES = "TEMP_WALLPAPER_TILES";
- private ArrayList<Drawable> mBundledWallpaperThumbs;
- private ArrayList<Integer> mBundledWallpaperResIds;
- private Resources mWallpaperResources;
-
private View mSelectedThumb;
private boolean mIgnoreNextTap;
private OnClickListener mThumbnailOnClickListener;
@@ -92,13 +84,80 @@
private SavedWallpaperImages mSavedImages;
private WallpaperInfo mLiveWallpaperInfoOnPickerLaunch;
- private static class ThumbnailMetaData {
- public TileType mTileType;
- public Uri mWallpaperUri;
- public int mSavedWallpaperDbId;
- public int mWallpaperResId;
- public LiveWallpaperListAdapter.LiveWallpaperInfo mLiveWallpaperInfo;
- public ResolveInfo mThirdPartyWallpaperPickerInfo;
+ public static abstract class WallpaperTileInfo {
+ public void onClick(WallpaperPickerActivity a) {}
+ public void onSave(WallpaperPickerActivity a) {}
+ public void onDelete() {}
+ public boolean isSelectable() { return false; }
+ }
+
+ public static class PickImageInfo extends WallpaperTileInfo {
+ public void onClick(WallpaperPickerActivity a) {
+ Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
+ intent.setType("image/*");
+ Utilities.startActivityForResultSafely(a, intent, IMAGE_PICK);
+ }
+ }
+
+ public static class UriWallpaperInfo extends WallpaperTileInfo {
+ private Uri mUri;
+ public UriWallpaperInfo(Uri uri) {
+ mUri = uri;
+ }
+ public void onClick(WallpaperPickerActivity a) {
+ CropView v = a.getCropView();
+ v.setTileSource(new BitmapRegionTileSource(
+ a, mUri, 1024, 0), null);
+ v.setTouchEnabled(true);
+ }
+
+ public void onSave(final WallpaperPickerActivity a) {
+ boolean finishActivityWhenDone = true;
+ OnBitmapCroppedHandler h = new OnBitmapCroppedHandler() {
+ public void onBitmapCropped(byte[] imageBytes) {
+ Point thumbSize = getDefaultThumbnailSize(a.getResources());
+ Bitmap thumb =
+ createThumbnail(thumbSize, null, null, imageBytes, null, 0, true);
+ a.getSavedImages().writeImage(thumb, imageBytes);
+ }
+ };
+ a.cropImageAndSetWallpaper(mUri, h, finishActivityWhenDone);
+ }
+ public boolean isSelectable() {
+ return true;
+ }
+ }
+
+ public static class ResourceWallpaperInfo extends WallpaperTileInfo {
+ private Resources mResources;
+ private int mResId;
+ private Drawable mThumb;
+
+ public ResourceWallpaperInfo(Resources res, int resId, Drawable thumb) {
+ mResources = res;
+ mResId = resId;
+ mThumb = thumb;
+ }
+ public void onClick(WallpaperPickerActivity a) {
+ BitmapRegionTileSource source = new BitmapRegionTileSource(
+ mResources, a, mResId, 1024, 0);
+ CropView v = a.getCropView();
+ v.setTileSource(source, null);
+ Point wallpaperSize = WallpaperCropActivity.getDefaultWallpaperSize(
+ a.getResources(), a.getWindowManager());
+ RectF crop = WallpaperCropActivity.getMaxCropRect(
+ source.getImageWidth(), source.getImageHeight(),
+ wallpaperSize.x, wallpaperSize.y, false);
+ v.setScale(wallpaperSize.x / crop.width());
+ v.setTouchEnabled(false);
+ }
+ public void onSave(WallpaperPickerActivity a) {
+ boolean finishActivityWhenDone = true;
+ a.cropImageAndSetWallpaper(mResources, mResId, finishActivityWhenDone);
+ }
+ public boolean isSelectable() {
+ return true;
+ }
}
// called by onCreate; this is subclassed to overwrite WallpaperCropActivity
@@ -151,63 +210,16 @@
}
return;
}
+ WallpaperTileInfo info = (WallpaperTileInfo) v.getTag();
if (mSelectedThumb != null) {
mSelectedThumb.setSelected(false);
+ mSelectedThumb = null;
}
-
- ThumbnailMetaData meta = (ThumbnailMetaData) v.getTag();
- if (meta.mTileType == TileType.WALLPAPER_RESOURCE ||
- meta.mTileType == TileType.SAVED_WALLPAPER ||
- meta.mTileType == TileType.WALLPAPER_URI) {
+ if (info.isSelectable()) {
mSelectedThumb = v;
v.setSelected(true);
}
- if (meta.mTileType == TileType.PICK_IMAGE) {
- Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
- intent.setType("image/*");
- Utilities.startActivityForResultSafely(
- WallpaperPickerActivity.this, intent, IMAGE_PICK);
- } else if (meta.mTileType == TileType.WALLPAPER_URI) {
- mCropView.setTileSource(new BitmapRegionTileSource(WallpaperPickerActivity.this,
- meta.mWallpaperUri, 1024, 0), null);
- mCropView.setTouchEnabled(true);
- } else if (meta.mTileType == TileType.SAVED_WALLPAPER) {
- String imageFilename = mSavedImages.getImageFilename(meta.mSavedWallpaperDbId);
- File file = new File(getFilesDir(), imageFilename);
- mCropView.setTileSource(new BitmapRegionTileSource(WallpaperPickerActivity.this,
- file.getAbsolutePath(), 1024, 0), null);
- mCropView.moveToLeft();
- mCropView.setTouchEnabled(false);
- } else if (meta.mTileType == TileType.LIVE_WALLPAPER) {
- Intent preview = new Intent(WallpaperManager.ACTION_CHANGE_LIVE_WALLPAPER);
- preview.putExtra(WallpaperManager.EXTRA_LIVE_WALLPAPER_COMPONENT,
- meta.mLiveWallpaperInfo.info.getComponent());
- WallpaperManager wm =
- WallpaperManager.getInstance(WallpaperPickerActivity.this);
- mLiveWallpaperInfoOnPickerLaunch = wm.getWallpaperInfo();
- Utilities.startActivityForResultSafely(WallpaperPickerActivity.this,
- preview, PICK_LIVE_WALLPAPER);
- } else if (meta.mTileType == TileType.WALLPAPER_RESOURCE) {
- BitmapRegionTileSource source = new BitmapRegionTileSource(mWallpaperResources,
- WallpaperPickerActivity.this, meta.mWallpaperResId, 1024, 0);
- mCropView.setTileSource(source, null);
- Point wallpaperSize = WallpaperCropActivity.getDefaultWallpaperSize(
- getResources(), getWindowManager());
- RectF crop = WallpaperCropActivity.getMaxCropRect(
- source.getImageWidth(), source.getImageHeight(),
- wallpaperSize.x, wallpaperSize.y, false);
- mCropView.setScale(wallpaperSize.x / crop.width());
- mCropView.setTouchEnabled(false);
- } else if (meta.mTileType == TileType.THIRD_PARTY_WALLPAPER_PICKER) {
- ResolveInfo info = meta.mThirdPartyWallpaperPickerInfo;
-
- final ComponentName itemComponentName = new ComponentName(
- info.activityInfo.packageName, info.activityInfo.name);
- Intent launchIntent = new Intent(Intent.ACTION_SET_WALLPAPER);
- launchIntent.setComponent(itemComponentName);
- Utilities.startActivityForResultSafely(WallpaperPickerActivity.this,
- launchIntent, PICK_WALLPAPER_THIRD_PARTY_ACTIVITY);
- }
+ info.onClick(WallpaperPickerActivity.this);
}
};
mLongClickListener = new View.OnLongClickListener() {
@@ -231,29 +243,24 @@
};
// Populate the built-in wallpapers
- findBundledWallpapers();
+ ArrayList<ResourceWallpaperInfo> wallpapers = findBundledWallpapers();
mWallpapersView = (LinearLayout) findViewById(R.id.wallpaper_list);
- ImageAdapter ia = new ImageAdapter(this, mBundledWallpaperThumbs);
- populateWallpapersFromAdapter(
- mWallpapersView, ia, mBundledWallpaperResIds, TileType.WALLPAPER_RESOURCE, false, true);
+ BuiltInWallpapersAdapter ia = new BuiltInWallpapersAdapter(this, wallpapers);
+ populateWallpapersFromAdapter(mWallpapersView, ia, false, true);
// Populate the saved wallpapers
mSavedImages = new SavedWallpaperImages(this);
mSavedImages.loadThumbnailsAndImageIdList();
- ArrayList<Drawable> savedWallpaperThumbs = mSavedImages.getThumbnails();
- ArrayList<Integer > savedWallpaperIds = mSavedImages.getImageIds();
- ia = new ImageAdapter(this, savedWallpaperThumbs);
- populateWallpapersFromAdapter(
- mWallpapersView, ia, savedWallpaperIds, TileType.SAVED_WALLPAPER, true, true);
+ populateWallpapersFromAdapter(mWallpapersView, mSavedImages, true, true);
// Populate the live wallpapers
- final LinearLayout liveWallpapersView = (LinearLayout) findViewById(R.id.live_wallpaper_list);
+ final LinearLayout liveWallpapersView =
+ (LinearLayout) findViewById(R.id.live_wallpaper_list);
final LiveWallpaperListAdapter a = new LiveWallpaperListAdapter(this);
a.registerDataSetObserver(new DataSetObserver() {
public void onChanged() {
liveWallpapersView.removeAllViews();
- populateWallpapersFromAdapter(
- liveWallpapersView, a, null, TileType.LIVE_WALLPAPER, false, false);
+ populateWallpapersFromAdapter(liveWallpapersView, a, false, false);
}
});
@@ -262,8 +269,7 @@
(LinearLayout) findViewById(R.id.third_party_wallpaper_list);
final ThirdPartyWallpaperPickerListAdapter ta =
new ThirdPartyWallpaperPickerListAdapter(this);
- populateWallpapersFromAdapter(thirdPartyWallpapersView, ta, null,
- TileType.THIRD_PARTY_WALLPAPER_PICKER, false, false);
+ populateWallpapersFromAdapter(thirdPartyWallpapersView, ta, false, false);
// Add a tile for the Gallery
LinearLayout masterWallpaperList = (LinearLayout) findViewById(R.id.master_wallpaper_list);
@@ -282,9 +288,8 @@
galleryThumbnailBg.setColorFilter(colorOverlay, PorterDuff.Mode.SRC_ATOP);
}
- ThumbnailMetaData meta = new ThumbnailMetaData();
- meta.mTileType = TileType.PICK_IMAGE;
- galleryThumbnail.setTag(meta);
+ PickImageInfo pickImageInfo = new PickImageInfo();
+ galleryThumbnail.setTag(pickImageInfo);
galleryThumbnail.setOnClickListener(mThumbnailOnClickListener);
// Create smooth layout transitions for when items are deleted
@@ -302,28 +307,8 @@
new View.OnClickListener() {
@Override
public void onClick(View v) {
- ThumbnailMetaData meta = (ThumbnailMetaData) mSelectedThumb.getTag();
- if (meta.mTileType == TileType.PICK_IMAGE) {
- // shouldn't be selected, but do nothing
- } else if (meta.mWallpaperUri != null) {
- boolean finishActivityWhenDone = true;
- OnBitmapCroppedHandler h = new OnBitmapCroppedHandler() {
- public void onBitmapCropped(byte[] imageBytes) {
- Bitmap thumb = createThumbnail(null, imageBytes, true);
- mSavedImages.writeImage(thumb, imageBytes);
- }
- };
- cropImageAndSetWallpaper(meta.mWallpaperUri, h, finishActivityWhenDone);
- } else if (meta.mSavedWallpaperDbId != 0) {
- boolean finishActivityWhenDone = true;
- String imageFilename =
- mSavedImages.getImageFilename(meta.mSavedWallpaperDbId);
- setWallpaper(imageFilename, finishActivityWhenDone);
- } else if (meta.mWallpaperResId != 0) {
- boolean finishActivityWhenDone = true;
- cropImageAndSetWallpaper(mWallpaperResources,
- meta.mWallpaperResId, finishActivityWhenDone);
- }
+ WallpaperTileInfo info = (WallpaperTileInfo) mSelectedThumb.getTag();
+ info.onSave(WallpaperPickerActivity.this);
}
});
@@ -376,8 +361,7 @@
CheckableFrameLayout c =
(CheckableFrameLayout) mWallpapersView.getChildAt(i);
if (c.isChecked()) {
- ThumbnailMetaData meta = (ThumbnailMetaData) c.getTag();
- mSavedImages.deleteImage(meta.mSavedWallpaperDbId);
+ ((WallpaperTileInfo) c.getTag()).onDelete();
viewsToRemove.add(c);
}
}
@@ -441,34 +425,12 @@
}
}
- private enum TileType {
- PICK_IMAGE,
- WALLPAPER_RESOURCE,
- WALLPAPER_URI,
- SAVED_WALLPAPER,
- LIVE_WALLPAPER,
- THIRD_PARTY_WALLPAPER_PICKER
- };
-
private void populateWallpapersFromAdapter(ViewGroup parent, BaseAdapter adapter,
- ArrayList<Integer> imageIds, TileType tileType, boolean addLongPressHandler, boolean selectFirstTile) {
+ boolean addLongPressHandler, boolean selectFirstTile) {
for (int i = 0; i < adapter.getCount(); i++) {
FrameLayout thumbnail = (FrameLayout) adapter.getView(i, null, parent);
parent.addView(thumbnail, i);
-
- ThumbnailMetaData meta = new ThumbnailMetaData();
- meta.mTileType = tileType;
- if (tileType == TileType.WALLPAPER_RESOURCE) {
- meta.mWallpaperResId = imageIds.get(i);
- } else if (tileType == TileType.SAVED_WALLPAPER) {
- meta.mSavedWallpaperDbId = imageIds.get(i);
- } else if (tileType == TileType.LIVE_WALLPAPER) {
- meta.mLiveWallpaperInfo =
- (LiveWallpaperListAdapter.LiveWallpaperInfo) adapter.getItem(i);
- } else if (tileType == TileType.THIRD_PARTY_WALLPAPER_PICKER) {
- meta.mThirdPartyWallpaperPickerInfo = (ResolveInfo) adapter.getItem(i);
- }
- thumbnail.setTag(meta);
+ thumbnail.setTag(adapter.getItem(i));
if (addLongPressHandler) {
addLongPressHandler(thumbnail);
}
@@ -479,16 +441,25 @@
}
}
- private Bitmap createThumbnail(Uri uri, byte[] imageBytes, boolean leftAligned) {
- Resources res = getResources();
- int width = res.getDimensionPixelSize(R.dimen.wallpaperThumbnailWidth);
- int height = res.getDimensionPixelSize(R.dimen.wallpaperThumbnailHeight);
+ private static Point getDefaultThumbnailSize(Resources res) {
+ return new Point(res.getDimensionPixelSize(R.dimen.wallpaperThumbnailWidth),
+ res.getDimensionPixelSize(R.dimen.wallpaperThumbnailHeight));
+
+ }
+
+ private static Bitmap createThumbnail(Point size, Context context, Uri uri, byte[] imageBytes,
+ Resources res, int resId, boolean leftAligned) {
+ int width = size.x;
+ int height = size.y;
BitmapCropTask cropTask;
if (uri != null) {
- cropTask = new BitmapCropTask(uri, null, width, height, false, true, null);
- } else {
+ cropTask = new BitmapCropTask(context, uri, null, width, height, false, true, null);
+ } else if (imageBytes != null) {
cropTask = new BitmapCropTask(imageBytes, null, width, height, false, true, null);
+ } else {
+ cropTask =
+ new BitmapCropTask(context, res, resId, null, width, height, false, true, null);
}
Point bounds = cropTask.getImageBounds();
if (bounds == null) {
@@ -515,7 +486,8 @@
// Load the thumbnail
ImageView image = (ImageView) pickedImageThumbnail.findViewById(R.id.wallpaper_image);
- Bitmap thumb = createThumbnail(uri, null, false);
+ Point defaultSize = getDefaultThumbnailSize(this.getResources());
+ Bitmap thumb = createThumbnail(defaultSize, this, uri, null, null, 0, false);
if (thumb != null) {
image.setImageBitmap(thumb);
Drawable thumbDrawable = image.getDrawable();
@@ -525,10 +497,8 @@
}
mWallpapersView.addView(pickedImageThumbnail, 0);
- ThumbnailMetaData meta = new ThumbnailMetaData();
- meta.mTileType = TileType.WALLPAPER_URI;
- meta.mWallpaperUri = uri;
- pickedImageThumbnail.setTag(meta);
+ UriWallpaperInfo info = new UriWallpaperInfo(uri);
+ pickedImageThumbnail.setTag(info);
pickedImageThumbnail.setOnClickListener(mThumbnailOnClickListener);
mThumbnailOnClickListener.onClick(pickedImageThumbnail);
}
@@ -564,18 +534,24 @@
v.setOnLongClickListener(mLongClickListener);
}
- private void findBundledWallpapers() {
- mBundledWallpaperThumbs = new ArrayList<Drawable>(24);
- mBundledWallpaperResIds = new ArrayList<Integer>(24);
+ private ArrayList<ResourceWallpaperInfo> findBundledWallpapers() {
+ ArrayList<ResourceWallpaperInfo> bundledWallpapers =
+ new ArrayList<ResourceWallpaperInfo>(24);
Pair<ApplicationInfo, Integer> r = getWallpaperArrayResourceId();
if (r != null) {
try {
- mWallpaperResources = getPackageManager().getResourcesForApplication(r.first);
- addWallpapers(mWallpaperResources, r.first.packageName, r.second);
+ Resources wallpaperRes = getPackageManager().getResourcesForApplication(r.first);
+ bundledWallpapers = addWallpapers(wallpaperRes, r.first.packageName, r.second);
} catch (PackageManager.NameNotFoundException e) {
}
}
+ //TODO: add default wallpaper
+ //Resources sysRes = Resources.getSystem();
+ //int resId = sysRes.getIdentifier("default_wallpaper", "drawable", "android");
+ //bundledWallpapers.add(
+ // new ResourceWallpaperInfo(sysRes, resId, new ColorDrawable(0xFFFF0000)));
+ return bundledWallpapers;
}
public Pair<ApplicationInfo, Integer> getWallpaperArrayResourceId() {
@@ -592,23 +568,39 @@
}
}
- private void addWallpapers(Resources resources, String packageName, int listResId) {
- final String[] extras = resources.getStringArray(listResId);
+ private ArrayList<ResourceWallpaperInfo> addWallpapers(
+ Resources res, String packageName, int listResId) {
+ ArrayList<ResourceWallpaperInfo> bundledWallpapers =
+ new ArrayList<ResourceWallpaperInfo>(24);
+ final String[] extras = res.getStringArray(listResId);
for (String extra : extras) {
- int res = resources.getIdentifier(extra, "drawable", packageName);
- if (res != 0) {
- final int thumbRes = resources.getIdentifier(extra + "_small",
- "drawable", packageName);
+ int resId = res.getIdentifier(extra, "drawable", packageName);
+ if (resId != 0) {
+ final int thumbRes = res.getIdentifier(extra + "_small", "drawable", packageName);
if (thumbRes != 0) {
- mBundledWallpaperThumbs.add(resources.getDrawable(thumbRes));
- mBundledWallpaperResIds.add(res);
+ ResourceWallpaperInfo wallpaperInfo =
+ new ResourceWallpaperInfo(res, resId, res.getDrawable(thumbRes));
+ bundledWallpapers.add(wallpaperInfo);
// Log.d(TAG, "add: [" + packageName + "]: " + extra + " (" + res + ")");
}
} else {
Log.e(TAG, "Couldn't find wallpaper " + extra);
}
}
+ return bundledWallpapers;
+ }
+
+ public CropView getCropView() {
+ return mCropView;
+ }
+
+ public SavedWallpaperImages getSavedImages() {
+ return mSavedImages;
+ }
+
+ public void onLiveWallpaperPickerLaunch() {
+ mLiveWallpaperInfoOnPickerLaunch = WallpaperManager.getInstance(this).getWallpaperInfo();
}
static class ZeroPaddingDrawable extends LevelListDrawable {
@@ -625,21 +617,21 @@
}
}
- private static class ImageAdapter extends BaseAdapter implements ListAdapter, SpinnerAdapter {
+ private static class BuiltInWallpapersAdapter extends BaseAdapter implements ListAdapter {
private LayoutInflater mLayoutInflater;
- private ArrayList<Drawable> mThumbs;
+ private ArrayList<ResourceWallpaperInfo> mWallpapers;
- ImageAdapter(Activity activity, ArrayList<Drawable> thumbs) {
+ BuiltInWallpapersAdapter(Activity activity, ArrayList<ResourceWallpaperInfo> wallpapers) {
mLayoutInflater = activity.getLayoutInflater();
- mThumbs = thumbs;
+ mWallpapers = wallpapers;
}
public int getCount() {
- return mThumbs.size();
+ return mWallpapers.size();
}
- public Object getItem(int position) {
- return position;
+ public ResourceWallpaperInfo getItem(int position) {
+ return mWallpapers.get(position);
}
public long getItemId(int position) {
@@ -647,27 +639,33 @@
}
public View getView(int position, View convertView, ViewGroup parent) {
- View view;
-
- if (convertView == null) {
- view = mLayoutInflater.inflate(R.layout.wallpaper_picker_item, parent, false);
- } else {
- view = convertView;
- }
-
- setWallpaperItemPaddingToZero((FrameLayout) view);
-
- ImageView image = (ImageView) view.findViewById(R.id.wallpaper_image);
-
- Drawable thumbDrawable = mThumbs.get(position);
- if (thumbDrawable != null) {
- image.setImageDrawable(thumbDrawable);
- thumbDrawable.setDither(true);
- } else {
+ Drawable thumb = mWallpapers.get(position).mThumb;
+ if (thumb == null) {
Log.e(TAG, "Error decoding thumbnail for wallpaper #" + position);
}
-
- return view;
+ return createImageTileView(mLayoutInflater, position, convertView, parent, thumb);
}
}
+
+ public static View createImageTileView(LayoutInflater layoutInflater, int position,
+ View convertView, ViewGroup parent, Drawable thumb) {
+ View view;
+
+ if (convertView == null) {
+ view = layoutInflater.inflate(R.layout.wallpaper_picker_item, parent, false);
+ } else {
+ view = convertView;
+ }
+
+ setWallpaperItemPaddingToZero((FrameLayout) view);
+
+ ImageView image = (ImageView) view.findViewById(R.id.wallpaper_image);
+
+ if (thumb != null) {
+ image.setImageDrawable(thumb);
+ thumb.setDither(true);
+ }
+
+ return view;
+ }
}
diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java
index 063a256..ada41a0 100644
--- a/src/com/android/launcher3/Workspace.java
+++ b/src/com/android/launcher3/Workspace.java
@@ -1846,10 +1846,10 @@
final boolean stateIsSpringLoaded = (state == State.SPRING_LOADED);
final boolean stateIsSmall = (state == State.SMALL);
final boolean stateIsOverview = (state == State.OVERVIEW);
- float finalBackgroundAlpha = stateIsSpringLoaded ? 1.0f : 0f;
+ float finalBackgroundAlpha = (stateIsSpringLoaded || stateIsOverview) ? 1.0f : 0f;
float finalHotseatAndPageIndicatorAlpha = (stateIsOverview || stateIsSmall) ? 0f : 1f;
float finalOverviewPanelAlpha = stateIsOverview ? 1f : 0f;
- float finalSearchBarAlpha = stateIsOverview ? 0f : 1f;
+ float finalSearchBarAlpha = !stateIsNormal ? 0f : 1f;
float finalWorkspaceTranslationY = stateIsOverview ? getOverviewModeTranslationY() : 0;
boolean zoomIn = true;
@@ -1872,8 +1872,6 @@
if (oldStateIsNormal && stateIsSmall) {
zoomIn = false;
updateChildrenLayersEnabled(false);
- } else {
- finalBackgroundAlpha = 1.0f;
}
}
final int duration = zoomIn ?
@@ -1881,24 +1879,9 @@
getResources().getInteger(R.integer.config_appsCustomizeWorkspaceShrinkTime);
for (int i = 0; i < getChildCount(); i++) {
final CellLayout cl = (CellLayout) getChildAt(i);
- float finalAlpha = (!mWorkspaceFadeInAdjacentScreens || stateIsSpringLoaded ||
- (i == mCurrentPage)) ? 1f : 0f;
- float currentAlpha = cl.getShortcutsAndWidgets().getAlpha();
- float initialAlpha = currentAlpha;
-
- // Determine the pages alpha during the state transition
- if ((oldStateIsSmall && stateIsNormal) ||
- (oldStateIsNormal && stateIsSmall)) {
- // To/from workspace - only show the current page unless the transition is not
- // animated and the animation end callback below doesn't run;
- // or, if we're in spring-loaded mode
- if (i == mCurrentPage || !animated || oldStateIsSpringLoaded) {
- finalAlpha = 1f;
- } else {
- initialAlpha = 0f;
- finalAlpha = 0f;
- }
- }
+ float finalAlpha = (!mWorkspaceFadeInAdjacentScreens ||
+ (i == mCurrentPage)) && !stateIsSmall ? 1f : 0f;
+ float initialAlpha = cl.getShortcutsAndWidgets().getAlpha();
mOldAlphas[i] = initialAlpha;
mNewAlphas[i] = finalAlpha;
@@ -1929,7 +1912,6 @@
cl.setBackgroundAlpha(mNewBackgroundAlphas[i]);
cl.setShortcutAndWidgetAlpha(mNewAlphas[i]);
} else {
-
if (mOldAlphas[i] != mNewAlphas[i] || currentAlpha != mNewAlphas[i]) {
LauncherViewPropertyAnimator alphaAnim =
new LauncherViewPropertyAnimator(cl.getShortcutsAndWidgets());
@@ -2932,7 +2914,10 @@
mTempPt[0] = x;
mTempPt[1] = y;
mLauncher.getDragLayer().getDescendantCoordRelativeToSelf(this, mTempPt, true);
- mLauncher.getHotseat().getHitRect(r);
+
+ LauncherAppState app = LauncherAppState.getInstance();
+ DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();
+ r = grid.getHotseatRect();
if (r.contains(mTempPt[0], mTempPt[1])) {
return true;
}