summaryrefslogtreecommitdiffstats
path: root/src/com/cyngn/theme/chooser/ThemeFragment.java
diff options
context:
space:
mode:
authorClark Scheff <clark@cyngn.com>2014-07-29 12:15:56 -0700
committerClark Scheff <clark@cyngn.com>2014-07-29 13:36:38 -0700
commit89df9342c934e750c11d1402f4b5c51b34defdec (patch)
treea132efce032474022c0bac3772e96268e5a089e7 /src/com/cyngn/theme/chooser/ThemeFragment.java
parente71e42f7304f5e6ba563a48de4ce1e70c94776ef (diff)
downloadpackages_apps_ThemeChooser-89df9342c934e750c11d1402f4b5c51b34defdec.tar.gz
packages_apps_ThemeChooser-89df9342c934e750c11d1402f4b5c51b34defdec.tar.bz2
packages_apps_ThemeChooser-89df9342c934e750c11d1402f4b5c51b34defdec.zip
Remove v1 code and resources and refactor v2 chooser.
Change-Id: Ic617365b3d26944e11c592b1508b4170ddb2871e
Diffstat (limited to 'src/com/cyngn/theme/chooser/ThemeFragment.java')
-rw-r--r--src/com/cyngn/theme/chooser/ThemeFragment.java1902
1 files changed, 1902 insertions, 0 deletions
diff --git a/src/com/cyngn/theme/chooser/ThemeFragment.java b/src/com/cyngn/theme/chooser/ThemeFragment.java
new file mode 100644
index 0000000..f6823ea
--- /dev/null
+++ b/src/com/cyngn/theme/chooser/ThemeFragment.java
@@ -0,0 +1,1902 @@
+/*
+ * Copyright (C) 2014 The CyanogenMod 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.cyngn.theme.chooser;
+
+import android.animation.Animator;
+import android.animation.AnimatorSet;
+import android.animation.IntEvaluator;
+import android.animation.ObjectAnimator;
+import android.animation.ValueAnimator;
+import android.app.WallpaperManager;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.ThemeUtils;
+import android.content.res.AssetManager;
+import android.content.res.Configuration;
+import android.content.res.Resources;
+import android.content.res.ThemeConfig;
+import android.content.res.ThemeManager;
+import android.database.Cursor;
+import android.graphics.Bitmap;
+import android.graphics.Bitmap.Config;
+import android.graphics.Point;
+import android.graphics.Rect;
+import android.graphics.Typeface;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.NinePatchDrawable;
+import android.media.MediaPlayer;
+import android.media.RingtoneManager;
+import android.net.Uri;
+import android.os.AsyncTask;
+import android.os.Bundle;
+import android.os.FileUtils;
+import android.os.Handler;
+import android.provider.Settings;
+import android.provider.ThemesContract;
+import android.provider.ThemesContract.PreviewColumns;
+import android.provider.ThemesContract.ThemesColumns;
+import android.support.v4.app.Fragment;
+import android.support.v4.app.LoaderManager;
+import android.support.v4.content.CursorLoader;
+import android.support.v4.content.Loader;
+import android.util.Log;
+import android.util.SparseArray;
+import android.view.Display;
+import android.view.Gravity;
+import android.view.LayoutInflater;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.ViewTreeObserver;
+import android.view.animation.AccelerateInterpolator;
+import android.view.animation.Animation;
+import android.view.animation.DecelerateInterpolator;
+import android.view.animation.ScaleAnimation;
+import android.widget.FrameLayout;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.PopupMenu;
+import android.widget.ProgressBar;
+import android.widget.ScrollView;
+import android.widget.TextView;
+import android.widget.Toast;
+
+import com.cyngn.theme.chooser.ComponentSelector.OnItemClickedListener;
+import com.cyngn.theme.util.AudioUtils;
+import com.cyngn.theme.util.BootAnimationHelper;
+import com.cyngn.theme.util.IconPreviewHelper;
+import com.cyngn.theme.util.ThemedTypefaceHelper;
+import com.cyngn.theme.util.TypefaceHelperCache;
+import com.cyngn.theme.util.Utils;
+import com.cyngn.theme.widget.BootAniImageView;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.zip.ZipFile;
+
+import static android.provider.ThemesContract.ThemesColumns.MODIFIES_ALARMS;
+import static android.provider.ThemesContract.ThemesColumns.MODIFIES_BOOT_ANIM;
+import static android.provider.ThemesContract.ThemesColumns.MODIFIES_LAUNCHER;
+import static android.provider.ThemesContract.ThemesColumns.MODIFIES_LOCKSCREEN;
+import static android.provider.ThemesContract.ThemesColumns.MODIFIES_NOTIFICATIONS;
+import static android.provider.ThemesContract.ThemesColumns.MODIFIES_OVERLAYS;
+import static android.provider.ThemesContract.ThemesColumns.MODIFIES_RINGTONES;
+import static android.provider.ThemesContract.ThemesColumns.MODIFIES_STATUS_BAR;
+import static android.provider.ThemesContract.ThemesColumns.MODIFIES_NAVIGATION_BAR;
+import static android.provider.ThemesContract.ThemesColumns.MODIFIES_ICONS;
+import static android.provider.ThemesContract.ThemesColumns.MODIFIES_FONTS;
+
+public class ThemeFragment extends Fragment implements LoaderManager.LoaderCallbacks<Cursor>,
+ ThemeManager.ThemeChangeListener {
+ private static final String TAG = ThemeFragment.class.getSimpleName();
+
+ public static final int ANIMATE_START_DELAY = 200;
+ public static final int ANIMATE_DURATION = 300;
+ public static final int ANIMATE_INTERPOLATE_FACTOR = 3;
+ public static final int ANIMATE_COMPONENT_CHANGE_DURATION = 200;
+ public static final int ANIMATE_COMPONENT_ICON_DELAY = 50;
+ public static final int ANIMATE_PROGRESS_IN_DURATION = 500;
+ public static final int ANIMATE_TITLE_OUT_DURATION = 400;
+ public static final int ANIMATE_PROGRESS_OUT_DURATION = 400;
+ public static final int ANIMATE_TITLE_IN_DURATION = 500;
+ public static final int REQUEST_UNINSTALL = 1; // Request code
+
+ private static final String NAVIGATION_BAR_BACKGROUND = "navbar_background";
+
+ public static final String CURRENTLY_APPLIED_THEME = "currently_applied_theme";
+
+ private static final ComponentName COMPONENT_DIALER =
+ new ComponentName("com.android.dialer", "com.android.dialer.DialtactsActivity");
+ private static final ComponentName COMPONENT_MESSAGING =
+ new ComponentName("com.android.mms", "com.android.mms.ui.ConversationList");
+ private static final ComponentName COMPONENT_CAMERANEXT =
+ new ComponentName("com.cyngn.cameranext", "com.android.camera.CameraLauncher");
+ private static final ComponentName COMPONENT_CAMERA =
+ new ComponentName("com.android.camera2", "com.android.camera.CameraActivity");
+ private static final ComponentName COMPONENT_BROWSER =
+ new ComponentName("com.android.browser", "com.android.browser.BrowserActivity");
+ private static final ComponentName COMPONENT_SETTINGS =
+ new ComponentName("com.android.settings", "com.android.settings.Settings");
+ private static final ComponentName COMPONENT_CALENDAR =
+ new ComponentName("com.android.calendar", "com.android.calendar.AllInOneActivity");
+ private static final ComponentName COMPONENT_GALERY =
+ new ComponentName("com.android.gallery3d", "com.android.gallery3d.app.GalleryActivity");
+ private static final String CAMERA_NEXT_PACKAGE = "com.cyngn.cameranext";
+
+ private static final int LOADER_ID_ALL = 0;
+ private static final int LOADER_ID_STATUS_BAR = 1;
+ private static final int LOADER_ID_FONT = 2;
+ private static final int LOADER_ID_ICONS = 3;
+ private static final int LOADER_ID_WALLPAPER = 4;
+ private static final int LOADER_ID_NAVIGATION_BAR = 5;
+ private static final int LOADER_ID_LOCKSCREEN = 6;
+ private static final int LOADER_ID_STYLE = 7;
+ private static final int LOADER_ID_BOOT_ANIMATION = 8;
+ private static final int LOADER_ID_RINGTONE = 9;
+ private static final int LOADER_ID_NOTIFICATION = 10;
+ private static final int LOADER_ID_ALARM = 11;
+
+ private static ComponentName[] sIconComponents;
+
+ private static TypefaceHelperCache sTypefaceHelperCache;
+
+ /**
+ * Maps the card's resource ID to a theme component
+ */
+ private final SparseArray<String> mCardIdsToComponentTypes = new SparseArray<String>();
+
+ private String mPkgName;
+ private Typeface mTypefaceNormal;
+ private int mBatteryStyle;
+
+ private ScrollView mScrollView;
+ private ViewGroup mScrollContent;
+ private ViewGroup mPreviewContent; // Contains icons, font, nav/status etc. Not wallpaper
+ private View mLoadingView;
+
+ //Status Bar Views
+ private ImageView mBluetooth;
+ private ImageView mWifi;
+ private ImageView mSignal;
+ private ImageView mBattery;
+ private TextView mClock;
+
+ // Other Misc Preview Views
+ private FrameLayout mShadowFrame;
+ private ImageView mWallpaper;
+ private ViewGroup mStatusBar;
+ private TextView mFontPreview;
+ private ViewGroup mIconContainer;
+ private ViewGroup mStyleContainer;
+ private ViewGroup mBootAnimationContainer;
+ private BootAniImageView mBootAnimation;
+
+ // Nav Bar Views
+ private ViewGroup mNavBar;
+ private ImageView mBackButton;
+ private ImageView mHomeButton;
+ private ImageView mRecentButton;
+
+ // Title Card Views
+ private ViewGroup mTitleCard;
+ private ViewGroup mTitleLayout;
+ private TextView mTitle;
+ private ImageView mApply;
+ private ImageView mOverflow;
+ private ProgressBar mProgress;
+
+ // Additional Card Views
+ private LinearLayout mAdditionalCards;
+ private WallpaperCardView mWallpaperCard;
+ private WallpaperCardView mLockScreenCard;
+
+ // Style views
+ private ImageView mStylePreview;
+
+ // Sound cards
+ private ViewGroup mRingtoneContainer;
+ private ImageView mRingtonePlayPause;
+ private ViewGroup mNotificationContainer;
+ private ImageView mNotificationPlayPause;
+ private ViewGroup mAlarmContainer;
+ private ImageView mAlarmPlayPause;
+ private Map<ImageView, MediaPlayer> mMediaPlayers;
+
+ private Handler mHandler;
+
+ private boolean mIsUninstalled;
+ private int mActiveCardId = -1;
+ private ComponentSelector mSelector;
+ // Supported components for the theme this fragment represents
+ private Map<String, String> mSelectedComponentsMap = new HashMap<String, String>();
+ // Current system theme configuration as component -> pkgName
+ private Map<String, String> mCurrentTheme = new HashMap<String, String>();
+
+ static ThemeFragment newInstance(String pkgName) {
+ if (sTypefaceHelperCache == null) {
+ sTypefaceHelperCache = TypefaceHelperCache.getInstance();
+ }
+ ThemeFragment f = new ThemeFragment();
+ Bundle args = new Bundle();
+ args.putString("pkgName", pkgName);
+ f.setArguments(args);
+ return f;
+ }
+
+ /**
+ * When creating, retrieve this instance's number from its arguments.
+ */
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ final Context context = getActivity();
+ mPkgName = getArguments().getString("pkgName");
+ mBatteryStyle = Settings.System.getInt(context.getContentResolver(),
+ Settings.System.STATUS_BAR_BATTERY, 0);
+
+ getIconComponents(context);
+ ThemedTypefaceHelper helper = sTypefaceHelperCache.getHelperForTheme(context,
+ CURRENTLY_APPLIED_THEME.equals(mPkgName) ? getAppliedFontPackageName() : mPkgName);
+ mTypefaceNormal = helper.getTypeface(Typeface.NORMAL);
+
+ mHandler = new Handler();
+
+ mCardIdsToComponentTypes.put(R.id.status_bar_container, MODIFIES_STATUS_BAR);
+ mCardIdsToComponentTypes.put(R.id.font_preview_container, MODIFIES_FONTS);
+ mCardIdsToComponentTypes.put(R.id.icon_container, MODIFIES_ICONS);
+ mCardIdsToComponentTypes.put(R.id.navigation_bar_container, MODIFIES_NAVIGATION_BAR);
+ mCardIdsToComponentTypes.put(R.id.wallpaper_card, MODIFIES_LAUNCHER);
+ mCardIdsToComponentTypes.put(R.id.lockscreen_card, MODIFIES_LOCKSCREEN);
+ mCardIdsToComponentTypes.put(R.id.style_card, MODIFIES_OVERLAYS);
+ mCardIdsToComponentTypes.put(R.id.bootani_preview_container, MODIFIES_BOOT_ANIM);
+ mCardIdsToComponentTypes.put(R.id.ringtone_preview_container, MODIFIES_RINGTONES);
+ mCardIdsToComponentTypes.put(R.id.notification_preview_container, MODIFIES_NOTIFICATIONS);
+ mCardIdsToComponentTypes.put(R.id.alarm_preview_container, MODIFIES_ALARMS);
+
+ mMediaPlayers = new HashMap<ImageView, MediaPlayer>(3);
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+ View v = inflater.inflate(R.layout.fragment_pager_list, container, false);
+
+ mScrollView = (ScrollView) v.findViewById(android.R.id.list);
+ mScrollContent = (ViewGroup) mScrollView.getChildAt(0);
+ mPreviewContent = (ViewGroup) v.findViewById(R.id.preview_container);
+ mLoadingView = v.findViewById(R.id.loading_view);
+
+ // Status Bar
+ mStatusBar = (ViewGroup) v.findViewById(R.id.status_bar);
+ mBluetooth = (ImageView) v.findViewById(R.id.bluetooth_icon);
+ mWifi = (ImageView) v.findViewById(R.id.wifi_icon);
+ mSignal = (ImageView) v.findViewById(R.id.signal_icon);
+ mBattery = (ImageView) v.findViewById(R.id.battery);
+ mClock = (TextView) v.findViewById(R.id.clock);
+
+ // Wallpaper / Font / Icons / etc
+ mWallpaper = (ImageView) v.findViewById(R.id.wallpaper);
+ mFontPreview = (TextView) v.findViewById(R.id.font_preview);
+ mFontPreview.setTypeface(mTypefaceNormal);
+ mIconContainer = (ViewGroup) v.findViewById(R.id.icon_container);
+ mShadowFrame = (FrameLayout) v.findViewById(R.id.shadow_frame);
+ mStyleContainer = (ViewGroup) v.findViewById(R.id.style_card);
+ mStylePreview = (ImageView) v.findViewById(R.id.style_preview);
+ mBootAnimationContainer = (ViewGroup) v.findViewById(R.id.bootani_preview_container);
+ mBootAnimation =
+ (BootAniImageView) mBootAnimationContainer.findViewById(R.id.bootani_preview);
+ mRingtoneContainer = (ViewGroup) v.findViewById(R.id.ringtone_preview_container);
+ mRingtonePlayPause = (ImageView) mRingtoneContainer.findViewById(R.id.play_pause);
+ mNotificationContainer = (ViewGroup) v.findViewById(R.id.notification_preview_container);
+ mNotificationPlayPause = (ImageView) mNotificationContainer.findViewById(R.id.play_pause);
+ mAlarmContainer = (ViewGroup) v.findViewById(R.id.alarm_preview_container);
+ mAlarmPlayPause = (ImageView) mAlarmContainer.findViewById(R.id.play_pause);
+
+ // Nav Bar
+ mNavBar = (ViewGroup) v.findViewById(R.id.navigation_bar);
+ mBackButton = (ImageView) v.findViewById(R.id.back_button);
+ mHomeButton = (ImageView) v.findViewById(R.id.home_button);
+ mRecentButton = (ImageView) v.findViewById(R.id.recent_button);
+
+ // Title Card
+ mTitleCard = (ViewGroup)v.findViewById(R.id.title_card);
+ mTitleLayout = (ViewGroup) v.findViewById(R.id.title_layout);
+ mTitle = (TextView) v.findViewById(R.id.title);
+ mProgress = (ProgressBar) v.findViewById(R.id.apply_progress);
+ mOverflow = (ImageView) v.findViewById(R.id.overflow);
+ mOverflow.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ PopupMenu popupmenu = new PopupMenu(getActivity(), mTitleCard, Gravity.END);
+ popupmenu.getMenuInflater().inflate(R.menu.overflow, popupmenu.getMenu());
+
+ if (CURRENTLY_APPLIED_THEME.equals(mPkgName) ||
+ mPkgName.equals(ThemeUtils.getDefaultThemePackageName(getActivity())) ||
+ mPkgName.equals(ThemeConfig.HOLO_DEFAULT)) {
+ Menu menu = popupmenu.getMenu();
+ menu.findItem(R.id.menu_delete).setEnabled(false);
+ }
+
+ popupmenu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
+ @Override
+ public boolean onMenuItemClick(MenuItem item) {
+ switch(item.getItemId()) {
+ case R.id.menu_author:
+ Toast.makeText(getActivity(),
+ "Not supported",
+ Toast.LENGTH_LONG).show();
+ break;
+ case R.id.menu_delete:
+ uninstallTheme();
+ break;
+ }
+
+ return true;
+ }
+ });
+ popupmenu.show();
+ }
+ });
+ mApply = (ImageView) v.findViewById(R.id.apply);
+ mApply.setOnClickListener(new View.OnClickListener() {
+ public void onClick(View v) {
+ applyTheme();
+ }
+ });
+ if (CURRENTLY_APPLIED_THEME.equals(mPkgName)) {
+ mApply.setVisibility(View.GONE);
+ }
+
+ // Additional cards which should hang out offscreen until expanded
+ mAdditionalCards = (LinearLayout) v.findViewById(R.id.additional_cards);
+
+
+ mWallpaperCard = (WallpaperCardView) v.findViewById(R.id.wallpaper_card);
+ mLockScreenCard = (WallpaperCardView) v.findViewById(R.id.lockscreen_card);
+ int translationY = getDistanceToMoveBelowScreen(mAdditionalCards);
+ mAdditionalCards.setTranslationY(translationY);
+
+ getLoaderManager().initLoader(LOADER_ID_ALL, null, this);
+
+ initCards(v);
+
+ return v;
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ if (CURRENTLY_APPLIED_THEME.equals(mPkgName)) {
+ if (getLoaderManager().getLoader(0) != null) {
+ getLoaderManager().restartLoader(0, null, this);
+ }
+ }
+ }
+
+ @Override
+ public void onPause() {
+ super.onPause();
+ stopMediaPlayers();
+ }
+
+ @Override
+ public void onDestroy() {
+ super.onDestroy();
+ freeMediaPlayers();
+ }
+
+ @Override
+ public void onProgress(int progress) {
+ mProgress.setProgress(progress);
+ }
+
+ @Override
+ public void onFinish(boolean isSuccess) {
+ // We post a runnable to mHandler so the client is removed from the same thread
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ ThemeManager tm = getThemeManager();
+ if (tm != null) tm.removeClient(ThemeFragment.this);
+ }
+ });
+ if (isSuccess) {
+ mProgress.setProgress(100);
+ animateProgressOut();
+ ((ChooserActivity) getActivity()).themeChangeEnded();
+ }
+ }
+
+ public void expand() {
+ // Full width and height!
+ ViewGroup content = (ViewGroup) mScrollView.getParent();
+ content.setPadding(0, 0, 0, 0);
+ ViewGroup.LayoutParams layoutParams = mPreviewContent.getLayoutParams();
+ layoutParams.height = ViewGroup.LayoutParams.MATCH_PARENT;
+ mPreviewContent.setLayoutParams(layoutParams);
+ mScrollView.setPadding(0,0,0,0);
+
+ // The parent of the wallpaper squishes the wp slightly because of padding from the 9 patch
+ // When the parent expands, the wallpaper returns to regular size which creates an
+ // undesireable effect.
+ Rect padding = new Rect();
+ NinePatchDrawable bg = (NinePatchDrawable) mShadowFrame.getBackground();
+ bg.getPadding(padding);
+ mIconContainer.setPadding(padding.left, padding.top, padding.right, padding.bottom);
+ mShadowFrame.setBackground(null);
+ mShadowFrame.setPadding(0, 0, 0, 0);
+ mAdditionalCards.setPadding(padding.left, padding.top, padding.right, padding.bottom);
+
+ // Off screen cards will become visible and then be animated in
+ mWallpaperCard.setVisibility(View.VISIBLE);
+
+ // Expand the children
+ int top = (int) getResources()
+ .getDimension(R.dimen.expanded_card_margin_top);
+ for (int i = 0; i < mPreviewContent.getChildCount(); i++) {
+ ComponentCardView child = (ComponentCardView) mPreviewContent.getChildAt(i);
+
+ LinearLayout.LayoutParams lparams =
+ (LinearLayout.LayoutParams) child.getLayoutParams();
+ lparams.setMargins(0, top, 0, 0);
+
+ child.setLayoutParams(lparams);
+ child.expand(false);
+ }
+
+ // Expand the additional children.
+ mAdditionalCards.setVisibility(View.VISIBLE);
+ for (int i = 0; i < mAdditionalCards.getChildCount(); i++) {
+ View v = mAdditionalCards.getChildAt(i);
+ if (v instanceof ComponentCardView) {
+ ComponentCardView card = (ComponentCardView) v;
+ card.setVisibility(View.VISIBLE);
+ card.expand(true);
+ }
+ }
+
+ // Collect the present position of all the children. The next layout/draw cycle will
+ // change these bounds since we just expanded them. Then we can animate from prev location
+ // to the new location. Note that the order of these calls matter as they all
+ // add themselves to the root layout as overlays
+ mScrollView.requestLayout();
+ animateWallpaperOut();
+ animateTitleCard(true, false);
+ animateChildren(true, getChildrensGlobalBounds(mPreviewContent));
+ animateExtras(true);
+ mSelector = ((ChooserActivity) getActivity()).getComponentSelector();
+ mSelector.setOnItemClickedListener(mOnComponentItemClicked);
+ if (mBootAnimation != null) mBootAnimation.start();
+ }
+
+
+
+ // Returns the boundaries for all the children of parent relative to the app window
+ private List<Rect> getChildrensGlobalBounds(ViewGroup parent) {
+ List<Rect> bounds = new ArrayList<Rect>();
+ for (int i = 0; i < parent.getChildCount(); i++) {
+ final View v = parent.getChildAt(i);
+ int[] pos = new int[2];
+ v.getLocationInWindow(pos);
+ Rect boundary = new Rect(pos[0], pos[1], pos[0] + v.getWidth(), pos[1]+v.getHeight());
+ bounds.add(boundary);
+ }
+ return bounds;
+ }
+
+ public void fadeOutCards(Runnable endAction) {
+ for (int i = 0; i < mPreviewContent.getChildCount(); i++) {
+ ComponentCardView v = (ComponentCardView) mPreviewContent.getChildAt(i);
+ v.animateFadeOut();
+ }
+ mHandler.postDelayed(endAction, ComponentCardView.CARD_FADE_DURATION);
+ }
+
+ public void collapse(final boolean applyTheme) {
+ // Pad the view so it appears thinner
+ ViewGroup content = (ViewGroup) mScrollView.getParent();
+ Resources r = mScrollView.getContext().getResources();
+ int leftRightPadding = (int) r.getDimension(R.dimen.collapsed_theme_page_padding);
+ content.setPadding(leftRightPadding, 0, leftRightPadding, 0);
+
+ //Move the theme preview so that it is near the center of page per spec
+ int paddingTop = (int) r.getDimension(R.dimen.collapsed_theme_page_padding_top);
+ mScrollView.setPadding(0, paddingTop, 0, 0);
+
+ // During expand the wallpaper size decreases slightly to makeup for 9patch padding
+ // so when we collapse we should increase it again.
+ mShadowFrame.setBackgroundResource(R.drawable.bg_themepreview_shadow);
+ Rect padding = new Rect();
+ final NinePatchDrawable bg = (NinePatchDrawable) mShadowFrame.getBackground();
+ bg.getPadding(padding);
+ mShadowFrame.setPadding(padding.left, padding.top, padding.right, padding.bottom);
+
+ // Gradually fade the drop shadow back in or else it will be out of place
+ ValueAnimator shadowAnimation = ValueAnimator.ofObject(new IntEvaluator(), 0, 255);
+ shadowAnimation.setDuration(ANIMATE_DURATION);
+ shadowAnimation.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
+ @Override
+ public void onAnimationUpdate(ValueAnimator animator) {
+ bg.setAlpha((Integer) animator.getAnimatedValue());
+ }
+
+ });
+ shadowAnimation.start();
+
+ //Move the title card back in
+ mTitleCard.setVisibility(View.VISIBLE);
+ mTitleCard.setTranslationY(0);
+
+ // Shrink the height
+ ViewGroup.LayoutParams layoutParams = mPreviewContent.getLayoutParams();
+ Resources resources = mPreviewContent.getResources();
+ layoutParams.height = (int) resources.getDimension(R.dimen.theme_preview_height);
+
+ for (int i = 0; i < mPreviewContent.getChildCount(); i++) {
+ ComponentCardView child = (ComponentCardView) mPreviewContent.getChildAt(i);
+ LinearLayout.LayoutParams lparams =
+ (LinearLayout.LayoutParams) child.getLayoutParams();
+ lparams.setMargins(0, 0, 0, 0);
+
+ if (child.getId() == R.id.icon_container) {
+ int top = (int) child.getResources()
+ .getDimension(R.dimen.collapsed_icon_card_margin_top);
+ lparams.setMargins(0, top, 0, 0);
+ } else if (child.getId() == R.id.font_preview_container) {
+ int top = (int) child.getResources()
+ .getDimension(R.dimen.collapsed_font_card_margin_top);
+ lparams.setMargins(0, top, 0, 0);
+ } else if (child.getId() == R.id.navigation_bar_container) {
+ int top = (int) child.getResources()
+ .getDimension(R.dimen.collapsed_navbar_card_margin_top);
+ lparams.setMargins(0, top, 0, 0);
+ }
+
+ child.getLayoutParams();
+ child.collapse();
+ }
+
+ // Collapse additional cards
+ for (int i = 0; i < mAdditionalCards.getChildCount(); i++) {
+ View v = mAdditionalCards.getChildAt(i);
+ if (v instanceof ComponentCardView) {
+ ComponentCardView card = (ComponentCardView) v;
+ card.setVisibility(View.VISIBLE);
+ card.collapse();
+ }
+ }
+
+ mScrollView.requestLayout();
+ animateChildren(false, getChildrensGlobalBounds(mPreviewContent));
+ animateExtras(false);
+ animateWallpaperIn();
+ animateTitleCard(false, applyTheme);
+ if (mBootAnimation != null) mBootAnimation.stop();
+ stopMediaPlayers();
+ }
+
+ // This will animate the children's vertical positions between the previous bounds and the
+ // new bounds which occur on the next draw
+ private void animateChildren(final boolean isExpanding, final List<Rect> prevBounds) {
+ final ViewGroup root = (ViewGroup) getActivity().getWindow()
+ .getDecorView().findViewById(android.R.id.content);
+
+ // Grab the child's new location and animate from prev to current loc.
+ final ViewTreeObserver observer = mScrollContent.getViewTreeObserver();
+ observer.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
+ public boolean onPreDraw() {
+ observer.removeOnPreDrawListener(this);
+
+ for (int i = mPreviewContent.getChildCount() - 1; i >= 0; i--) {
+ final ComponentCardView v = (ComponentCardView) mPreviewContent.getChildAt(i);
+
+ float prevY;
+ float endY;
+ float prevHeight;
+ float endHeight;
+ if (i >= prevBounds.size()) {
+ // View is being created
+ prevY = mPreviewContent.getTop() + mPreviewContent.getHeight();
+ endY = v.getY();
+ prevHeight = v.getHeight();
+ endHeight = v.getHeight();
+ } else {
+ Rect boundary = prevBounds.get(i);
+ prevY = boundary.top;
+ prevHeight = boundary.height();
+
+ int[] endPos = new int[2];
+ v.getLocationInWindow(endPos);
+ endY = endPos[1];
+ endHeight = v.getHeight();
+ }
+
+ int paddingTop = v.getPaddingTop() / 2;
+ v.setTranslationY((prevY - endY - paddingTop) + (prevHeight - endHeight) / 2);
+ root.getOverlay().add(v);
+
+ // Expanding has a delay while the wallpaper begins to fade out
+ // Collapsing is opposite of this so wallpaper will have the delay instead
+ int startDelay = isExpanding ? ANIMATE_START_DELAY : 0;
+
+ v.animate()
+ .setStartDelay(startDelay)
+ .translationY(0)
+ .setDuration(ANIMATE_DURATION)
+ .setInterpolator(
+ new DecelerateInterpolator(ANIMATE_INTERPOLATE_FACTOR))
+ .withEndAction(new Runnable() {
+ public void run() {
+ root.getOverlay().remove(v);
+ mPreviewContent.addView(v, 0);
+ }
+ });
+ v.postDelayed(new Runnable() {
+ public void run() {
+ if (isExpanding) {
+ v.animateExpand();
+ }
+ }
+ }, ANIMATE_DURATION / 2);
+ }
+ return true;
+ }
+ });
+ }
+
+ private void animateExtras(final boolean isExpanding) {
+ int[] pos = new int[2];
+ mAdditionalCards.getLocationInWindow(pos);
+ final ViewGroup parent = (ViewGroup) mAdditionalCards.getParent();
+ final ViewGroup root = (ViewGroup) getActivity().getWindow()
+ .getDecorView().findViewById(android.R.id.content);
+
+ // During a collapse we don't want the card to shrink so add it to the overlay now
+ // During an expand we want the card to expand so add it to the overlay post-layout
+ if (!isExpanding) {
+ root.getOverlay().add(mAdditionalCards);
+ }
+
+ // Expanding has a delay while the wallpaper begins to fade out
+ // Collapsing is opposite of this so wallpaper will have the delay instead
+ final int startDelay = isExpanding ? ANIMATE_START_DELAY : 0;
+ final ViewTreeObserver observer = mScrollContent.getViewTreeObserver();
+ observer.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
+ public boolean onPreDraw() {
+ observer.removeOnPreDrawListener(this);
+
+ int translationY = 0;
+ if (isExpanding) {
+ root.getOverlay().add(mAdditionalCards);
+ } else {
+ translationY = getDistanceToMoveBelowScreen(mAdditionalCards);
+ }
+
+ int duration = isExpanding ? ANIMATE_DURATION + 100 : ANIMATE_DURATION;
+ mAdditionalCards.animate()
+ .setStartDelay(startDelay)
+ .translationY(translationY)
+ .setDuration(duration)
+ .setInterpolator(
+ new DecelerateInterpolator(ANIMATE_INTERPOLATE_FACTOR))
+ .withEndAction(new Runnable() {
+ public void run() {
+ if (!isExpanding) {
+ mAdditionalCards.setVisibility(View.INVISIBLE);
+ }
+ root.getOverlay().remove(mAdditionalCards);
+ parent.addView(mAdditionalCards);
+ }
+ });
+ return false;
+ }
+ });
+ }
+
+ private int getDistanceToMoveBelowScreen(View v) {
+ Display display = getActivity().getWindowManager().getDefaultDisplay();
+ Point p = new Point();
+ display.getSize(p);
+ int heightId = getResources()
+ .getIdentifier("system_bar_height", "dimen", "android");
+ int navbar_height = getResources().getDimensionPixelSize(heightId);
+ int[] pos = new int[2];
+ v.getLocationInWindow(pos);
+ return p.y + navbar_height - pos[1];
+ }
+
+ private void animateTitleCard(final boolean expand, final boolean applyTheme) {
+ final ViewGroup parent = (ViewGroup) mTitleCard.getParent();
+ // Get current location of the title card
+ int[] location = new int[2];
+ mTitleCard.getLocationOnScreen(location);
+ final int prevY = location[1];
+
+ final ViewTreeObserver observer = mScrollContent.getViewTreeObserver();
+ observer.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
+ public boolean onPreDraw() {
+ observer.removeOnPreDrawListener(this);
+
+ final ViewGroup root = (ViewGroup) getActivity().getWindow()
+ .getDecorView().findViewById(android.R.id.content);
+
+ root.getOverlay().add(mTitleCard);
+
+ //Move title card back where it was before the relayout
+ float alpha = 1f;
+ if (expand) {
+ int[] endPos = new int[2];
+ mTitleCard.getLocationInWindow(endPos);
+ int endY = endPos[1];
+ mTitleCard.setTranslationY(prevY - endY);
+ alpha = 0;
+ } else {
+ }
+
+ // Fade the title card and move it out of the way
+ mTitleCard.animate()
+ .alpha(alpha)
+ .setDuration(ANIMATE_DURATION)
+ .withEndAction(new Runnable() {
+ public void run() {
+ root.getOverlay().remove(mTitleCard);
+ parent.addView(mTitleCard);
+ if (expand) {
+ mTitleCard.setVisibility(View.GONE);
+ } else if (applyTheme) {
+ // since the title card is the last animation when collapsing
+ // we will handle applying the theme, if applicable, here
+ applyTheme();
+ }
+ }
+ });
+ return true;
+ }
+ });
+ }
+
+ private void animateWallpaperOut() {
+ final ViewGroup root = (ViewGroup) getActivity().getWindow()
+ .getDecorView().findViewById(android.R.id.content);
+
+ int[] location = new int[2];
+ mWallpaper.getLocationOnScreen(location);
+
+ final int prevY = location[1];
+
+ final ViewTreeObserver observer = mScrollContent.getViewTreeObserver();
+ observer.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
+ public boolean onPreDraw() {
+ observer.removeOnPreDrawListener(this);
+ root.getOverlay().add(mWallpaper);
+
+ int[] location = new int[2];
+ mWallpaper.getLocationOnScreen(location);
+ final int newY = location[1];
+
+ mWallpaper.setTranslationY(prevY - newY);
+ mWallpaper.animate()
+ .alpha(0f)
+ .setDuration(300)
+ .withEndAction(new Runnable() {
+ public void run() {
+ root.getOverlay().remove(mWallpaper);
+ mShadowFrame.addView(mWallpaper, 0);
+ mWallpaper.setVisibility(View.GONE);
+ }
+ });
+ return true;
+
+ }
+ });
+ }
+
+ private void animateWallpaperIn() {
+ mWallpaper.setVisibility(View.VISIBLE);
+ mWallpaper.setTranslationY(0);
+ mWallpaper.animate()
+ .alpha(1f)
+ .setDuration(300);
+ }
+
+ private String getAppliedFontPackageName() {
+ final Configuration config = getActivity().getResources().getConfiguration();
+ final ThemeConfig themeConfig = config != null ? config.themeConfig : null;
+ return themeConfig != null ? themeConfig.getFontPkgName() :
+ ThemeConfig.getSystemTheme().getFontPkgName();
+ }
+
+ private ThemeManager getThemeManager() {
+ final Context context = getActivity();
+ if (context != null) {
+ return (ThemeManager) context.getSystemService(Context.THEME_SERVICE);
+ }
+ return null;
+ }
+
+ private void freeMediaPlayers() {
+ for (MediaPlayer mp : mMediaPlayers.values()) {
+ if (mp != null) {
+ mp.stop();
+ mp.release();
+ }
+ }
+ mMediaPlayers.clear();
+ }
+
+ private View.OnClickListener mPlayPauseClickListener = new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ MediaPlayer mp = (MediaPlayer) v.getTag();
+ if (mp != null) {
+ if (mp.isPlaying()) {
+ ((ImageView) v).setImageResource(R.drawable.media_sound_preview);
+ mp.pause();
+ mp.seekTo(0);
+ } else {
+ stopMediaPlayers();
+ ((ImageView) v).setImageResource(R.drawable.media_sound_stop);
+ mp.start();
+ }
+ }
+ }
+ };
+
+ private MediaPlayer.OnCompletionListener mPlayCompletionListener
+ = new MediaPlayer.OnCompletionListener() {
+ @Override
+ public void onCompletion(MediaPlayer mp) {
+ for (ImageView v : mMediaPlayers.keySet()) {
+ if (mp == mMediaPlayers.get(v)) {
+ if (v != null) {
+ v.setImageResource(R.drawable.media_sound_preview);
+ }
+ }
+ }
+ }
+ };
+
+ private void stopMediaPlayers() {
+ for (ImageView v : mMediaPlayers.keySet()) {
+ if (v != null) {
+ v.setImageResource(R.drawable.media_sound_preview);
+ }
+ MediaPlayer mp = mMediaPlayers.get(v);
+ if (mp != null && mp.isPlaying()) {
+ mp.pause();
+ mp.seekTo(0);
+ }
+ }
+ }
+
+ @Override
+ public Loader<Cursor> onCreateLoader(int id, Bundle args) {
+ String pkgName = mPkgName;
+ if (args != null) {
+ pkgName = args.getString("pkgName");
+ }
+ Uri uri = ThemesContract.PreviewColumns.CONTENT_URI;
+ String selection = ThemesContract.ThemesColumns.PKG_NAME + "= ?";
+ String[] selectionArgs = new String[] { pkgName };
+ String[] projection = null;
+ switch (id) {
+ case LOADER_ID_ALL:
+ if (!CURRENTLY_APPLIED_THEME.equals(pkgName)) {
+ projection = new String[] {
+ ThemesColumns.PKG_NAME,
+ ThemesColumns.TITLE,
+ ThemesColumns.WALLPAPER_URI,
+ ThemesColumns.HOMESCREEN_URI,
+ // Theme abilities
+ ThemesColumns.MODIFIES_LAUNCHER,
+ ThemesColumns.MODIFIES_LOCKSCREEN,
+ ThemesColumns.MODIFIES_ALARMS,
+ ThemesColumns.MODIFIES_BOOT_ANIM,
+ ThemesColumns.MODIFIES_FONTS,
+ ThemesColumns.MODIFIES_ICONS,
+ ThemesColumns.MODIFIES_NAVIGATION_BAR,
+ ThemesColumns.MODIFIES_OVERLAYS,
+ ThemesColumns.MODIFIES_RINGTONES,
+ ThemesColumns.MODIFIES_STATUS_BAR,
+ ThemesColumns.MODIFIES_NOTIFICATIONS,
+ //Previews
+ PreviewColumns.WALLPAPER_PREVIEW,
+ PreviewColumns.STATUSBAR_BACKGROUND,
+ PreviewColumns.STATUSBAR_WIFI_ICON,
+ PreviewColumns.STATUSBAR_WIFI_COMBO_MARGIN_END,
+ PreviewColumns.STATUSBAR_BLUETOOTH_ICON,
+ PreviewColumns.STATUSBAR_SIGNAL_ICON,
+ PreviewColumns.STATUSBAR_CLOCK_TEXT_COLOR,
+ PreviewColumns.STATUSBAR_BATTERY_CIRCLE,
+ PreviewColumns.STATUSBAR_BATTERY_LANDSCAPE,
+ PreviewColumns.STATUSBAR_BATTERY_PORTRAIT,
+ PreviewColumns.NAVBAR_BACK_BUTTON,
+ PreviewColumns.NAVBAR_HOME_BUTTON,
+ PreviewColumns.NAVBAR_RECENT_BUTTON,
+ PreviewColumns.ICON_PREVIEW_1,
+ PreviewColumns.ICON_PREVIEW_2,
+ PreviewColumns.ICON_PREVIEW_3,
+ PreviewColumns.LOCK_WALLPAPER_PREVIEW,
+ PreviewColumns.STYLE_PREVIEW
+ };
+ } else {
+ projection = new String[] {
+ PreviewColumns.WALLPAPER_PREVIEW,
+ PreviewColumns.STATUSBAR_BACKGROUND,
+ PreviewColumns.STATUSBAR_WIFI_ICON,
+ PreviewColumns.STATUSBAR_WIFI_COMBO_MARGIN_END,
+ PreviewColumns.STATUSBAR_BLUETOOTH_ICON,
+ PreviewColumns.STATUSBAR_SIGNAL_ICON,
+ PreviewColumns.STATUSBAR_CLOCK_TEXT_COLOR,
+ PreviewColumns.STATUSBAR_BATTERY_CIRCLE,
+ PreviewColumns.STATUSBAR_BATTERY_LANDSCAPE,
+ PreviewColumns.STATUSBAR_BATTERY_PORTRAIT,
+ PreviewColumns.NAVBAR_BACK_BUTTON,
+ PreviewColumns.NAVBAR_HOME_BUTTON,
+ PreviewColumns.NAVBAR_RECENT_BUTTON,
+ PreviewColumns.ICON_PREVIEW_1,
+ PreviewColumns.ICON_PREVIEW_2,
+ PreviewColumns.ICON_PREVIEW_3,
+ PreviewColumns.LOCK_WALLPAPER_PREVIEW,
+ PreviewColumns.STYLE_PREVIEW,
+ // TODO: add this to the ThemesContract if this
+ // design moves beyond prototype
+ NAVIGATION_BAR_BACKGROUND
+ };
+ uri = PreviewColumns.APPLIED_URI;
+ selection = null;
+ selectionArgs = null;
+ }
+ break;
+ case LOADER_ID_STATUS_BAR:
+ projection = new String[] {
+ ThemesColumns.PKG_NAME,
+ ThemesColumns.TITLE,
+ PreviewColumns.STATUSBAR_BACKGROUND,
+ PreviewColumns.STATUSBAR_WIFI_ICON,
+ PreviewColumns.STATUSBAR_WIFI_COMBO_MARGIN_END,
+ PreviewColumns.STATUSBAR_BLUETOOTH_ICON,
+ PreviewColumns.STATUSBAR_SIGNAL_ICON,
+ PreviewColumns.STATUSBAR_CLOCK_TEXT_COLOR,
+ PreviewColumns.STATUSBAR_BATTERY_CIRCLE,
+ PreviewColumns.STATUSBAR_BATTERY_LANDSCAPE,
+ PreviewColumns.STATUSBAR_BATTERY_PORTRAIT
+ };
+ break;
+ case LOADER_ID_FONT:
+ projection = new String[] {
+ ThemesColumns.PKG_NAME,
+ ThemesColumns.TITLE
+ };
+ break;
+ case LOADER_ID_ICONS:
+ projection = new String[] {
+ ThemesColumns.PKG_NAME,
+ ThemesColumns.TITLE,
+ PreviewColumns.ICON_PREVIEW_1,
+ PreviewColumns.ICON_PREVIEW_2,
+ PreviewColumns.ICON_PREVIEW_3,
+ PreviewColumns.ICON_PREVIEW_4
+ };
+ break;
+ case LOADER_ID_WALLPAPER:
+ projection = new String[] {
+ ThemesColumns.PKG_NAME,
+ ThemesColumns.TITLE,
+ PreviewColumns.WALLPAPER_PREVIEW
+ };
+ break;
+ case LOADER_ID_NAVIGATION_BAR:
+ projection = new String[] {
+ ThemesColumns.PKG_NAME,
+ ThemesColumns.TITLE,
+ PreviewColumns.STATUSBAR_BACKGROUND,
+ PreviewColumns.NAVBAR_BACK_BUTTON,
+ PreviewColumns.NAVBAR_HOME_BUTTON,
+ PreviewColumns.NAVBAR_RECENT_BUTTON
+ };
+ break;
+ case LOADER_ID_LOCKSCREEN:
+ projection = new String[]{
+ ThemesColumns.PKG_NAME,
+ ThemesColumns.TITLE,
+ PreviewColumns.LOCK_WALLPAPER_PREVIEW
+ };
+ break;
+ case LOADER_ID_STYLE:
+ projection = new String[] {
+ ThemesColumns.PKG_NAME,
+ ThemesColumns.TITLE,
+ PreviewColumns.STYLE_PREVIEW
+ };
+ break;
+ case LOADER_ID_BOOT_ANIMATION:
+ projection = new String[] {
+ ThemesColumns.PKG_NAME,
+ ThemesColumns.TITLE
+ };
+ break;
+ case LOADER_ID_RINGTONE:
+ case LOADER_ID_NOTIFICATION:
+ case LOADER_ID_ALARM:
+ projection = new String[] {
+ ThemesColumns.PKG_NAME,
+ ThemesColumns.TITLE
+ };
+ break;
+ }
+ return new CursorLoader(getActivity(), uri, projection, selection, selectionArgs, null);
+ }
+
+ @Override
+ public void onLoadFinished(Loader<Cursor> loader, Cursor c) {
+ c.moveToFirst();
+ if (c.getCount() == 0) return;
+ switch (loader.getId()) {
+ case LOADER_ID_ALL:
+ populateSupportedComponents(c);
+ loadStatusBar(c, false);
+ loadIcons(c, false);
+ loadNavBar(c, false);
+ loadTitle(c);
+ loadFont(c, false);
+ loadAndRemoveAdditionalCards(c);
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ animateContentIn();
+ }
+ });
+ break;
+ case LOADER_ID_STATUS_BAR:
+ loadStatusBar(c, true);
+ break;
+ case LOADER_ID_FONT:
+ loadFont(c, true);
+ break;
+ case LOADER_ID_ICONS:
+ loadIcons(c, true);
+ break;
+ case LOADER_ID_WALLPAPER:
+ loadWallpaper(c, true);
+ break;
+ case LOADER_ID_NAVIGATION_BAR:
+ loadNavBar(c, true);
+ break;
+ case LOADER_ID_LOCKSCREEN:
+ loadLockScreen(c, true);
+ break;
+ case LOADER_ID_STYLE:
+ loadStyle(c, true);
+ break;
+ case LOADER_ID_BOOT_ANIMATION:
+ loadBootAnimation(c, true);
+ break;
+ case LOADER_ID_RINGTONE:
+ loadAudible(RingtoneManager.TYPE_RINGTONE, c, true);
+ break;
+ case LOADER_ID_NOTIFICATION:
+ loadAudible(RingtoneManager.TYPE_NOTIFICATION, c, true);
+ break;
+ case LOADER_ID_ALARM:
+ loadAudible(RingtoneManager.TYPE_ALARM, c, true);
+ break;
+ }
+ }
+
+ @Override
+ public void onLoaderReset(Loader<Cursor> loader) {}
+
+ private void loadAndRemoveAdditionalCards(Cursor c) {
+ LinkedList<View> removeList = new LinkedList<View>();
+ for(int i=0; i < mAdditionalCards.getChildCount(); i++) {
+ View v = mAdditionalCards.getChildAt(i);
+ if (v instanceof ComponentCardView) {
+ String component = mCardIdsToComponentTypes.get(v.getId());
+ if (shouldShowComponentCard(component)) {
+ loadAdditionalCard(c, component);
+ } else {
+ removeList.add(v);
+ // remove the Space below this card
+ removeList.add(mAdditionalCards.getChildAt(i+1));
+
+ if (component != null && !shouldShowComponentCard(component)) {
+ mCardIdsToComponentTypes.remove(v.getId());
+ }
+ }
+ }
+ }
+
+ // TODO: It might make more sense to not inflate so many views if we do not
+ // plan to actually use them. But it is nice to be able to declare them in the
+ // xml layout under additionalCards
+ for(View v : removeList) {
+ mAdditionalCards.removeView(v);
+ }
+
+ if (shouldShowComponentCard(MODIFIES_LOCKSCREEN)) {
+ loadLockScreen(c, false);
+ } else {
+ mAdditionalCards.removeView(mLockScreenCard);
+ }
+ }
+
+ private void loadAdditionalCard(Cursor c, String component) {
+ if (MODIFIES_LOCKSCREEN.equals(component)) {
+ loadLockScreen(c, false);
+ } else if (MODIFIES_LAUNCHER.equals(component)) {
+ loadWallpaper(c, false);
+ } else if (MODIFIES_OVERLAYS.equals(component)) {
+ loadStyle(c, false);
+ } else if (MODIFIES_BOOT_ANIM.equals(component)) {
+ loadBootAnimation(c, false);
+ } else if (MODIFIES_RINGTONES.equals(component)) {
+ loadAudible(RingtoneManager.TYPE_RINGTONE, c, false);
+ } else if (MODIFIES_NOTIFICATIONS.equals(component)) {
+ loadAudible(RingtoneManager.TYPE_NOTIFICATION, c, false);
+ } else if (MODIFIES_ALARMS.equals(component)) {
+ loadAudible(RingtoneManager.TYPE_ALARM, c, false);
+ } else {
+ throw new IllegalArgumentException("Don't know how to load: " + component);
+ }
+ }
+
+ private void populateSupportedComponents(Cursor c) {
+ // Currently applied theme doesn't return the columns we expect and
+ // it doesn't matter because currently applied theme shows everything anyhow
+ if (CURRENTLY_APPLIED_THEME.equals(mPkgName)) {
+ return;
+ }
+
+ List<String> components = ThemeUtils.getAllComponents();
+ for(String component : components) {
+ int pkgIdx = c.getColumnIndex(ThemesColumns.PKG_NAME);
+ int modifiesCompIdx = c.getColumnIndex(component);
+
+ String pkg = c.getString(pkgIdx);
+ boolean supported = c.getInt(modifiesCompIdx) == 1;
+ if (supported) {
+ mSelectedComponentsMap.put(component, pkg);
+ }
+ }
+ if (!mSelectedComponentsMap.containsKey(MODIFIES_BOOT_ANIM)) {
+ mBootAnimation = null;
+ }
+ }
+
+ /**
+ * Determines whether a card should be shown or not.
+ * UX Rules:
+ * 1) "My Theme" always shows all cards
+ * 2) Other themes only show what has been implemented in the theme
+ *
+ */
+ private Boolean shouldShowComponentCard(String component) {
+ if (CURRENTLY_APPLIED_THEME.equals(mPkgName)) {
+ return true;
+ }
+ String pkg = mSelectedComponentsMap.get(component);
+ return pkg != null && pkg.equals(mPkgName);
+ }
+
+ private void loadTitle(Cursor c) {
+ if (CURRENTLY_APPLIED_THEME.equals(mPkgName)) {
+ mTitle.setText(R.string.my_theme);
+ } else {
+ int titleIdx = c.getColumnIndex(ThemesColumns.TITLE);
+ String title = c.getString(titleIdx);
+ mTitle.setText(title);
+ }
+ }
+
+ private void loadWallpaper(Cursor c, boolean animate) {
+ Drawable overlay = null;
+ if (animate) {
+ overlay = getOverlayDrawable(mWallpaperCard, true);
+ }
+
+ int pkgNameIdx = c.getColumnIndex(ThemesColumns.PKG_NAME);
+ int wpIdx = c.getColumnIndex(PreviewColumns.WALLPAPER_PREVIEW);
+ final Resources res = getResources();
+ if (pkgNameIdx > -1) {
+ Bitmap bitmap = Utils.loadBitmapBlob(c, wpIdx);
+ mWallpaper.setImageBitmap(bitmap);
+ mWallpaperCard.setWallpaper(new BitmapDrawable(res, bitmap));
+ String pkgName = c.getString(pkgNameIdx);
+ mSelectedComponentsMap.put(MODIFIES_LAUNCHER, pkgName);
+ } else {
+ final Context context = getActivity();
+ Drawable wp = context == null ? null :
+ WallpaperManager.getInstance(context).getDrawable();
+ if (wp == null) {
+ wp = new BitmapDrawable(res, Utils.loadBitmapBlob(c, wpIdx));
+ }
+ mWallpaper.setImageDrawable(wp);
+ mWallpaperCard.setWallpaper(wp);
+ }
+
+ if (animate) {
+ animateContentChange(R.id.wallpaper_card, mWallpaperCard, overlay);
+ }
+ }
+
+ public void loadLockScreen(Cursor c, boolean animate) {
+ Drawable overlay = null;
+ if (animate) {
+ overlay = getOverlayDrawable(mLockScreenCard, true);
+ }
+
+ int pkgNameIdx = c.getColumnIndex(ThemesColumns.PKG_NAME);
+ int wpIdx = c.getColumnIndex(PreviewColumns.LOCK_WALLPAPER_PREVIEW);
+ final Resources res = getResources();
+ if (pkgNameIdx > -1) {
+ Bitmap bitmap = Utils.loadBitmapBlob(c, wpIdx);
+ mLockScreenCard.setWallpaper(new BitmapDrawable(res, bitmap));
+ String pkgName = c.getString(pkgNameIdx);
+ mSelectedComponentsMap.put(MODIFIES_LOCKSCREEN, pkgName);
+ } else {
+ final Context context = getActivity();
+ Drawable wp = context == null ? null :
+ WallpaperManager.getInstance(context).getFastKeyguardDrawable();
+ if (wp == null) {
+ wp = new BitmapDrawable(res, Utils.loadBitmapBlob(c, wpIdx));
+ }
+ mLockScreenCard.setWallpaper(wp);
+ }
+
+ if (animate) {
+ animateContentChange(R.id.lockscreen_card, mLockScreenCard, overlay);
+ }
+ }
+
+ private void loadStatusBar(Cursor c, boolean animate) {
+ int backgroundIdx = c.getColumnIndex(PreviewColumns.STATUSBAR_BACKGROUND);
+ int wifiIdx = c.getColumnIndex(PreviewColumns.STATUSBAR_WIFI_ICON);
+ int wifiMarginIdx = c.getColumnIndex(PreviewColumns.STATUSBAR_WIFI_COMBO_MARGIN_END);
+ int bluetoothIdx = c.getColumnIndex(PreviewColumns.STATUSBAR_BLUETOOTH_ICON);
+ int signalIdx = c.getColumnIndex(PreviewColumns.STATUSBAR_SIGNAL_ICON);
+ int batteryIdx = c.getColumnIndex(Utils.getBatteryIndex(mBatteryStyle));
+ int clockColorIdx = c.getColumnIndex(PreviewColumns.STATUSBAR_CLOCK_TEXT_COLOR);
+ int pkgNameIdx = c.getColumnIndex(ThemesColumns.PKG_NAME);
+
+ Bitmap background = Utils.loadBitmapBlob(c, backgroundIdx);
+ Bitmap bluetoothIcon = Utils.loadBitmapBlob(c, bluetoothIdx);
+ Bitmap wifiIcon = Utils.loadBitmapBlob(c, wifiIdx);
+ Bitmap signalIcon = Utils.loadBitmapBlob(c, signalIdx);
+ Bitmap batteryIcon = Utils.loadBitmapBlob(c, batteryIdx);
+ int wifiMargin = c.getInt(wifiMarginIdx);
+ int clockTextColor = c.getInt(clockColorIdx);
+
+ Drawable overlay = null;
+ if (animate) {
+ overlay = getOverlayDrawable(mStatusBar, false);
+ }
+
+ mStatusBar.setBackground(new BitmapDrawable(getActivity().getResources(), background));
+ mBluetooth.setImageBitmap(bluetoothIcon);
+ mWifi.setImageBitmap(wifiIcon);
+ mSignal.setImageBitmap(signalIcon);
+ mBattery.setImageBitmap(batteryIcon);
+ mClock.setTextColor(clockTextColor);
+
+ ViewGroup.MarginLayoutParams params =
+ (ViewGroup.MarginLayoutParams) mWifi.getLayoutParams();
+ params.setMarginEnd(wifiMargin);
+ mWifi.setLayoutParams(params);
+
+ if (mBatteryStyle == 4) {
+ mBattery.setVisibility(View.GONE);
+ } else {
+ mBattery.setVisibility(View.VISIBLE);
+ }
+ mStatusBar.post(new Runnable() {
+ @Override
+ public void run() {
+ mStatusBar.invalidate();
+ }
+ });
+ if (pkgNameIdx > -1) {
+ String pkgName = c.getString(pkgNameIdx);
+ mSelectedComponentsMap.put(MODIFIES_STATUS_BAR, pkgName);
+ }
+ if (animate) {
+ animateContentChange(R.id.status_bar_container, mStatusBar, overlay);
+ }
+ }
+
+ private void loadIcons(Cursor c, boolean animate) {
+ int[] iconIdx = new int[4];
+ iconIdx[0] = c.getColumnIndex(PreviewColumns.ICON_PREVIEW_1);
+ iconIdx[1] = c.getColumnIndex(PreviewColumns.ICON_PREVIEW_2);
+ iconIdx[2] = c.getColumnIndex(PreviewColumns.ICON_PREVIEW_3);
+ iconIdx[3] = c.getColumnIndex(PreviewColumns.ICON_PREVIEW_4);
+ int pkgNameIdx = c.getColumnIndex(ThemesColumns.PKG_NAME);
+
+ // Set the icons. If the provider does not have an icon preview then
+ // fall back to the default icon set
+ IconPreviewHelper helper = new IconPreviewHelper(getActivity(), "");
+ int numOfChildren = ((ViewGroup)mIconContainer.getChildAt(1)).getChildCount();
+
+ List<ImageView> iconViews = new ArrayList<ImageView>(numOfChildren);
+ for(int i=0; i < numOfChildren; i++) {
+ final View view = (View) ((ViewGroup)mIconContainer.getChildAt(1)).getChildAt(i);
+ if (!(view instanceof ImageView)) continue;
+ iconViews.add((ImageView) view);
+ }
+
+ for(int i=0; i < iconViews.size() && i < iconIdx.length; i++) {
+ final ImageView v = iconViews.get(i);
+ Bitmap bitmap = Utils.loadBitmapBlob(c, iconIdx[i]);
+ Drawable oldIcon = v.getDrawable();
+ Drawable newIcon;
+ if (bitmap == null) {
+ ComponentName component = sIconComponents[i];
+ newIcon = helper.getDefaultIcon(component.getPackageName(),
+ component.getClassName());
+ } else {
+ newIcon = new BitmapDrawable(getResources(), bitmap);
+ }
+ if (animate) {
+ Drawable[] layers = new Drawable[2];
+ layers[0] = oldIcon instanceof IconTransitionDrawable ?
+ ((IconTransitionDrawable) oldIcon).getDrawable(1) : oldIcon;
+ layers[1] = newIcon;
+ final IconTransitionDrawable itd = new IconTransitionDrawable(layers);
+ v.postDelayed(new Runnable() {
+ @Override
+ public void run() {
+ itd.startTransition(ANIMATE_COMPONENT_CHANGE_DURATION);
+ v.setImageDrawable(itd);
+ }
+ }, ANIMATE_COMPONENT_ICON_DELAY * i);
+ } else {
+ v.setImageDrawable(newIcon);
+ }
+ }
+ if (pkgNameIdx > -1) {
+ String pkgName = c.getString(pkgNameIdx);
+ mSelectedComponentsMap.put(MODIFIES_ICONS, pkgName);
+ }
+ }
+
+ private void loadNavBar(Cursor c, boolean animate) {
+ int backButtonIdx = c.getColumnIndex(PreviewColumns.NAVBAR_BACK_BUTTON);
+ int homeButtonIdx = c.getColumnIndex(PreviewColumns.NAVBAR_HOME_BUTTON);
+ int recentButtonIdx = c.getColumnIndex(PreviewColumns.NAVBAR_RECENT_BUTTON);
+ int backgroundIdx = c.getColumnIndex(NAVIGATION_BAR_BACKGROUND);
+ if (backgroundIdx == -1) {
+ backgroundIdx = c.getColumnIndex(PreviewColumns.STATUSBAR_BACKGROUND);
+ }
+ int pkgNameIdx = c.getColumnIndex(ThemesColumns.PKG_NAME);
+
+ Bitmap background = Utils.loadBitmapBlob(c, backgroundIdx);
+ Bitmap backButton = Utils.loadBitmapBlob(c, backButtonIdx);
+ Bitmap homeButton = Utils.loadBitmapBlob(c, homeButtonIdx);
+ Bitmap recentButton = Utils.loadBitmapBlob(c, recentButtonIdx);
+
+ Drawable overlay = null;
+ if (animate) {
+ overlay = getOverlayDrawable(mNavBar, false);
+ }
+
+ mNavBar.setBackground(new BitmapDrawable(getActivity().getResources(), background));
+ mBackButton.setImageBitmap(backButton);
+ mHomeButton.setImageBitmap(homeButton);
+ mRecentButton.setImageBitmap(recentButton);
+
+ if (pkgNameIdx > -1) {
+ String pkgName = c.getString(pkgNameIdx);
+ mSelectedComponentsMap.put(MODIFIES_NAVIGATION_BAR, pkgName);
+ }
+ if (animate) {
+ animateContentChange(R.id.navigation_bar_container, mNavBar, overlay);
+ }
+ }
+
+ private void loadFont(Cursor c, boolean animate) {
+ Drawable overlay = null;
+ if (animate) {
+ overlay = getOverlayDrawable(mFontPreview, true);
+ }
+
+ int pkgNameIdx = c.getColumnIndex(ThemesColumns.PKG_NAME);
+ String pkgName = pkgNameIdx >= 0 ? c.getString(pkgNameIdx) : mPkgName;
+ TypefaceHelperCache cache = TypefaceHelperCache.getInstance();
+ ThemedTypefaceHelper helper = cache.getHelperForTheme(getActivity(),
+ CURRENTLY_APPLIED_THEME.equals(pkgName) ? getAppliedFontPackageName() : pkgName);
+ mTypefaceNormal = helper.getTypeface(Typeface.NORMAL);
+ mFontPreview.setTypeface(mTypefaceNormal);
+ if (pkgNameIdx > -1) {
+ mSelectedComponentsMap.put(MODIFIES_FONTS, pkgName);
+ }
+ if (animate) {
+ animateContentChange(R.id.font_preview_container, mFontPreview, overlay);
+ }
+ }
+
+ private void loadStyle(Cursor c, boolean animate) {
+ Drawable overlay = null;
+ if (animate) {
+ overlay = getOverlayDrawable(mStylePreview, true);
+ }
+
+ int pkgNameIdx = c.getColumnIndex(ThemesColumns.PKG_NAME);
+ int styleIdx = c.getColumnIndex(PreviewColumns.STYLE_PREVIEW);
+ mStylePreview.setImageBitmap(Utils.loadBitmapBlob(c, styleIdx));
+ if (pkgNameIdx > -1) {
+ String pkgName = c.getString(pkgNameIdx);
+ mSelectedComponentsMap.put(MODIFIES_OVERLAYS, pkgName);
+ }
+ if (animate) {
+ animateContentChange(R.id.style_card, mStylePreview, overlay);
+ }
+ }
+
+ private void loadBootAnimation(Cursor c, boolean autoStart) {
+ int pkgNameIdx = c.getColumnIndex(ThemesColumns.PKG_NAME);
+ if (mBootAnimation != null) {
+ String pkgName;
+ if (pkgNameIdx > -1) {
+ pkgName = c.getString(pkgNameIdx);
+ mSelectedComponentsMap.put(MODIFIES_BOOT_ANIM, pkgName);
+ } else {
+ pkgName = mCurrentTheme.get(MODIFIES_BOOT_ANIM);
+ }
+ mBootAnimation.stop();
+ new AnimationLoader(getActivity(), pkgName, mBootAnimation, autoStart).execute();
+ }
+ }
+
+ private void loadAudible(int type, Cursor c, boolean animate) {
+ View audibleContainer = null;
+ ImageView playPause = null;
+ String component = null;
+ switch (type) {
+ case RingtoneManager.TYPE_RINGTONE:
+ audibleContainer = mRingtoneContainer;
+ playPause = mRingtonePlayPause;
+ component = MODIFIES_RINGTONES;
+ break;
+ case RingtoneManager.TYPE_NOTIFICATION:
+ audibleContainer = mNotificationContainer;
+ playPause = mNotificationPlayPause;
+ component = MODIFIES_NOTIFICATIONS;
+ break;
+ case RingtoneManager.TYPE_ALARM:
+ audibleContainer = mAlarmContainer;
+ playPause = mAlarmPlayPause;
+ component = MODIFIES_ALARMS;
+ break;
+ }
+ if (audibleContainer == null) return;
+ TextView label = (TextView) audibleContainer.findViewById(R.id.label);
+ label.setText(getAudibleLabel(type));
+
+ int pkgNameIdx = c.getColumnIndex(ThemesColumns.PKG_NAME);
+ int titleIdx = c.getColumnIndex(ThemesColumns.TITLE);
+ if (playPause == null) {
+ playPause =
+ (ImageView) audibleContainer.findViewById(R.id.play_pause);
+ }
+ TextView title = (TextView) audibleContainer.findViewById(R.id.audible_name);
+ MediaPlayer mp = mMediaPlayers.get(playPause);
+ if (mp == null) {
+ mp = new MediaPlayer();
+ }
+ if (pkgNameIdx > -1) {
+ String pkgName = c.getString(pkgNameIdx);
+ try {
+ AudioUtils.loadThemeAudible(getActivity(), type, pkgName, mp);
+ } catch (PackageManager.NameNotFoundException e) {
+ Log.w(TAG, "Unable to load sound for " + pkgName, e);
+ return;
+ }
+ title.setText(c.getString(titleIdx));
+ mSelectedComponentsMap.put(component, pkgName);
+ } else {
+ final Context context = getActivity();
+ Uri ringtoneUri;
+ try {
+ ringtoneUri = AudioUtils.loadDefaultAudible(context, type, mp);
+ } catch (IOException e) {
+ Log.w(TAG, "Unable to load default sound ", e);
+ return;
+ }
+ title.setText(RingtoneManager.getRingtone(context, ringtoneUri).getTitle(context));
+ }
+
+ playPause.setTag(mp);
+ mMediaPlayers.put(playPause, mp);
+ playPause.setOnClickListener(mPlayPauseClickListener);
+ mp.setOnCompletionListener(mPlayCompletionListener);
+ }
+
+ private Drawable getOverlayDrawable(View v, boolean requiresTransparency) {
+ if (!v.isDrawingCacheEnabled()) v.setDrawingCacheEnabled(true);
+ Bitmap cache = v.getDrawingCache(true).copy(
+ requiresTransparency ? Config.ARGB_8888 : Config.RGB_565, false);
+ Drawable d = cache != null ? new BitmapDrawable(getResources(), cache) : null;
+ v.destroyDrawingCache();
+
+ return d;
+ }
+
+ private String getAudibleLabel(int type) {
+ switch (type) {
+ case RingtoneManager.TYPE_RINGTONE:
+ return getString(R.string.ringtone_label);
+ case RingtoneManager.TYPE_NOTIFICATION:
+ return getString(R.string.notification_label);
+ case RingtoneManager.TYPE_ALARM:
+ return getString(R.string.alarm_label);
+ }
+ return null;
+ }
+
+ public static ComponentName[] getIconComponents(Context context) {
+ if (sIconComponents == null || sIconComponents.length == 0) {
+ sIconComponents = new ComponentName[]{COMPONENT_DIALER, COMPONENT_MESSAGING,
+ COMPONENT_CAMERA, COMPONENT_BROWSER};
+
+ PackageManager pm = context.getPackageManager();
+
+ // if device does not have telephony replace dialer and mms
+ if (!pm.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)) {
+ sIconComponents[0] = COMPONENT_CALENDAR;
+ sIconComponents[1] = COMPONENT_GALERY;
+ }
+
+ if (!pm.hasSystemFeature(PackageManager.FEATURE_CAMERA)) {
+ sIconComponents[2] = COMPONENT_SETTINGS;
+ } else {
+ // decide on which camera icon to use
+ try {
+ if (pm.getPackageInfo(CAMERA_NEXT_PACKAGE, 0) != null) {
+ sIconComponents[2] = COMPONENT_CAMERANEXT;
+ }
+ } catch (PackageManager.NameNotFoundException e) {
+ // default to COMPONENT_CAMERA
+ }
+ }
+
+ }
+ return sIconComponents;
+ }
+
+ private void initCards(View parent) {
+ for (int i = 0; i < mCardIdsToComponentTypes.size(); i++) {
+ parent.findViewById(mCardIdsToComponentTypes.keyAt(i))
+ .setOnClickListener(mCardClickListener);
+ }
+ }
+
+ private View.OnClickListener mCardClickListener = new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ if (mActiveCardId > 0) {
+ mActiveCardId = -1;
+ getActivity().onBackPressed();
+ return;
+ }
+ mActiveCardId = v.getId();
+ String component = mCardIdsToComponentTypes.get(mActiveCardId);
+ ((ChooserActivity) getActivity()).showComponentSelector(component, v);
+ fadeOutNonSelectedCards(mActiveCardId);
+ stopMediaPlayers();
+ }
+ };
+
+ private OnItemClickedListener mOnComponentItemClicked = new OnItemClickedListener() {
+ @Override
+ public void onItemClicked(String pkgName) {
+ Bundle args = new Bundle();
+ args.putString("pkgName", pkgName);
+ int loaderId = -1;
+ String component = mSelector.getComponentType();
+ if (MODIFIES_STATUS_BAR.equals(component)) {
+ loaderId = LOADER_ID_STATUS_BAR;
+ } else if (MODIFIES_FONTS.equals(component)) {
+ loaderId = LOADER_ID_FONT;
+ } else if (MODIFIES_ICONS.equals(component)) {
+ loaderId = LOADER_ID_ICONS;
+ } else if (MODIFIES_NAVIGATION_BAR.equals(component)) {
+ loaderId = LOADER_ID_NAVIGATION_BAR;
+ } else if (MODIFIES_LAUNCHER.equals(component)) {
+ loaderId = LOADER_ID_WALLPAPER;
+ } else if (MODIFIES_LOCKSCREEN.equals(component)) {
+ loaderId = LOADER_ID_LOCKSCREEN;
+ } else if (MODIFIES_OVERLAYS.equals(component)) {
+ loaderId = LOADER_ID_STYLE;
+ } else if (MODIFIES_BOOT_ANIM.equals(component)) {
+ loaderId = LOADER_ID_BOOT_ANIMATION;
+ } else if (MODIFIES_RINGTONES.equals(component)) {
+ loaderId = LOADER_ID_RINGTONE;
+ } else if (MODIFIES_NOTIFICATIONS.equals(component)) {
+ loaderId = LOADER_ID_NOTIFICATION;
+ } else if (MODIFIES_ALARMS.equals(component)) {
+ loaderId = LOADER_ID_ALARM;
+ } else {
+ return;
+ }
+ getLoaderManager().restartLoader(loaderId, args, ThemeFragment.this);
+ }
+ };
+
+ private void fadeOutNonSelectedCards(int selectedCardId) {
+ for (int i = 0; i < mCardIdsToComponentTypes.size(); i++) {
+ if (mCardIdsToComponentTypes.keyAt(i) != selectedCardId) {
+ ComponentCardView card = (ComponentCardView) getView().findViewById(
+ mCardIdsToComponentTypes.keyAt(i));
+ card.animateCardFadeOut();
+ }
+ }
+ }
+
+ private void animateContentChange(int parentId, View viewToAnimate, Drawable overlay) {
+ ((ComponentCardView) getView().findViewById(parentId))
+ .animateContentChange(viewToAnimate, overlay, ANIMATE_COMPONENT_CHANGE_DURATION);
+ }
+
+ private Runnable mApplyThemeRunnable = new Runnable() {
+ @Override
+ public void run() {
+ final Context context = getActivity();
+ if (context != null) {
+ if (mSelectedComponentsMap != null && mSelectedComponentsMap.size() > 0) {
+ if (!CURRENTLY_APPLIED_THEME.equals(mPkgName)) {
+ ThemeUtils.completeComponentMap(getActivity(),
+ mSelectedComponentsMap);
+ }
+ // Post this on mHandler so the client is added and removed from the same
+ // thread
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ ThemeManager tm = getThemeManager();
+ if (tm != null) {
+ // if this is not the "my theme" card, add missing components
+ // from defaults
+ tm.addClient(ThemeFragment.this);
+ tm.requestThemeChange(mSelectedComponentsMap);
+ }
+ }
+ });
+ }
+ }
+ }
+ };
+
+ private void applyTheme() {
+ if (mSelectedComponentsMap == null || mSelectedComponentsMap.size() <= 0) return;
+ ((ChooserActivity) getActivity()).themeChangeStarted();
+ animateProgressIn(mApplyThemeRunnable);
+ }
+
+ private void animateProgressIn(Runnable endAction) {
+ mProgress.setVisibility(View.VISIBLE);
+ mProgress.setProgress(0);
+ float pivotX = mTitleLayout.getWidth() -
+ getResources().getDimensionPixelSize(R.dimen.apply_progress_padding);
+ ScaleAnimation scaleAnim = new ScaleAnimation(0f, 1f, 1f, 1f,
+ pivotX, 0f);
+ scaleAnim.setDuration(ANIMATE_PROGRESS_IN_DURATION);
+
+ mTitleLayout.animate()
+ .translationXBy(-(pivotX / 4))
+ .alpha(0f)
+ .setDuration(ANIMATE_TITLE_OUT_DURATION)
+ .setInterpolator(new AccelerateInterpolator())
+ .withEndAction(endAction).start();
+ mProgress.startAnimation(scaleAnim);
+ }
+
+ private void animateProgressOut() {
+ mProgress.setVisibility(View.VISIBLE);
+ float pivotX = mTitleLayout.getWidth() -
+ getResources().getDimensionPixelSize(R.dimen.apply_progress_padding);
+ ScaleAnimation scaleAnim = new ScaleAnimation(1f, 0f, 1f, 1f,
+ pivotX, 0f);
+ scaleAnim.setDuration(ANIMATE_PROGRESS_OUT_DURATION);
+ scaleAnim.setFillAfter(false);
+ scaleAnim.setAnimationListener(new Animation.AnimationListener() {
+ @Override
+ public void onAnimationStart(Animation animation) {
+ }
+
+ @Override
+ public void onAnimationEnd(Animation animation) {
+ mProgress.setVisibility(View.GONE);
+ }
+
+ @Override
+ public void onAnimationRepeat(Animation animation) {
+ }
+ });
+
+ mTitleLayout.animate()
+ .translationXBy((pivotX / 4))
+ .alpha(1f)
+ .setDuration(ANIMATE_TITLE_IN_DURATION)
+ .setInterpolator(new AccelerateInterpolator())
+ .start();
+ mProgress.startAnimation(scaleAnim);
+ }
+
+ private void animateContentIn() {
+ AnimatorSet set = new AnimatorSet();
+ set.setDuration(ANIMATE_TITLE_IN_DURATION);
+ set.play(ObjectAnimator.ofFloat(mLoadingView, "alpha", 1f, 0f))
+ .with(ObjectAnimator.ofFloat(mTitleLayout, "alpha", 0f, 1f));
+ set.addListener(new Animator.AnimatorListener() {
+ @Override
+ public void onAnimationStart(Animator animation) {
+ }
+
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mLoadingView.setVisibility(View.GONE);
+ }
+
+ @Override
+ public void onAnimationCancel(Animator animation) {
+ }
+
+ @Override
+ public void onAnimationRepeat(Animator animation) {
+ }
+ });
+ set.start();
+ }
+
+ public void fadeInCards() {
+ mActiveCardId = -1;
+ for (int i = 0; i < mCardIdsToComponentTypes.size(); i++) {
+ ComponentCardView card = (ComponentCardView) getView().findViewById(
+ mCardIdsToComponentTypes.keyAt(i));
+ card.animateCardFadeIn();
+ }
+ }
+
+ public boolean componentsChanged() {
+ for (String key : mSelectedComponentsMap.keySet()) {
+ if (!mPkgName.equals(mSelectedComponentsMap.get(key))) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public void clearChanges() {
+ mSelectedComponentsMap.clear();
+ getLoaderManager().restartLoader(LOADER_ID_ALL, null, ThemeFragment.this);
+ }
+
+ private void uninstallTheme() {
+ Uri packageURI = Uri.parse("package:" + mPkgName);
+ Intent uninstallIntent = new Intent(Intent.ACTION_UNINSTALL_PACKAGE, packageURI);
+ uninstallIntent.putExtra(Intent.EXTRA_UNINSTALL_ALL_USERS, true);
+ startActivityForResult(uninstallIntent,
+ ChooserActivity.REQUEST_UNINSTALL);
+ }
+
+ public void onActivityResult (int requestCode, int resultCode, Intent data) {
+ if (requestCode == REQUEST_UNINSTALL) {
+ try {
+ ApplicationInfo ainfo = getActivity()
+ .getPackageManager().getApplicationInfo(mPkgName, 0);
+ } catch (PackageManager.NameNotFoundException e) {
+ mIsUninstalled = true;
+ }
+ }
+ }
+
+ public boolean isUninstalled() {
+ return mIsUninstalled;
+ }
+
+ public void setCurrentTheme(Map<String, String> currentTheme) {
+ mCurrentTheme = currentTheme;
+ }
+
+ class AnimationLoader extends AsyncTask<Void, Void, Boolean> {
+ Context mContext;
+ String mPkgName;
+ BootAniImageView mBootAnim;
+ boolean mAutoStart;
+
+ public AnimationLoader(Context context, String pkgName, BootAniImageView bootAnim) {
+ this(context, pkgName, bootAnim, false);
+ }
+
+ public AnimationLoader(Context context, String pkgName, BootAniImageView bootAnim,
+ boolean autoStart) {
+ mContext = context;
+ mPkgName = pkgName;
+ mBootAnim = bootAnim;
+ mAutoStart = autoStart;
+ }
+
+ @Override
+ protected void onPreExecute() {
+ super.onPreExecute();
+ }
+
+ @Override
+ protected Boolean doInBackground(Void... params) {
+ if (mContext == null) {
+ return Boolean.FALSE;
+ }
+ ZipFile zip = null;
+ if (ThemeConfig.HOLO_DEFAULT.equals(mPkgName)) {
+ try {
+ zip = new ZipFile(new File(BootAnimationHelper.SYSTEM_BOOT_ANI_PATH));
+ } catch (Exception e) {
+ Log.w(TAG, "Unable to load boot animation", e);
+ return Boolean.FALSE;
+ }
+ } else {
+ // check if the bootanimation is cached
+ File f = new File(mContext.getCacheDir(),
+ mPkgName + BootAnimationHelper.CACHED_SUFFIX);
+ if (!f.exists()) {
+ // go easy on cache storage and clear out any previous boot animations
+ BootAnimationHelper.clearBootAnimationCache(mContext);
+ try {
+ Context themeContext = mContext.createPackageContext(mPkgName, 0);
+ AssetManager am = themeContext.getAssets();
+ InputStream is = am.open("bootanimation/bootanimation.zip");
+ FileUtils.copyToFile(is, f);
+ is.close();
+ } catch (Exception e) {
+ Log.w(TAG, "Unable to load boot animation", e);
+ return Boolean.FALSE;
+ }
+ }
+ try {
+ zip = new ZipFile(f);
+ } catch (IOException e) {
+ Log.w(TAG, "Unable to load boot animation", e);
+ return Boolean.FALSE;
+ }
+ }
+ if (zip != null) {
+ mBootAnim.setBootAnimation(zip);
+ } else {
+ return Boolean.FALSE;
+ }
+ return Boolean.TRUE;
+ }
+
+ @Override
+ protected void onPostExecute(Boolean isSuccess) {
+ super.onPostExecute(isSuccess);
+ if (isSuccess && mAutoStart) {
+ mBootAnim.start();
+ }
+ }
+ }
+}