Android Open Source - Chopping Basic Prefs






From Project

Back to project page Chopping.

License

The source code is released under:

Apache License

If you think the Android project Chopping listed in this page is inappropriate, such as containing malicious code/tools or violating the copyright, please email info at java2s dot com, thanks.

Java Source Code

package com.chopping.application;
//from w  w w. j  av  a  2s . c  om
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
import java.util.Set;

import android.content.ComponentName;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.preference.PreferenceManager;
import android.text.TextUtils;

import com.android.volley.DefaultRetryPolicy;
import com.android.volley.Request;
import com.android.volley.Response;
import com.android.volley.VolleyError;
import com.android.volley.toolbox.StringRequest;
import com.chopping.bus.ApplicationConfigurationDownloadedEvent;
import com.chopping.bus.ApplicationConfigurationLoadingIgnoredEvent;
import com.chopping.exceptions.CanNotOpenOrFindAppPropertiesException;
import com.chopping.exceptions.InvalidAppPropertiesException;
import com.chopping.net.TaskHelper;
import com.chopping.utils.Consts;
import com.chopping.utils.DeviceUtils;
import com.chopping.utils.IncomingCallReceiver;

import de.greenrobot.event.EventBus;

/**
 * Basic class that provides Preference storage and make it easy to store data globally. We call {@link
 * android.preference.PreferenceManager#getDefaultSharedPreferences(android.content.Context)} so that all
 * preference-components like {@link android.preference.PreferenceActivity}, {@link
 * android.preference.PreferenceFragment} could share a same storage-base.
 * <p/>
 * <p/>
 * Forget <code>edit().xxx.commit().</code>
 *
 * @author Xinyue Zhao
 */
