diff options
Diffstat (limited to 'src/com/cyngn/theme/util/BootAnimationHelper.java')
-rw-r--r-- | src/com/cyngn/theme/util/BootAnimationHelper.java | 253 |
1 files changed, 253 insertions, 0 deletions
diff --git a/src/com/cyngn/theme/util/BootAnimationHelper.java b/src/com/cyngn/theme/util/BootAnimationHelper.java new file mode 100644 index 0000000..23ced7c --- /dev/null +++ b/src/com/cyngn/theme/util/BootAnimationHelper.java @@ -0,0 +1,253 @@ +/* + * 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.util; + +import android.app.ActivityManager; +import android.content.Context; +import android.content.res.ThemeConfig; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.os.AsyncTask; +import android.view.View; +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; +import java.io.InputStreamReader; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Enumeration; +import java.util.List; +import java.util.zip.ZipEntry; +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 { + /** + * Number of times to play this part + */ + public int playCount; + /** + * If non-zero, pause for the given # of seconds before moving on to next part. + */ + public int pause; + /** + * The name of this part + */ + public String partName; + /** + * Time each frame is displayed + */ + public int frameRateMillis; + /** + * List of file names for the given frames in this part + */ + public List<String> frames; + /** + * width of the animation + */ + public int width; + /** + * height of the animation + */ + public int height; + + public AnimationPart(int playCount, int pause, String partName, int frameRateMillis, + int width, int height) { + this.playCount = playCount == 0 ? MAX_REPEAT_COUNT : playCount; + this.pause = pause; + this.partName = partName; + this.frameRateMillis = frameRateMillis; + this.width = width; + this.height = height; + frames = new ArrayList<String>(); + } + + public void addFrame(String frame) { + frames.add(frame); + } + } + + /** + * Gather up all the details for the given boot animation + * @param context + * @param zip The bootanimation.zip + * @return A list of AnimationPart if successful, null if not. + * @throws IOException + */ + public static List<AnimationPart> parseAnimation(Context context, ZipFile zip) + throws IOException { + List<AnimationPart> animationParts = null; + + ZipEntry ze = zip.getEntry("desc.txt"); + if (ze != null) { + animationParts = parseDescription(zip.getInputStream(ze)); + } + + if (animationParts == null) return null; + + for (AnimationPart a : animationParts) { + for (Enumeration<? extends ZipEntry> e = zip.entries();e.hasMoreElements();) { + ze = e.nextElement(); + if (!ze.isDirectory() && ze.getName().contains(a.partName)) { + a.addFrame(ze.getName()); + } + } + Collections.sort(a.frames); + } + + return animationParts; + } + + /** + * Parses the desc.txt of the boot animation + * @param in InputStream to the desc.txt + * @return A list of the parts as given in desc.txt + * @throws IOException + */ + private static List<AnimationPart> parseDescription(InputStream in) throws IOException { + BufferedReader reader = new BufferedReader(new InputStreamReader(in)); + String line = reader.readLine(); + String[] details = line.split(" "); + final int width = Integer.parseInt(details[0]); + final int height = Integer.parseInt(details[1]); + final int frameRateMillis = 1000 / Integer.parseInt(details[2]); + + List<AnimationPart> animationParts = new ArrayList<AnimationPart>(); + while ((line = reader.readLine()) != null) { + String[] info = line.split(" "); + if (info.length == 4 && (info[0].equals("p") || info[0].equals("c"))) { + int playCount = Integer.parseInt(info[1]); + int pause = Integer.parseInt(info[2]); + String name = info[3]; + AnimationPart ap = new AnimationPart(playCount, pause, name, frameRateMillis, + width, height); + animationParts.add(ap); + } + } + + return animationParts; + } + + public static String getPreviewFrameEntryName(InputStream is) throws IOException { + ZipInputStream zis = (is instanceof ZipInputStream) ? (ZipInputStream) is + : new ZipInputStream(new BufferedInputStream(is)); + ZipEntry ze; + // First thing to do is iterate over all the entries and the zip and store them + // for building the animations afterwards + String previewName = null; + while ((ze = zis.getNextEntry()) != null) { + final String entryName = ze.getName(); + if (entryName.contains("/") + && (entryName.endsWith(".png") || entryName.endsWith(".jpg"))) { + previewName = entryName; + } + } + + return previewName; + } + + public static Bitmap loadPreviewFrame(Context context, InputStream is, String previewName) + throws IOException { + ZipInputStream zis = (is instanceof ZipInputStream) ? (ZipInputStream) is + : new ZipInputStream(new BufferedInputStream(is)); + ZipEntry ze; + ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE); + BitmapFactory.Options opts = new BitmapFactory.Options(); + opts.inSampleSize = am.isLowRamDevice() ? 4 : 2; + opts.inPreferredConfig = Bitmap.Config.RGB_565; + // First thing to do is iterate over all the entries and the zip and store them + // for building the animations afterwards + Bitmap preview = null; + while ((ze = zis.getNextEntry()) != null && preview == null) { + final String entryName = ze.getName(); + if (entryName.equals(previewName)) { + preview = BitmapFactory.decodeStream(zis, null, opts); + } + } + zis.close(); + + 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; + private Context context; + + public LoadBootAnimationImage(ImageView imv, Context context, String path) { + this.imv = imv; + this.context = context; + this.path = path; + } + + @Override + protected Bitmap doInBackground(Object... params) { + Bitmap bitmap = null; + String previewName = null; + // this is ugly, ugly, ugly. Did I mention this is ugly? + try { + if (ThemeConfig.HOLO_DEFAULT.equals(path)) { + previewName = getPreviewFrameEntryName( + new FileInputStream(SYSTEM_BOOT_ANI_PATH)); + bitmap = loadPreviewFrame( + context, new FileInputStream(SYSTEM_BOOT_ANI_PATH), previewName); + } else { + final Context themeCtx = context.createPackageContext(path, 0); + previewName = getPreviewFrameEntryName( + themeCtx.getAssets().open("bootanimation/bootanimation.zip")); + bitmap = loadPreviewFrame(context, + themeCtx.getAssets().open("bootanimation/bootanimation.zip"), + previewName); + } + } catch (Exception e) { + // don't care since a null bitmap will be returned + e.printStackTrace(); + } + return bitmap; + } + + @Override + protected void onPostExecute(Bitmap result) { + if (result != null && imv != null) { + imv.setVisibility(View.VISIBLE); + imv.setImageBitmap(result); + } + } + } +} |