diff options
Diffstat (limited to 'gallerycommon/src/com/android')
8 files changed, 494 insertions, 31 deletions
diff --git a/gallerycommon/src/com/android/gallery3d/common/ApiHelper.java b/gallerycommon/src/com/android/gallery3d/common/ApiHelper.java index 406c5263c..418e3cdd2 100644 --- a/gallerycommon/src/com/android/gallery3d/common/ApiHelper.java +++ b/gallerycommon/src/com/android/gallery3d/common/ApiHelper.java @@ -16,7 +16,6 @@ package com.android.gallery3d.common; -import android.app.Activity; import android.app.admin.DevicePolicyManager; import android.content.ComponentName; import android.hardware.Camera; @@ -36,6 +35,7 @@ public class ApiHelper { public static final int ICE_CREAM_SANDWICH = 14; public static final int ICE_CREAM_SANDWICH_MR1 = 15; public static final int JELLY_BEAN = 16; + public static final int JELLY_BEAN_MR1 = 17; } public static final boolean ENABLE_PHOTO_EDITOR = @@ -75,9 +75,6 @@ public class ApiHelper { public static final boolean HAS_AUTO_FOCUS_MOVE_CALLBACK = Build.VERSION.SDK_INT >= VERSION_CODES.JELLY_BEAN; - public static final boolean HAS_ACTIVITY_INVALIDATE_OPTIONS_MENU = - hasMethod(Activity.class, "invalidateOptionsMenu"); - public static final boolean HAS_REMOTE_VIEWS_SERVICE = Build.VERSION.SDK_INT >= VERSION_CODES.HONEYCOMB; @@ -109,8 +106,8 @@ public class ApiHelper { public static final boolean HAS_MEDIA_ACTION_SOUND = Build.VERSION.SDK_INT >= VERSION_CODES.JELLY_BEAN; - public static final boolean HAS_PANORAMA = - Build.VERSION.SDK_INT >= VERSION_CODES.HONEYCOMB; + public static final boolean HAS_OLD_PANORAMA = + Build.VERSION.SDK_INT >= VERSION_CODES.ICE_CREAM_SANDWICH; public static final boolean HAS_TIME_LAPSE_RECORDING = Build.VERSION.SDK_INT >= VERSION_CODES.HONEYCOMB; @@ -130,46 +127,46 @@ public class ApiHelper { public static final boolean HAS_MOTION_EVENT_TRANSFORM = Build.VERSION.SDK_INT >= VERSION_CODES.HONEYCOMB; - public static final boolean HAS_SHARE_ACTION_PROVIDER = - Build.VERSION.SDK_INT >= VERSION_CODES.ICE_CREAM_SANDWICH; - - public static final boolean HAS_EFFECTS_RECORDING = - Build.VERSION.SDK_INT >= VERSION_CODES.JELLY_BEAN; + public static final boolean HAS_EFFECTS_RECORDING = false; public static final boolean HAS_GET_SUPPORTED_VIDEO_SIZE = Build.VERSION.SDK_INT >= VERSION_CODES.HONEYCOMB; - public static int getIntFieldIfExists(Class<?> klass, String fieldName, - Class<?> obj, int defaultVal) { - try { - Field f = klass.getDeclaredField(fieldName); - return f.getInt(obj); - } catch (Exception e) { - return defaultVal; - } - } - public static final boolean HAS_SET_ICON_ATTRIBUTE = Build.VERSION.SDK_INT >= VERSION_CODES.HONEYCOMB; - public static final boolean HAS_ACTION_BAR_SET_LOGO = - Build.VERSION.SDK_INT >= VERSION_CODES.ICE_CREAM_SANDWICH; - - public static final boolean HAS_ACTION_BAR_SET_HOME_BUTTON_ENABLED = - Build.VERSION.SDK_INT >= VERSION_CODES.ICE_CREAM_SANDWICH; - public static final boolean HAS_MEDIA_PROVIDER_FILES_TABLE = Build.VERSION.SDK_INT >= VERSION_CODES.HONEYCOMB; public static final boolean HAS_SURFACE_TEXTURE_RECORDING = Build.VERSION.SDK_INT >= VERSION_CODES.JELLY_BEAN; - public static final boolean HAS_MENU_ITEM_SHOW_AS_ACTION = + public static final boolean HAS_ACTION_BAR = Build.VERSION.SDK_INT >= VERSION_CODES.HONEYCOMB; - public static final boolean HAS_ACTION_BAR = + // Ex: View.setTranslationX. + public static final boolean HAS_VIEW_TRANSFORM_PROPERTIES = Build.VERSION.SDK_INT >= VERSION_CODES.HONEYCOMB; + public static final boolean HAS_CAMERA_HDR = + Build.VERSION.SDK_INT >= VERSION_CODES.JELLY_BEAN_MR1; + + public static final boolean CAN_START_PREVIEW_IN_JPEG_CALLBACK = + Build.VERSION.SDK_INT >= VERSION_CODES.ICE_CREAM_SANDWICH; + + public static final boolean CAN_USE_FLAG_SECURE = + Build.VERSION.SDK_INT >= VERSION_CODES.HONEYCOMB; + + public static int getIntFieldIfExists(Class<?> klass, String fieldName, + Class<?> obj, int defaultVal) { + try { + Field f = klass.getDeclaredField(fieldName); + return f.getInt(obj); + } catch (Exception e) { + return defaultVal; + } + } + private static boolean hasField(Class<?> klass, String fieldName) { try { klass.getDeclaredField(fieldName); diff --git a/gallerycommon/src/com/android/gallery3d/common/HttpClientFactory.java b/gallerycommon/src/com/android/gallery3d/common/HttpClientFactory.java index 9e327aa51..18b7a8875 100644 --- a/gallerycommon/src/com/android/gallery3d/common/HttpClientFactory.java +++ b/gallerycommon/src/com/android/gallery3d/common/HttpClientFactory.java @@ -121,7 +121,7 @@ public final class HttpClientFactory { Build.DEVICE, Build.MODEL, Build.ID, - Build.VERSION.SDK, + Build.VERSION.SDK_INT, Build.VERSION.RELEASE, Build.VERSION.INCREMENTAL); } diff --git a/gallerycommon/src/com/android/gallery3d/common/LightCycleHelper.java b/gallerycommon/src/com/android/gallery3d/common/LightCycleHelper.java new file mode 100644 index 000000000..c4fb61a52 --- /dev/null +++ b/gallerycommon/src/com/android/gallery3d/common/LightCycleHelper.java @@ -0,0 +1,97 @@ +/* + * Copyright (C) 2012 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.gallery3d.common; + +import android.app.Activity; +import android.content.Context; +import android.content.Intent; +import android.content.pm.PackageManager; +import android.net.Uri; + +public class LightCycleHelper { + public static final String EXTRA_OUTPUT_DIR = "output_dir"; + private static final String PANORAMA_FILENAME_PREFIX = "panorama_"; + public static final String LIGHTCYCLE_PACKAGE = + "com.google.android.apps.lightcycle"; + public static final String LIGHTCYCLE_CAPTURE_CLASS = + "com.google.android.apps.lightcycle.PanoramaCaptureActivity"; + private static final String LIGHTCYCLE_VIEW_CLASS = + "com.google.android.apps.lightcycle.PanoramaViewActivity"; + + private static boolean sUpdated; + private static boolean sHasViewActivity; + private static boolean sHasCaptureActivity; + + private static boolean hasLightCycleActivity(PackageManager pm, String activityClass) { + Intent it = new Intent(); + it.setClassName(LIGHTCYCLE_PACKAGE, activityClass); + return (pm.resolveActivity(it, 0) != null); + } + + private static void update(PackageManager pm) { + sUpdated = true; + sHasViewActivity = hasLightCycleActivity(pm, LIGHTCYCLE_VIEW_CLASS); + sHasCaptureActivity = hasLightCycleActivity(pm, LIGHTCYCLE_CAPTURE_CLASS); + } + + public static synchronized boolean hasLightCycleView(PackageManager pm) { + if (!sUpdated) { + update(pm); + } + return sHasViewActivity; + } + + public static synchronized boolean hasLightCycleCapture(PackageManager pm) { + if (!sUpdated) { + update(pm); + } + return sHasCaptureActivity; + } + + public static synchronized void onPackageAdded(Context context, String packageName) { + if (LIGHTCYCLE_PACKAGE.equals(packageName)) { + update(context.getPackageManager()); + } + } + + public static synchronized void onPackageRemoved(Context context, String packageName) { + if (LIGHTCYCLE_PACKAGE.equals(packageName)) { + update(context.getPackageManager()); + } + } + + public static synchronized void onPackageChanged(Context context, String packageName) { + if (LIGHTCYCLE_PACKAGE.equals(packageName)) { + update(context.getPackageManager()); + } + } + + public static void viewPanorama(Activity activity, Uri uri, String type) { + try { + Intent intent = new Intent(Intent.ACTION_VIEW) + .setDataAndType(uri, type) + .setClassName(LIGHTCYCLE_PACKAGE, LIGHTCYCLE_VIEW_CLASS); + activity.startActivity(intent); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + public static boolean isPanorama(String filename) { + return filename.startsWith(PANORAMA_FILENAME_PREFIX); + } +} diff --git a/gallerycommon/src/com/android/gallery3d/common/Utils.java b/gallerycommon/src/com/android/gallery3d/common/Utils.java index 391b22535..f5a266706 100644 --- a/gallerycommon/src/com/android/gallery3d/common/Utils.java +++ b/gallerycommon/src/com/android/gallery3d/common/Utils.java @@ -310,7 +310,7 @@ public class Utils { Build.DEVICE, Build.MODEL, Build.ID, - Build.VERSION.SDK, + Build.VERSION.SDK_INT, Build.VERSION.RELEASE, Build.VERSION.INCREMENTAL); } diff --git a/gallerycommon/src/com/android/gallery3d/util/Future.java b/gallerycommon/src/com/android/gallery3d/util/Future.java new file mode 100644 index 000000000..580a2a120 --- /dev/null +++ b/gallerycommon/src/com/android/gallery3d/util/Future.java @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2010 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.gallery3d.util; + +// This Future differs from the java.util.concurrent.Future in these aspects: +// +// - Once cancel() is called, isCancelled() always returns true. It is a sticky +// flag used to communicate to the implementation. The implmentation may +// ignore that flag. Regardless whether the Future is cancelled, a return +// value will be provided to get(). The implementation may choose to return +// null if it finds the Future is cancelled. +// +// - get() does not throw exceptions. +// +public interface Future<T> { + public void cancel(); + public boolean isCancelled(); + public boolean isDone(); + public T get(); + public void waitDone(); +} diff --git a/gallerycommon/src/com/android/gallery3d/util/FutureListener.java b/gallerycommon/src/com/android/gallery3d/util/FutureListener.java new file mode 100644 index 000000000..ed1f820c7 --- /dev/null +++ b/gallerycommon/src/com/android/gallery3d/util/FutureListener.java @@ -0,0 +1,21 @@ +/* + * Copyright (C) 2010 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.gallery3d.util; + +public interface FutureListener<T> { + public void onFutureDone(Future<T> future); +} diff --git a/gallerycommon/src/com/android/gallery3d/util/PriorityThreadFactory.java b/gallerycommon/src/com/android/gallery3d/util/PriorityThreadFactory.java new file mode 100644 index 000000000..30d8e4a96 --- /dev/null +++ b/gallerycommon/src/com/android/gallery3d/util/PriorityThreadFactory.java @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2010 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.gallery3d.util; + + +import android.os.Process; + +import java.util.concurrent.ThreadFactory; +import java.util.concurrent.atomic.AtomicInteger; + +/** + * A thread factory that creates threads with a given thread priority. + */ +public class PriorityThreadFactory implements ThreadFactory { + + private final int mPriority; + private final AtomicInteger mNumber = new AtomicInteger(); + private final String mName; + + public PriorityThreadFactory(String name, int priority) { + mName = name; + mPriority = priority; + } + + @Override + public Thread newThread(Runnable r) { + return new Thread(r, mName + '-' + mNumber.getAndIncrement()) { + @Override + public void run() { + Process.setThreadPriority(mPriority); + super.run(); + } + }; + } + +} diff --git a/gallerycommon/src/com/android/gallery3d/util/ThreadPool.java b/gallerycommon/src/com/android/gallery3d/util/ThreadPool.java new file mode 100644 index 000000000..cada234b3 --- /dev/null +++ b/gallerycommon/src/com/android/gallery3d/util/ThreadPool.java @@ -0,0 +1,264 @@ +/* + * Copyright (C) 2010 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.gallery3d.util; + +import android.util.Log; + +import java.util.concurrent.Executor; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; + +public class ThreadPool { + @SuppressWarnings("unused") + private static final String TAG = "ThreadPool"; + private static final int CORE_POOL_SIZE = 4; + private static final int MAX_POOL_SIZE = 8; + private static final int KEEP_ALIVE_TIME = 10; // 10 seconds + + // Resource type + public static final int MODE_NONE = 0; + public static final int MODE_CPU = 1; + public static final int MODE_NETWORK = 2; + + public static final JobContext JOB_CONTEXT_STUB = new JobContextStub(); + + ResourceCounter mCpuCounter = new ResourceCounter(2); + ResourceCounter mNetworkCounter = new ResourceCounter(2); + + // A Job is like a Callable, but it has an addition JobContext parameter. + public interface Job<T> { + public T run(JobContext jc); + } + + public interface JobContext { + boolean isCancelled(); + void setCancelListener(CancelListener listener); + boolean setMode(int mode); + } + + private static class JobContextStub implements JobContext { + @Override + public boolean isCancelled() { + return false; + } + + @Override + public void setCancelListener(CancelListener listener) { + } + + @Override + public boolean setMode(int mode) { + return true; + } + } + + public interface CancelListener { + public void onCancel(); + } + + private static class ResourceCounter { + public int value; + public ResourceCounter(int v) { + value = v; + } + } + + private final Executor mExecutor; + + public ThreadPool() { + mExecutor = new ThreadPoolExecutor( + CORE_POOL_SIZE, MAX_POOL_SIZE, KEEP_ALIVE_TIME, + TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>(), + new PriorityThreadFactory("thread-pool", + android.os.Process.THREAD_PRIORITY_BACKGROUND)); + } + + // Submit a job to the thread pool. The listener will be called when the + // job is finished (or cancelled). + public <T> Future<T> submit(Job<T> job, FutureListener<T> listener) { + Worker<T> w = new Worker<T>(job, listener); + mExecutor.execute(w); + return w; + } + + public <T> Future<T> submit(Job<T> job) { + return submit(job, null); + } + + private class Worker<T> implements Runnable, Future<T>, JobContext { + @SuppressWarnings("hiding") + private static final String TAG = "Worker"; + private Job<T> mJob; + private FutureListener<T> mListener; + private CancelListener mCancelListener; + private ResourceCounter mWaitOnResource; + private volatile boolean mIsCancelled; + private boolean mIsDone; + private T mResult; + private int mMode; + + public Worker(Job<T> job, FutureListener<T> listener) { + mJob = job; + mListener = listener; + } + + // This is called by a thread in the thread pool. + @Override + public void run() { + T result = null; + + // A job is in CPU mode by default. setMode returns false + // if the job is cancelled. + if (setMode(MODE_CPU)) { + try { + result = mJob.run(this); + } catch (Throwable ex) { + Log.w(TAG, "Exception in running a job", ex); + } + } + + synchronized(this) { + setMode(MODE_NONE); + mResult = result; + mIsDone = true; + notifyAll(); + } + if (mListener != null) mListener.onFutureDone(this); + } + + // Below are the methods for Future. + @Override + public synchronized void cancel() { + if (mIsCancelled) return; + mIsCancelled = true; + if (mWaitOnResource != null) { + synchronized (mWaitOnResource) { + mWaitOnResource.notifyAll(); + } + } + if (mCancelListener != null) { + mCancelListener.onCancel(); + } + } + + @Override + public boolean isCancelled() { + return mIsCancelled; + } + + @Override + public synchronized boolean isDone() { + return mIsDone; + } + + @Override + public synchronized T get() { + while (!mIsDone) { + try { + wait(); + } catch (Exception ex) { + Log.w(TAG, "ingore exception", ex); + // ignore. + } + } + return mResult; + } + + @Override + public void waitDone() { + get(); + } + + // Below are the methods for JobContext (only called from the + // thread running the job) + @Override + public synchronized void setCancelListener(CancelListener listener) { + mCancelListener = listener; + if (mIsCancelled && mCancelListener != null) { + mCancelListener.onCancel(); + } + } + + @Override + public boolean setMode(int mode) { + // Release old resource + ResourceCounter rc = modeToCounter(mMode); + if (rc != null) releaseResource(rc); + mMode = MODE_NONE; + + // Acquire new resource + rc = modeToCounter(mode); + if (rc != null) { + if (!acquireResource(rc)) { + return false; + } + mMode = mode; + } + + return true; + } + + private ResourceCounter modeToCounter(int mode) { + if (mode == MODE_CPU) { + return mCpuCounter; + } else if (mode == MODE_NETWORK) { + return mNetworkCounter; + } else { + return null; + } + } + + private boolean acquireResource(ResourceCounter counter) { + while (true) { + synchronized (this) { + if (mIsCancelled) { + mWaitOnResource = null; + return false; + } + mWaitOnResource = counter; + } + + synchronized (counter) { + if (counter.value > 0) { + counter.value--; + break; + } else { + try { + counter.wait(); + } catch (InterruptedException ex) { + // ignore. + } + } + } + } + + synchronized (this) { + mWaitOnResource = null; + } + + return true; + } + + private void releaseResource(ResourceCounter counter) { + synchronized (counter) { + counter.value++; + counter.notifyAll(); + } + } + } +} |