public class BasicPrefs {
  private SharedPreferences mPreferences = null;
  protected Context mContext;
  //----------------------------------------------------------
  // Description: Constants
  //----------------------------------------------------------
  private static final long ONE_HOUR = 3600000;
  private static final long SIX_HOURS = 21600000;
  /**
   * Standard name of application's properties that contains url to the App's config.
   * <p/>
   * <b>The name is forced to be named.</b>
   */
  private static final String APP_PROPERTIES = "app.properties";
  /**
   * Url to the application's configuration.
   * <p/>
   * <b>Mandatory, name is forced to be named</b> in app.properties.
   */
  private static final String APP_CONFIG = "app_config";
  /**
   * Fallback Url to the application's configuration.
   * <p/>
   * <b>Mandatory, name is forced to be named</b> in app.properties.
   */
  private static final String APP_CONFIG_FALLBACK = "app_config_fallback";
  /**
   * Update time-rate. Default is 6 Hours making new loading for configuration.
   * <p/>
   * <b>Optional, name is forced to be named</b> in app.properties.
   * <p/>
   * Generally the Application will load its configuration by calling {@link BasicPrefs#downloadApplicationConfiguration()}
   * which communicates backend with this rate internally. But after the App itself has been updated with new
   * version(new {@link com.chopping.application.BasicPrefs#APP_CODE}), this rate must be ignored.
   */
  private static final String UPDATE_RATE = "update_rate";
  /**
   * Storage for the live status of app, if true, the app can be live, false can not. App can not be live if mExp is
   * not null.
   */
  private static final String APP_CAN_LIVE = "app_can_live";
  /**
   * Storage for last update.
   */
  private static final String LAST_UPDATE = "last_update";
  /**
   * Exception will be created if can not find APP_PROPERTIES, APP_CONFIG & APP_CONFIG_FALLBACK can not be found in
   * file APP_PROPERTIES.
   */
  private RuntimeException mExp;
  /**
   * Temp storage for update-rate. It will be written into preference after App's configurations have been loaded.
   */
  private String mUpdateRate;
  /**
   * True if App is a new version.
   */
  private boolean mNewAppVersion;
  /**
   * Storage for App's VERSION.
   */
  private final static String APP_VERSION = "DeviceData.app.version";
  /**
   * Storage for App's VERSION-CODE.
   */
  private final static String APP_CODE = "DeviceData.app.code";
  /**
   * Storage for DEVICE_ID.
   */
  private final static String DEVICE_ID = "DeviceData.deviceid";
  /**
   * Storage for Device-MODEL.
   */
  private final static String DEVICE_MODEL = "DeviceData.model";
  /**
   * Storage for OS type.
   */
  private final static String OS_NAME = "DeviceData.os";
  /**
   * Storage for OS Releases' Version.
   */
  private final static String OS_VERSION = "DeviceData.os.version";
  /**
   * Storage for API level.
   */
  private final static String OS_API_LEVEL = "DeviceData.os.api.level";
  /**
   * Storage for screen resolution(dpi).
   */
  private final static String SCREEN_DPI = "DeviceData.screen.dpi";
  /**
   * Storage, detect whether to reject incoming calls or not.
   */
  private final static String REJECT_INCOMING = "Reject.incoming";
  /**
   * API. Get list of all external applications.
   */
  private static final String KEY_APP_LIST = "app_list";
  /**
   * Website , home-site of the application, it could be null when the update is a download from a third party url. It
   * should be the page of store where the application is published.
   * <p/>
   * <p/>
   * For example. When {@link #getUpdateHome()} return {@code null}, user updates application by downloading through
   * {@link #getUpdateUrl()}.
   */
  private static final String UPDATE_HOME = "update_home";
  /**
   * Third party url to download the new version, it should be ignored when {@link #getUpdateHome()} doesn't return
   * {@code null}. Because the end user should do update in store.
   */
  private static final String UPDATE_URL = "update_url";
  /**
   * Some extras  information for update.
   */
  private static final String UPDATE_MESSAGE = "update_message";
  /**
   * Indicator for whether this update is mandatory or not.
   */
  private static final String UPDATE_MANDATORY = "update_mandatory";
  /**
   * New version code of the application, after updating it must be equal to {@link #getAppCode()}.
   */
  private static final String UPDATE_VERSION_CODE = "update_version_code";
  /**
   * New version name of the application, after updating it must be equal to {@link #getAppVersion()}.
   */
  private static final String UPDATE_VERSION_NAME = "update_version_name";
  /**
   * Storage. If the downloading is in processing or not.
   */
  private static final String KEY_DOWNLOADING_UPDATE = "key.downloading.update";

  /**
   * Website , home-site of the application, it could be null when the update is a download from a third party url. It
   * should be the page of store where the application is published.
   * <p/>
   * <p/>
   * For example. When {@link #getUpdateHome()} return {@code null}, user updates application by downloading through
   * {@link #getUpdateUrl()}.
   *
   * @return Website , home-site of the application.
   */
  public String getUpdateHome() {
    return getString(UPDATE_HOME, null);
  }

  /**
   * Third party url to download the new version, it should be ignored when {@link #getUpdateHome()} doesn't return
   * {@code null}. Because the end user should do update in store.
   *
   * @return The url to download the new version.
   */
  public String getUpdateUrl() {
    return getString(UPDATE_URL, null);
  }

  /**
   * Get some extras  information for update.
   *
   * @return information for update.
   */
  public String getUpdateMessage() {
    return getString(UPDATE_MESSAGE, null);
  }

  /**
   * Indicator for whether this update is mandatory or not.
   *
   * @return {@code true} if update is mandatory, user can not cancel.
   */
  public boolean isUpdateMandatory() {
    return getBoolean(UPDATE_MANDATORY, false);
  }

  /**
   * New version code of the application, after updating it must be equal to {@link #getAppCode()}.
   */
  public int getUpdateVersionCode() {
    return getInt(UPDATE_VERSION_CODE, 0);
  }

  /**
   * New version name of the application, after updating it must be equal to {@link #getAppVersion()}.
   */
  public String getUpdateVersionName() {
    return getString(UPDATE_VERSION_NAME, null);
  }

