Back to project page Resonos-Android-Framework.
The source code is released under:
Apache License
If you think the Android project Resonos-Android-Framework listed in this page is inappropriate, such as containing malicious code/tools or violating the copyright, please email info at java2s dot com, thanks.
package com.resonos.apps.library; //from www.j a v a 2 s .c om import java.util.HashMap; import java.util.Map; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.ThreadFactory; import java.util.concurrent.atomic.AtomicInteger; import android.app.Activity; import android.content.Context; import android.content.pm.PackageInfo; import android.content.pm.PackageManager.NameNotFoundException; import android.content.res.Configuration; import android.os.Bundle; import android.os.Handler; import android.util.DisplayMetrics; import android.view.View; import android.view.Window; import android.widget.Toast; import com.flurry.android.FlurryAgent; import com.resonos.app.library.R; import com.resonos.apps.library.AlertFragment.AlertBuilder; import com.resonos.apps.library.util.AppUtils; import com.resonos.apps.library.util.ErrorReporter; import com.resonos.apps.library.util.M; import com.resonos.apps.library.util.NetworkClient; import com.resonos.apps.library.util.NetworkClient.OnServerResponseListener; import com.resonos.apps.library.util.NetworkRequest; import com.resonos.apps.library.widget.QuickAction3D; //---------------------------------------------------------------------- public abstract class App implements OnServerResponseListener { // constants public static boolean DEBUG, LANDSCAPE; public static float DENSITY; public static int SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_SIZE, SCREEN_XPIX, SCREEN_YPIX; public static String SCREEN_SIZE_STRING = "unknown"; public static final String GLOBAL_PREFERENCES = "_global_preferences"; public static final String STATE_OLD_VERSION = "oldVersion", STATE_NEW_VERSION = "newVersionID"; protected static final int DIALOG_USER_RATE = -748382; // context private Context cx; private FragmentBaseActivity activity = null; // objects public Handler mHandler = new Handler(); public NetworkClient mNetworkClient; public AppInfo mAppInfo; private Thread mUIThread; // static objects - these must have no activity references private static ExecutorService sExecutorService = null; private static ThreadFactory sThreadFactory = null; private static ErrorReporter sError = null; // local references to static objects public ExecutorService mExecutorService; public ErrorReporter mError; // state private boolean mOldVersion = false; public String mNewVersionID; // enum public enum NetworkActions {GET_INFO}; /** * This class contains fields to fill in about the overriding app * No need to fill in fields beginning with an underscore (_) */ public class AppInfo { // contants private static final int DEF_ASK_EVERY = 6; private static final int DEF_EX_THREAD_COUNT = 5; // these will be filled in automatically public String _packageName; public String _versionID; public int _versionCode; // info to supply public String appName; public String flurryID; public boolean debug = false; public String packageProName; public String contactEmailHelp; public String errorURL; public String infoURL; public int mFragmentContainerID; public int mRootID; public boolean useExecutorService = false; public boolean useNetworkClient = true; public boolean useNetworkGetInfo = true; /** set this var to 0 to never ask the user to rate the app */ public int askUserToRateEvery = DEF_ASK_EVERY; public int executorServiceThreadCount = DEF_EX_THREAD_COUNT; private void prepare() { try { _packageName = cx.getPackageName(); PackageInfo pkg = cx.getPackageManager().getPackageInfo(_packageName, 0); _versionID = pkg.versionName; _versionCode = pkg.versionCode; } catch (NameNotFoundException e) { _versionID = "Unknown"; _versionCode = -1; } } } /** * Create a new App, corresponds to the onCreate of the root activity or service * @param context, activity or service * @param appInfo, a filled out data structure * @param any additional parameter */ public App(Bundle savedInstanceState, Context context) { // separate out context and activity to allow for services, etc cx = context; if (cx instanceof FragmentBaseActivity) activity = (FragmentBaseActivity)cx; mUIThread = Thread.currentThread(); boolean firstRun = (savedInstanceState == null); // fill in the rest of the app info mAppInfo = new AppInfo(); getAppParameters(mAppInfo); mAppInfo.prepare(); // set some global vars DEBUG = mAppInfo.debug; readScreenConfiguration(); // set up exception handler if (sError == null) sError = new ErrorReporter(this); mError = sError; if (mAppInfo.useExecutorService || mAppInfo.useNetworkClient) { if (sThreadFactory == null) sThreadFactory = new ThreadFactory() { private static final String THREAD_FACTORY_TAG = "R Thread #"; private final AtomicInteger mCount = new AtomicInteger(1); public Thread newThread(Runnable r) { Thread t = new Thread(r, THREAD_FACTORY_TAG + mCount.getAndIncrement()); t.setUncaughtExceptionHandler(mError.getExceptionHandler()); return t; } }; if (sExecutorService == null) sExecutorService = Executors.newFixedThreadPool(mAppInfo.executorServiceThreadCount, sThreadFactory); mExecutorService = sExecutorService; } // load online data if (mAppInfo.useNetworkClient) mNetworkClient = createNetworkClient(); if (firstRun) { if (mAppInfo.useNetworkGetInfo && mAppInfo.infoURL != null) mNetworkClient.getRawAsString(NetworkActions.GET_INFO, mAppInfo.infoURL); if (AppUtils.checkNewVersionFirstLoad(this)) onNewVersionFirstLoad(); // check if we should ask user to rate if (mAppInfo.askUserToRateEvery > 0 && activity != null) if (AppUtils.checkDisplayLoadMsg(cx, mAppInfo.askUserToRateEvery)) onShowUserRateDialog(activity); } else { mOldVersion = savedInstanceState.getBoolean(STATE_OLD_VERSION, false); mNewVersionID = savedInstanceState.getString(STATE_NEW_VERSION); } } /** * Saves the state of this App to be reloaded after configuration changes. * @return a Bundle with the saved information */ public Bundle onSaveInstanceState() { Bundle outState = new Bundle(); outState.putBoolean(STATE_OLD_VERSION, mOldVersion); outState.putString(STATE_NEW_VERSION, mNewVersionID); return outState; } /** * Update our global static vars with the current screen configuration. */ public void readScreenConfiguration() { readScreenConfiguration(-1, -1); } /** * Update our global static vars with the current screen configuration. * We override the retrieved app width and height sometimes because it cannot * be fully accurately retrieved without just measuring the framelayout everything * is put in. It is in that class, {@link FragmentBaseActivity.SizeFrameLayout}, * when we know that the size is even valid to measure. * @param w : override the app width, or -1 to retrieve it as normal * @param h : override the app height, or -1 to retrieve it as normal */ public void readScreenConfiguration(int w, int h) { DisplayMetrics dm = cx.getResources().getDisplayMetrics(); SCREEN_WIDTH = SCREEN_XPIX = (w == -1) ? dm.widthPixels : w; SCREEN_HEIGHT = SCREEN_YPIX = (h == -1) ? dm.heightPixels : h; if (activity != null && w != -1 && h != -1) { Window win = activity.getWindow(); View v = win.findViewById(Window.ID_ANDROID_CONTENT); if (v != null) { if (v.getHeight() > 0) { SCREEN_WIDTH = v.getWidth(); SCREEN_HEIGHT = v.getHeight(); } } } DENSITY = dm.density; LANDSCAPE = cx.getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE; SCREEN_SIZE = cx.getResources().getConfiguration().screenLayout & Configuration.SCREENLAYOUT_SIZE_MASK; switch (SCREEN_SIZE) { case Configuration.SCREENLAYOUT_SIZE_XLARGE: SCREEN_SIZE_STRING = "xlarge"; M.log("App", "Screen size is: XLARGE, density is "+DENSITY + ", resolution is "+SCREEN_WIDTH+"x"+SCREEN_HEIGHT); break; case Configuration.SCREENLAYOUT_SIZE_LARGE: SCREEN_SIZE_STRING = "large"; M.log("App", "Screen size is: LARGE, density is "+DENSITY + ", resolution is "+SCREEN_WIDTH+"x"+SCREEN_HEIGHT); break; case Configuration.SCREENLAYOUT_SIZE_NORMAL: SCREEN_SIZE_STRING = "normal"; M.log("App", "Screen size is: NORMAL, density is "+DENSITY + ", resolution is "+SCREEN_WIDTH+"x"+SCREEN_HEIGHT); break; case Configuration.SCREENLAYOUT_SIZE_SMALL: SCREEN_SIZE_STRING = "small"; M.log("App", "Screen size is: SMALL, density is "+DENSITY + ", resolution is "+SCREEN_WIDTH+"x"+SCREEN_HEIGHT); break; default: SCREEN_SIZE_STRING = "unknown"; M.log("App", "Screen size is: unknown, density is "+DENSITY + ", resolution is "+SCREEN_WIDTH+"x"+SCREEN_HEIGHT); break; } } /** * Convert DP to pixels. Named inDP to signify providing a measurement "in DP" * @param dp : measurement in density pixels * @return measurement in pixels */ public static int inDP(int dp) { return (int)(dp * DENSITY + 0.5f); } /** * Convert pixels to DP * @param px : measurement in pixels * @return measurement in density pixels */ public static int toDP(int px) { return (int)((float)px / DENSITY + 0.5f); } /** * Use this method to supply information about your app * @param appInfo: fill in this structure with information */ protected abstract void getAppParameters(AppInfo appInfo); /** * Creates the object that manages loading information from the internet * Override this method to use your custon NetworkClient subclass * @return */ protected NetworkClient createNetworkClient() { return new NetworkClient(this, this); } /** * Shows the user the default dialog asking for a rating in the Google Play Market. * Override this to have a custom behavior. The default behavior should be suitable for most apps. * For a positive response, call AppUtils.launchMarketThisApp(App.this); * For a later response, call AppUtils.remindMeLater(cx); * For a never response, no action is sufficient. */ protected void onShowUserRateDialog(FragmentBaseActivity a) { new AlertBuilder(cx) .setTitle(getAppName()) .setMessage(cx.getString(R.string.txt_ask_rate, getAppName())) .setPositiveButton(cx.getString(R.string.btn_rate_market)) .setNeutralButton(cx.getString(R.string.btn_remind_later)) .setNegativeButton(cx.getString(R.string.btn_never_again)) .show(a, DIALOG_USER_RATE); } /** * Called when the generic info fetcher from server has completed * Override this method to supply some actions. * @param success: whether the operation was successful * @param response: the raw response * @param oldVersion: true if this app is outdated * @param info: an attempt to decode the raw response in a param:value style map */ protected void onGetInfo(boolean success, String response, boolean oldVersion, Map<String, String> info) { // } /** * Called when the user has used this app before, but this is the first time the current version has been loaded. * Override this to supply some actions. */ protected void onNewVersionFirstLoad() { // } @Override public void onServerResponse(boolean success, NetworkRequest req, String response) { if (req.mID == NetworkActions.GET_INFO) { String version = getVersionID(); Map<String,String> info = null; if (success) { try { info = NetworkClient.createResponseMap(response); version = info.get("version"); } catch (Exception ex) { // } } if (version != null && !version.equals(getVersionID())) { mOldVersion = true; mNewVersionID = version; } onGetInfo(success, response, mOldVersion, info); } } /** * @return returns true if this is not the most recent version of the application */ public boolean isOldVersion() { return mOldVersion; } /** * Gets the UI Thread * @return the thread object */ public Thread getUIThread() { return mUIThread; } /** * Corresponds to root service/activity onStart */ public void onStart() { if (mAppInfo.flurryID != null) FlurryAgent.onStartSession(cx, mAppInfo.flurryID); } /** * Corresponds to root service/activity onStop */ public void onStop() { if (mAppInfo.flurryID != null) FlurryAgent.onEndSession(cx); } /** * Shortcut for toasting * @param String message * @param true for long, false for short */ public void toast(String msg, boolean longToast) { CharSequence text = (CharSequence)msg; Toast toast = Toast.makeText(cx, text, longToast ? Toast.LENGTH_LONG : Toast.LENGTH_SHORT); toast.show(); } /** * Shortcut for toasting * @param String resource message * @param true for long, false for short */ public void toast(int msg, boolean longToast) { CharSequence text = (CharSequence)cx.getString(msg); Toast toast = Toast.makeText(cx, text, longToast ? Toast.LENGTH_LONG : Toast.LENGTH_SHORT); toast.show(); } /** * Creates a tooltip toast where the screen must be tapped to remove it * @param String resource message */ public void tooltipToast(final int msg) { mHandler.post(new Runnable() { public void run() { QuickAction3D qa = new QuickAction3D(cx); qa.addInfo(0, msg, null); qa.showCentered(getRootView(), false); } }); } /** * Creates a tooltip toast where the screen must be tapped to remove it * @param String message */ public void tooltipToast(final String msg) { mHandler.post(new Runnable() { public void run() { QuickAction3D qa = new QuickAction3D(cx); qa.addInfo(0, msg, null); qa.showCentered(getRootView(), false); } }); } /** * Fires a flurry custom event with 1 parameter * @param event name * @param param 1 name * @param value 1 */ public static void fireTrackerEvent(String event, String param, String value) { HashMap<String, String> parameters = new HashMap<String, String>(); parameters.put(param, value); FlurryAgent.onEvent(event, parameters); M.log("Home", "Flurry: onEvent "+event + " - " + param + " : " + value); } /** * Fires a flurry custom event with 2 parameters * @param event name * @param param 1 name * @param value 1 * @param param 2 name * @param value 2 */ public static void fireTrackerEvent(String event, String param1, String value1, String param2, String value2) { HashMap<String, String> parameters = new HashMap<String, String>(); parameters.put(param1, value1); parameters.put(param2, value2); FlurryAgent.onEvent(event, parameters); M.log("Home", "Flurry: onEvent "+event + " - " + param1+ " : " + value1 + " - " + param2+ " : " + value2); } /** * @return The App activity, if it exists */ public Activity getActivity() { return activity; } /** * @return The App context */ public Context getContext() { return cx; } /** * @return The App name */ public String getAppName() { return mAppInfo.appName; } /** * @return The App version name */ public String getVersionID() { return mAppInfo._versionID; } /** * @return If we are in debug mode */ public boolean isDebugging() { return mAppInfo.debug; } /** * @return the main fragment container view */ public View getContainerView() { return activity.findViewById(mAppInfo.mFragmentContainerID); } /** * @return The root of our app's view tree */ public View getRootView() { return activity.findViewById(mAppInfo.mRootID); } }