/* -*- Mode: Java; c-basic-offset: 4; tab-width: 4; indent-tabs-mode: nil; -*- * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ package org.mozilla.gecko; import android.content.Context; import android.content.SharedPreferences; import android.graphics.Bitmap; import android.util.Log; import org.mozilla.gecko.gfx.BitmapUtils; import org.mozilla.gecko.util.ThreadUtils; public class WebAppAllocator { private final String LOGTAG = "GeckoWebAppAllocator"; // The number of WebApp# and WEBAPP# activites/apps/intents private final static int MAX_WEB_APPS = 100; protected static GeckoApp sContext = null; protected static WebAppAllocator sInstance = null; public static WebAppAllocator getInstance() { return getInstance(GeckoApp.mAppContext); } public static synchronized WebAppAllocator getInstance(Context cx) { if (sInstance == null) { if (!(cx instanceof GeckoApp)) throw new RuntimeException("Context needs to be a GeckoApp"); sContext = (GeckoApp) cx; sInstance = new WebAppAllocator(cx); } // The marketplaceApp will run in this same process, but has a different context // Rather than just failing, we want to create a new Allocator instead if (cx != sContext) { sInstance = null; sContext = (GeckoApp) cx; sInstance = new WebAppAllocator(cx); } return sInstance; } SharedPreferences mPrefs; protected WebAppAllocator(Context context) { mPrefs = context.getSharedPreferences("webapps", Context.MODE_PRIVATE | Context.MODE_MULTI_PROCESS); } public static String appKey(int index) { return "app" + index; } static public String iconKey(int index) { return "icon" + index; } public synchronized int findAndAllocateIndex(String app, String name, String aIconData) { Bitmap icon = (aIconData != null) ? BitmapUtils.getBitmapFromDataURI(aIconData) : null; return findAndAllocateIndex(app, name, icon); } public synchronized int findAndAllocateIndex(final String app, final String name, final Bitmap aIcon) { int index = getIndexForApp(app); if (index != -1) return index; for (int i = 0; i < MAX_WEB_APPS; ++i) { if (!mPrefs.contains(appKey(i))) { // found unused index i updateAppAllocation(app, i, aIcon); return i; } } // no more apps! return -1; } public synchronized void updateAppAllocation(final String app, final int index, final Bitmap aIcon) { if (aIcon != null) { ThreadUtils.getBackgroundHandler().post(new Runnable() { @Override public void run() { int color = 0; try { color = BitmapUtils.getDominantColor(aIcon); } catch (Exception e) { Log.e(LOGTAG, "Exception during getDominantColor", e); } mPrefs.edit() .putString(appKey(index), app) .putInt(iconKey(index), color).commit(); } }); } else { mPrefs.edit() .putString(appKey(index), app) .putInt(iconKey(index), 0).commit(); } } public synchronized int getIndexForApp(String app) { for (int i = 0; i < MAX_WEB_APPS; ++i) { if (mPrefs.getString(appKey(i), "").equals(app)) { return i; } } return -1; } public synchronized String getAppForIndex(int index) { return mPrefs.getString(appKey(index), null); } public synchronized int releaseIndexForApp(String app) { int index = getIndexForApp(app); if (index == -1) return -1; releaseIndex(index); return index; } public synchronized void releaseIndex(final int index) { ThreadUtils.postToBackgroundThread(new Runnable() { @Override public void run() { mPrefs.edit() .remove(appKey(index)) .remove(iconKey(index)) .commit(); } }); } }