  /**
   * Whether downloading is in processing or not.
   *
   * @return {@code true} if downloading is running.
   */
  public boolean isDownloadingUpdate() {
    return getBoolean(KEY_DOWNLOADING_UPDATE, false);
  }

  /**
   * Set whether the downloading is in processing or not.
   *
   * @param downloading
   *     {@code true} if download has been started, it should be set just after calling request to load to prevent some
   *     mistakes. {@code false} if download is finished, it must be set after loading handler comes back.
   */
  public void setDownloadingUpdate(boolean downloading) {
    setBoolean(KEY_DOWNLOADING_UPDATE, downloading);
  }

  /**
   * Constructor of {@link com.chopping.application.BasicPrefs}.
   *
   * @param context
   *     {@link android.content.Context}
   */
  protected BasicPrefs(Context context) {
    mContext = context;
    mPreferences = PreferenceManager.getDefaultSharedPreferences(context);

    /* Asking for some other information.*/
    try {
      PackageManager manager = context.getPackageManager();
      PackageInfo info = manager.getPackageInfo(context.getPackageName(), 0);
      setString(APP_VERSION, info.versionName);
      int lastAppCode = getInt(APP_CODE, -1);
      if (lastAppCode < 0) {
        /*First installation.*/
        mNewAppVersion = true;
      } else if (info.versionCode > lastAppCode) {
        /*Update installation.*/
        mNewAppVersion = true;
      } else {
        /*Only start without update.*/
        mNewAppVersion = false;
      }
      setInt(APP_CODE, info.versionCode);
      if (TextUtils.isEmpty(android.os.Build.MODEL)) {
        setString(DEVICE_MODEL, Consts.UNKNOWN.name());
      } else {
        setString(DEVICE_MODEL, android.os.Build.MODEL);
      }
      setString(OS_NAME, Consts.ANDROID.name());
      setString(OS_VERSION, android.os.Build.VERSION.RELEASE);
      setInt(OS_API_LEVEL, android.os.Build.VERSION.SDK_INT);
      setString(SCREEN_DPI, DeviceUtils.getDeviceResolution(context).name());
    } catch (PackageManager.NameNotFoundException _e) {
      _e.printStackTrace();
    } catch (Exception _e) {
      _e.printStackTrace();
    }

    /* Read "app.properties" under resources of project.*/
    getAppPropertiesUrl(context);

  }


  /**
   * Get the url to the application's configuration.
   *
   * @param context
   *     A {@link android.content.Context} object.
   *
   * @return The url in {@link java.lang.String} to the App's config.
   */
  private String getAppPropertiesUrl(Context context) {
    Properties prop = new Properties();
    InputStream input = null;
    String value = null;
    try {
      /*From "resources".*/
      input = context.getClassLoader().getResourceAsStream(APP_PROPERTIES);
      if (input != null) {
        // load a properties file
        prop.load(input);
        value = prop.getProperty(APP_CONFIG);
        setString(APP_CONFIG, value);
        value = prop.getProperty(APP_CONFIG_FALLBACK);
        setString(APP_CONFIG_FALLBACK, value);
        if (TextUtils.isEmpty(getAppConfigUrl()) || TextUtils.isEmpty(getAppConfigFallbackUrl())) {
          mExp = new InvalidAppPropertiesException();
        }
        /*Get update-rate. We don't save it first in preference until App's configurations have been loaded.*/
        mUpdateRate = prop.getProperty(UPDATE_RATE);
        if (TextUtils.isEmpty(mUpdateRate) || //Do not provide, prompt to use 6 hours.
            !TextUtils.isDigitsOnly(mUpdateRate)) {//Invalid format of update-rate.
          mUpdateRate = "6";
        }
        LL.i(String.format("Properly loading after %s hours.", mUpdateRate));
      } else {
        mExp = new CanNotOpenOrFindAppPropertiesException();
      }
    } catch (IOException ex) {
      mExp = new CanNotOpenOrFindAppPropertiesException();
    } finally {
      if (input != null) {
        try {
          input.close();
        } catch (IOException e) {
          e.printStackTrace();
        }
      }
    }
    return value;
  }


