summaryrefslogtreecommitdiffstats
path: root/src/org/cyanogenmod/theme
diff options
context:
space:
mode:
authorClark Scheff <clark@cyngn.com>2014-07-23 22:17:41 +0000
committerGerrit Code Review <gerrit@cyngn.com>2014-07-23 22:17:41 +0000
commit9278bdf94666cd7df51c444bf5bfb1c4e8f3a1e0 (patch)
tree5ac48a00a531fd2293b76bb7e88c360adbf262cf /src/org/cyanogenmod/theme
parent698d99ea5cbd68a56f768d8cc04bda8abd5417f2 (diff)
parent711e7480eef4e684d0c53e905377fc521f878068 (diff)
downloadpackages_apps_ThemeChooser-9278bdf94666cd7df51c444bf5bfb1c4e8f3a1e0.zip
packages_apps_ThemeChooser-9278bdf94666cd7df51c444bf5bfb1c4e8f3a1e0.tar.gz
packages_apps_ThemeChooser-9278bdf94666cd7df51c444bf5bfb1c4e8f3a1e0.tar.bz2
Merge "Add boot animation card." into cm-11.0
Diffstat (limited to 'src/org/cyanogenmod/theme')
-rw-r--r--src/org/cyanogenmod/theme/chooserv2/ThemeFragment.java149
-rw-r--r--src/org/cyanogenmod/theme/util/BootAnimationHelper.java16
-rw-r--r--src/org/cyanogenmod/theme/widget/BootAniImageView.java59
3 files changed, 205 insertions, 19 deletions
diff --git a/src/org/cyanogenmod/theme/chooserv2/ThemeFragment.java b/src/org/cyanogenmod/theme/chooserv2/ThemeFragment.java
index 95f2c9c..09c95a2 100644
--- a/src/org/cyanogenmod/theme/chooserv2/ThemeFragment.java
+++ b/src/org/cyanogenmod/theme/chooserv2/ThemeFragment.java
@@ -22,6 +22,7 @@ import android.content.ComponentName;
import android.content.Context;
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;
@@ -36,7 +37,9 @@ import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.NinePatchDrawable;
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;
@@ -46,6 +49,7 @@ 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.LayoutInflater;
@@ -61,22 +65,30 @@ import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ProgressBar;
import android.widget.RelativeLayout;
-import android.widget.Space;
+
+import android.widget.ScrollView;
import android.widget.TextView;
import org.cyanogenmod.theme.chooser.R;
import org.cyanogenmod.theme.chooserv2.ComponentSelector.OnItemClickedListener;
+import org.cyanogenmod.theme.util.BootAnimationHelper;
import org.cyanogenmod.theme.util.IconPreviewHelper;
import org.cyanogenmod.theme.util.ThemedTypefaceHelper;
import org.cyanogenmod.theme.util.TypefaceHelperCache;
import org.cyanogenmod.theme.util.Utils;
+import org.cyanogenmod.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_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_OVERLAYS;
@@ -87,6 +99,8 @@ 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;
@@ -127,6 +141,7 @@ public class ThemeFragment extends Fragment implements LoaderManager.LoaderCallb
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_APPLIED = 20;
private static ComponentName[] sIconComponents;
@@ -140,7 +155,7 @@ public class ThemeFragment extends Fragment implements LoaderManager.LoaderCallb
private Typeface mTypefaceNormal;
private int mBatteryStyle;
- private ViewGroup mScrollView;
+ private ScrollView mScrollView;
private ViewGroup mScrollContent;
private ViewGroup mPreviewContent; // Contains icons, font, nav/status etc. Not wallpaper
@@ -158,6 +173,8 @@ public class ThemeFragment extends Fragment implements LoaderManager.LoaderCallb
private TextView mFontPreview;
private ViewGroup mIconContainer;
private ViewGroup mStyleContainer;
+ private ViewGroup mBootAnimationContainer;
+ private BootAniImageView mBootAnimation;
// Nav Bar Views
private ViewGroup mNavBar;
@@ -198,6 +215,7 @@ public class ThemeFragment extends Fragment implements LoaderManager.LoaderCallb
sCardIdsToComponentTypes.put(R.id.wallpaper_card, MODIFIES_LAUNCHER);
sCardIdsToComponentTypes.put(R.id.lockscreen_card, MODIFIES_LOCKSCREEN);
sCardIdsToComponentTypes.put(R.id.style_card, MODIFIES_OVERLAYS);
+ sCardIdsToComponentTypes.put(R.id.bootani_preview_container, MODIFIES_BOOT_ANIM);
}
static ThemeFragment newInstance(String pkgName) {
@@ -232,7 +250,7 @@ public class ThemeFragment extends Fragment implements LoaderManager.LoaderCallb
Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.v2_fragment_pager_list, container, false);
- mScrollView = (ViewGroup) v.findViewById(android.R.id.list);
+ mScrollView = (ScrollView) v.findViewById(android.R.id.list);
mScrollContent = (ViewGroup) mScrollView.getChildAt(0);
mPreviewContent = (ViewGroup) v.findViewById(R.id.preview_container);
@@ -252,6 +270,9 @@ public class ThemeFragment extends Fragment implements LoaderManager.LoaderCallb
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);
// Nav Bar
mNavBar = (ViewGroup) v.findViewById(R.id.navigation_bar);
@@ -383,6 +404,7 @@ public class ThemeFragment extends Fragment implements LoaderManager.LoaderCallb
animateExtras(true);
mSelector = ((ChooserActivity) getActivity()).getComponentSelector();
mSelector.setOnItemClickedListener(mOnComponentItemClicked);
+ if (mBootAnimation != null) mBootAnimation.start();
}
@@ -486,6 +508,7 @@ public class ThemeFragment extends Fragment implements LoaderManager.LoaderCallb
animateExtras(false);
animateWallpaperIn();
animateTitleCard(false, applyTheme);
+ if (mBootAnimation != null) mBootAnimation.stop();
}
// This will animate the children's vertical positions between the previous bounds and the
@@ -868,6 +891,12 @@ public class ThemeFragment extends Fragment implements LoaderManager.LoaderCallb
PreviewColumns.STYLE_PREVIEW
};
break;
+ case LOADER_ID_BOOT_ANIMATION:
+ projection = new String[] {
+ ThemesColumns.PKG_NAME,
+ ThemesColumns.TITLE
+ };
+ break;
case LOADER_ID_APPLIED:
//TODO: Mix n match query should only be done once
uri = ThemesContract.MixnMatchColumns.CONTENT_URI;
@@ -892,7 +921,6 @@ public class ThemeFragment extends Fragment implements LoaderManager.LoaderCallb
loadTitle(c);
loadFont(c, false);
loadAndRemoveAdditionalCards(c);
- loadStyle(c, false);
break;
case LOADER_ID_STATUS_BAR:
loadStatusBar(c, true);
@@ -915,6 +943,9 @@ public class ThemeFragment extends Fragment implements LoaderManager.LoaderCallb
case LOADER_ID_STYLE:
loadStyle(c, true);
break;
+ case LOADER_ID_BOOT_ANIMATION:
+ loadBootAnimation(c, true);
+ break;
case LOADER_ID_APPLIED:
getLoaderManager().initLoader(LOADER_ID_ALL, null, this);
populateCurrentTheme(c);
@@ -931,6 +962,9 @@ public class ThemeFragment extends Fragment implements LoaderManager.LoaderCallb
loadAdditionalCard(c, component);
} else {
removeList.add(v);
+ // remove the Space below this card
+ removeList.add(mAdditionalCards.getChildAt(i+1));
+ sCardIdsToComponentTypes.remove(v.getId());
}
}
}
@@ -956,6 +990,8 @@ public class ThemeFragment extends Fragment implements LoaderManager.LoaderCallb
loadWallpaper(c);
} else if (MODIFIES_OVERLAYS.equals(component)) {
loadStyle(c, false);
+ } else if (MODIFIES_BOOT_ANIM.equals(component)) {
+ loadBootAnimation(c, false);
} else {
throw new IllegalArgumentException("Don't know how to load: " +component);
}
@@ -979,6 +1015,9 @@ public class ThemeFragment extends Fragment implements LoaderManager.LoaderCallb
mSelectedComponentsMap.put(component, pkg);
}
}
+ if (!mSelectedComponentsMap.containsKey(MODIFIES_BOOT_ANIM)) {
+ mBootAnimation = null;
+ }
}
private void populateCurrentTheme(Cursor c) {
@@ -1248,6 +1287,21 @@ public class ThemeFragment extends Fragment implements LoaderManager.LoaderCallb
}
}
+ 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 Drawable getOverlayDrawable(View v, boolean requiresTransparency) {
if (!v.isDrawingCacheEnabled()) v.setDrawingCacheEnabled(true);
Bitmap cache = v.getDrawingCache(true).copy(
@@ -1331,6 +1385,8 @@ public class ThemeFragment extends Fragment implements LoaderManager.LoaderCallb
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 {
return;
}
@@ -1458,4 +1514,89 @@ public class ThemeFragment extends Fragment implements LoaderManager.LoaderCallb
mSelectedComponentsMap.clear();
getLoaderManager().restartLoader(LOADER_ID_ALL, null, ThemeFragment.this);
}
+
+ 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();
+ mBootAnim.setImageDrawable(null);
+ }
+
+ @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();
+ mScrollView.postDelayed(new Runnable() {
+ @Override
+ public void run() {
+ mScrollView.fullScroll(View.FOCUS_DOWN);
+ }
+ }, 10);
+ }
+ }
+ }
}
diff --git a/src/org/cyanogenmod/theme/util/BootAnimationHelper.java b/src/org/cyanogenmod/theme/util/BootAnimationHelper.java
index 1e0fafa..6d18ffb 100644
--- a/src/org/cyanogenmod/theme/util/BootAnimationHelper.java
+++ b/src/org/cyanogenmod/theme/util/BootAnimationHelper.java
@@ -26,6 +26,7 @@ import android.widget.ImageView;
import java.io.BufferedInputStream;
import java.io.BufferedReader;
+import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
@@ -39,9 +40,12 @@ import java.util.zip.ZipFile;
import java.util.zip.ZipInputStream;
public class BootAnimationHelper {
+ private static final int MAX_REPEAT_COUNT = 3;
+
public static final String THEME_INTERNAL_BOOT_ANI_PATH =
"assets/bootanimation/bootanimation.zip";
public static final String SYSTEM_BOOT_ANI_PATH = "/system/media/bootanimation.zip";
+ public static final String CACHED_SUFFIX = "_bootanimation.zip";
public static class AnimationPart {
/**
@@ -75,7 +79,7 @@ public class BootAnimationHelper {
public AnimationPart(int playCount, int pause, String partName, int frameRateMillis,
int width, int height) {
- this.playCount = playCount;
+ this.playCount = playCount == 0 ? MAX_REPEAT_COUNT : playCount;
this.pause = pause;
this.partName = partName;
this.frameRateMillis = frameRateMillis;
@@ -191,6 +195,16 @@ public class BootAnimationHelper {
return preview;
}
+ public static void clearBootAnimationCache(Context context) {
+ File cache = context.getCacheDir();
+ if (cache.exists()) {
+ for(File f : cache.listFiles()) {
+ // volley stores stuff in cache so don't delete the volley directory
+ if(!f.isDirectory() && f.getName().endsWith(CACHED_SUFFIX)) f.delete();
+ }
+ }
+ }
+
public static class LoadBootAnimationImage extends AsyncTask<Object, Void, Bitmap> {
private ImageView imv;
private String path;
diff --git a/src/org/cyanogenmod/theme/widget/BootAniImageView.java b/src/org/cyanogenmod/theme/widget/BootAniImageView.java
index 4b16be3..1682316 100644
--- a/src/org/cyanogenmod/theme/widget/BootAniImageView.java
+++ b/src/org/cyanogenmod/theme/widget/BootAniImageView.java
@@ -21,6 +21,7 @@ import android.graphics.BitmapFactory;
import android.util.AttributeSet;
import android.util.Log;
import android.widget.ImageView;
+import libcore.io.IoUtils;
import org.cyanogenmod.theme.util.BootAnimationHelper;
import java.io.IOException;
@@ -58,21 +59,31 @@ public class BootAniImageView extends ImageView {
}
@Override
- protected void onDetachedFromWindow() {
- super.onDetachedFromWindow();
- mActive = false;
- removeCallbacks(mUpdateAnimationRunnable);
+ public void setVisibility(int visibility) {
+ super.setVisibility(visibility);
+ if (visibility == VISIBLE) {
+ if (mBootAniZip != null) start();
+ } else {
+ stop();
+ }
+ }
+
+ public synchronized boolean setBootAnimation(ZipFile bootAni) {
+ // make sure we are stopped first
+ stop();
if (mBootAniZip != null) {
- try {
- mBootAniZip.close();
- } catch (IOException e) {
+ IoUtils.closeQuietly(mBootAniZip);
+ // This boot animation may be a different size than the previous
+ // one so clear out the buffers so they can be recreated with
+ // the correct size.
+ for (int i = 0; i < MAX_BUFFERS; i++) {
+ if (mBuffers[i] != null) {
+ mBuffers[i].recycle();
+ mBuffers[i] = null;
+ }
}
}
-
- }
-
- public boolean setBootAnimation(ZipFile bootAni) {
mBootAniZip = bootAni;
try {
mAnimationParts = BootAnimationHelper.parseAnimation(mContext, mBootAniZip);
@@ -84,6 +95,8 @@ public class BootAniImageView extends ImageView {
mCurrentPart = 0;
mCurrentPartPlayCount = part.playCount;
mFrameDuration = part.frameRateMillis;
+ mWriteBufferIndex = mReadBufferIndex = 0;
+ mCurrentFrame = 0;
getNextFrame();
@@ -94,6 +107,7 @@ public class BootAniImageView extends ImageView {
BitmapFactory.Options opts = new BitmapFactory.Options();
opts.inBitmap = mBuffers[mWriteBufferIndex];
opts.inPreferredConfig = Bitmap.Config.RGB_565;
+ opts.inMutable = true;
final BootAnimationHelper.AnimationPart part = mAnimationParts.get(mCurrentPart);
try {
mBuffers[mWriteBufferIndex] =
@@ -107,8 +121,11 @@ public class BootAniImageView extends ImageView {
if (mCurrentPartPlayCount > 0) {
if (--mCurrentPartPlayCount == 0) {
mCurrentPart++;
+ if (mCurrentPart >= mAnimationParts.size()) mCurrentPart = 0;
mCurrentFrame = 0;
mCurrentPartPlayCount = mAnimationParts.get(mCurrentPart).playCount;
+ } else {
+ mCurrentFrame = 0;
}
} else {
mCurrentFrame = 0;
@@ -121,14 +138,22 @@ public class BootAniImageView extends ImageView {
post(mUpdateAnimationRunnable);
}
+ public void stop() {
+ mActive = false;
+ removeCallbacks(mUpdateImageRunnable);
+ removeCallbacks(mUpdateAnimationRunnable);
+ }
+
private Runnable mUpdateAnimationRunnable = new Runnable() {
@Override
public void run() {
if (!mActive) return;
BootAniImageView.this.postDelayed(mUpdateAnimationRunnable, mFrameDuration);
- BootAniImageView.this.post(mUpdateImageRunnable);
- mReadBufferIndex = (mReadBufferIndex + 1) % MAX_BUFFERS;
- getNextFrame();
+ if (!isOffScreen()) {
+ BootAniImageView.this.post(mUpdateImageRunnable);
+ mReadBufferIndex = (mReadBufferIndex + 1) % MAX_BUFFERS;
+ getNextFrame();
+ }
}
};
@@ -138,4 +163,10 @@ public class BootAniImageView extends ImageView {
setImageBitmap(mBuffers[mReadBufferIndex]);
}
};
+
+ private boolean isOffScreen() {
+ int[] pos = new int[2];
+ getLocationOnScreen(pos);
+ return pos[1] >= mContext.getResources().getDisplayMetrics().heightPixels;
+ }
}