  protected String getString(String key, String defValue) {
    return mPreferences.getString(key, defValue);
  }

  protected boolean setString(String key, String value) {
    SharedPreferences.Editor edit = mPreferences.edit();
    edit.putString(key, value);
    return edit.commit();
  }

  protected boolean getBoolean(String key, boolean defValue) {
    return mPreferences.getBoolean(key, defValue);
  }

  protected boolean setBoolean(String key, boolean value) {
    SharedPreferences.Editor edit = mPreferences.edit();
    edit.putBoolean(key, value);
    return edit.commit();
  }

  protected int getInt(String key, int defValue) {
    return mPreferences.getInt(key, defValue);
  }

  protected boolean setInt(String key, int value) {
    SharedPreferences.Editor edit = mPreferences.edit();
    edit.putInt(key, value);
    return edit.commit();
  }

  protected long getLong(String key, long defValue) {
    return mPreferences.getLong(key, defValue);
  }

  protected boolean setLong(String key, long value) {
    SharedPreferences.Editor edit = mPreferences.edit();
    edit.putLong(key, value);
    return edit.commit();
  }

  protected float getFloat(String key, float defValue) {
    return mPreferences.getFloat(key, defValue);
  }

  protected boolean setFloat(String key, float value) {
    SharedPreferences.Editor edit = mPreferences.edit();
    edit.putFloat(key, value);
    return edit.commit();
  }

  protected boolean contains(String key) {
    return mPreferences.contains(key);
  }

  /**
   * Get url to application's configuration..
   *
   * @return Url in string.
   */
  private String getAppConfigUrl() {
    return getString(APP_CONFIG, null);
  }

  /**
   * Get fallback url to application's configuration..
   *
   * @return Url in string.
   */
  private String getAppConfigFallbackUrl() {
    return getString(APP_CONFIG_FALLBACK, null);
  }

  /**
   * Get API for all external applications.
   *
   * @return API.
   */
  public String getApiAppList() {
    return getString(KEY_APP_LIST, null);
  }

  /**
   * Live-Status of the App. If true, the app can be live, false can not. This method would be called at life-cycle's
   * onResume in order to prevent user from be in an invalidate App-status.
   *
   * @return True, the app can be live.
   */
  public boolean canAppLive() {
    return getBoolean(APP_CAN_LIVE, false);
  }

  /**
   * Get App version-name.
   *
   * @return App's version-name.
   */
  public String getAppVersion() {
    return getString(APP_VERSION, null);
  }

  /**
   * Get App's version-code.
   *
   * @return App's version-code.
   */
  public int getAppCode() {
    return getInt(APP_CODE, -1);
  }


  /**
   * Get device model.
   *
   * @return Device model in {@link java.lang.String}, it might return {@code Consts.UNKNOWN.name()}.
   */
  public String getDeviceModel() {
    return getString(DEVICE_MODEL, Consts.UNKNOWN.name());
  }


  /**
   * Get OS name.
   *
   * @return OS name defined in {@link com.chopping.utils.Consts}, it must return {@code Consts.ANDROID}.
   */
  public Consts getOsName() {
    return Consts.valueOf(getString(OS_NAME, Consts.ANDROID.name()));
  }


  /**
   * Get OS releases' version.
   *
   * @return OS version in {@link java.lang.String}.
   */
  public String getOsVersion() {
    return getString(OS_VERSION, android.os.Build.VERSION.RELEASE);
  }

  /**
   * Get OS API Level.
   *
   * @return API Level in int.
   */
  public int getOsApiLevel() {
    return getInt(OS_API_LEVEL, android.os.Build.VERSION.SDK_INT);
  }

  /**
   * Get screen resolution(DPI).
   *
   * @return Screen's dpi which defined in {@link com.chopping.utils.Consts}, it might return {@code Consts.UNKNOWN)}.
   */
  public Consts getDeviceDPI() {
    return Consts.valueOf(getString(SCREEN_DPI, Consts.UNKNOWN.name()));
  }

  /**
   * Set whether system should reject incoming calls or not.
   * @param reject {@code true} if system hooks incoming calls.
   */
  public void setRejectIncomingCall(boolean reject) {
    ComponentName receiver = new ComponentName(mContext, IncomingCallReceiver.class);
    PackageManager pm = mContext.getPackageManager();
    boolean currentIsReject =  isRejectIncomingCall();
    if(currentIsReject && reject) {
      return  ;//no need to change state.
    }
    if(!currentIsReject && !reject) {
      return  ;//no need to change state.
    }
    if (reject) {
      pm.setComponentEnabledSetting(receiver, PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
          PackageManager.DONT_KILL_APP);
    } else {
      pm.setComponentEnabledSetting(receiver, PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
          PackageManager.DONT_KILL_APP);
    }
    setBoolean(REJECT_INCOMING, reject);
  }

  /**
   * Detect whether to reject incoming calls or not.
   * @return {@code true} if system hooks incoming calls. Default is {@code false}.
   */
  public boolean isRejectIncomingCall() {
    return getBoolean(REJECT_INCOMING, false);
  }

  /**
   * Download application's configuration, internal will use url that has been loaded from app.properties. It could
   * use fallback if the url is invalid.
   * <p/>
   * Call this at {@code onResume()} of {@link android.app.Activity} or {@link android.support.v4.app.Fragment} for
   * each visible cases when App be brought to front.
   *
   * @throws CanNotOpenOrFindAppPropertiesException
   *     If can not find  "app.properties" .
   * @throws InvalidAppPropertiesException
   *     If can not find some mandatory properties.
   */
  public void downloadApplicationConfiguration() throws CanNotOpenOrFindAppPropertiesException,
      InvalidAppPropertiesException {
    if (mExp != null) {
      setBoolean(APP_CAN_LIVE, false);
      throw mExp;
    }
    long lastUpdate = getLong(LAST_UPDATE, -1);
    boolean loadingConfig = lastUpdate < 0 || //Fist install, no last update.
        System.currentTimeMillis() - lastUpdate >= getLong(UPDATE_RATE, SIX_HOURS) ||
        //Long time use and try to load newly.
        mNewAppVersion; //App has been updated.
    if (loadingConfig) {
      LL.i("Loading App's configuration.");
      /*
       * Request App's configuration.
       */
      StringRequest request = new StringRequest(Request.Method.GET, getAppConfigUrl(),
          new Response.Listener<String>() {
            @Override
            public void onResponse(String response) {
              LL.i(":) Loaded App's config: " + getAppConfigUrl());
              writePrefsWithStream(new ByteArrayInputStream(response.getBytes()));
              saveUpdateRate();
            }
          }, new Response.ErrorListener() {
        @Override
        public void onErrorResponse(VolleyError error) {
          LL.w(":( Can't load remote config: " + getAppConfigUrl());
          LL.i(":) We load fallback: " + getAppConfigFallbackUrl());
          writePrefsWithStream(mContext.getClassLoader().getResourceAsStream(getAppConfigFallbackUrl()));
          saveUpdateRate();
        }
      });
      request.setRetryPolicy(new DefaultRetryPolicy(10 * 1000, DefaultRetryPolicy.DEFAULT_MAX_RETRIES,
          DefaultRetryPolicy.DEFAULT_BACKOFF_MULT));
      TaskHelper.getRequestQueue().add(request);
    } else {
      /* Finish loading configuration directly. */
      EventBus.getDefault().post(new ApplicationConfigurationLoadingIgnoredEvent());
    }
  }

  /**
   * Refresh update-rate for loading App's configurations.
   */
  private void saveUpdateRate() {
    setLong(UPDATE_RATE, !TextUtils.isEmpty(mUpdateRate) ? Integer.valueOf(mUpdateRate) * ONE_HOUR : SIX_HOURS);
    LL.i(String.format("Loading after %d seconds.", getLong(UPDATE_RATE, -1)));
  }

  /**
   * Read .properties of App's configuration in stream and write into preference. Finally send event to info front.
   * Recode saving time into {@link android.content.SharedPreferences}.
   *
   * @param input
   *     {@link java.io.InputStream} for loaded .properties.
   */
  private void writePrefsWithStream(InputStream input) {
    Properties prop = new Properties();
    try {
      prop.load(input);
      Set<String> names = prop.stringPropertyNames();
      String valueStr;
      /*
       * Read all properties and store into Android's preference.
       */
      for (String name : names) {
        valueStr = prop.getProperty(name);
        //        LL.d(String.format("%s=%s", name, valueStr));
        if (TextUtils.isDigitsOnly(valueStr)) {
          try {
            int intValue = Integer.valueOf(valueStr);
            setInt(name, intValue);
          } catch (NumberFormatException eL) {
            long longValue = Long.valueOf(valueStr);
            setLong(name, longValue);
          }
        } else {
          try {
            float floatValue = Float.parseFloat(valueStr);
            setFloat(name, floatValue);
          } catch (Exception eF) {
            if (TextUtils.equals(valueStr.toLowerCase(), "true") || TextUtils.equals(valueStr.toLowerCase(),
                "false")) {
              setBoolean(name, Boolean.parseBoolean(valueStr));
            } else {
              /*Have no choice, then all in to string.*/
              setString(name, valueStr);
            }
          }
        }
      }
    } catch (IOException ex) {
      ex.printStackTrace();
    } finally {
      if (input != null) {
        try {
          input.close();
        } catch (IOException e) {
          e.printStackTrace();
        }
      }
      setBoolean(APP_CAN_LIVE, true);
      setLong(LAST_UPDATE, System.currentTimeMillis());
      mNewAppVersion = false;
      /* Read and info front. */
      EventBus.getDefault().post(new ApplicationConfigurationDownloadedEvent());
    }
  }
}




Java Source Code List

com.android.internal.telephony.ITelephony.java
com.chopping.ApplicationTest.java
com.chopping.activities.BaseActivity.java
com.chopping.activities.BrightnessRefreshActivity.java
com.chopping.activities.ErrorHandlerActivity.java
com.chopping.application.BasicPrefs.java
com.chopping.application.ErrorHandler.java
com.chopping.application.IApp.java
com.chopping.application.InstalledAppReceiver.java
com.chopping.application.LL.java
com.chopping.bus.AirplaneModeOnEvent.java
com.chopping.bus.ApplicationConfigurationDownloadedEvent.java
com.chopping.bus.ApplicationConfigurationLoadingIgnoredEvent.java
com.chopping.bus.CloseDrawerEvent.java
com.chopping.bus.ExternalAppChangedEvent.java
com.chopping.bus.LinkToExternalAppEvent.java
com.chopping.bus.ReloadEvent.java
com.chopping.data.AppListItem.java
com.chopping.data.AppList.java
com.chopping.exceptions.CanNotOpenOrFindAppPropertiesException.java
com.chopping.exceptions.InvalidAppPropertiesException.java
com.chopping.exceptions.OperationFailException.java
com.chopping.fragments.AppListFragment.java
com.chopping.fragments.BaseFragment.java
com.chopping.fragments.ErrorHandlerFragment.java
com.chopping.net.GsonRequestTask.java
com.chopping.net.TaskHelper.java
com.chopping.utils.Consts.java
com.chopping.utils.DeviceUtils.java
com.chopping.utils.IncomingCallReceiver.java
com.chopping.utils.MediaUtils.java
com.chopping.utils.NetworkUtils.java
com.chopping.utils.Utils.java
com.chopping.utils.views.OneDirectionScrollView.java