Android Open Source - Resonos-Android-Framework Fragment Base Activity






From Project

Back to project page Resonos-Android-Framework.

License

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.

Java Source Code

package com.resonos.apps.library;
//from  ww w  .  j av  a 2  s  .co  m
import java.util.HashMap;
import java.util.Map;

import android.content.Context;
import android.content.res.Configuration;
import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.os.Bundle;
import android.os.Handler;
import android.support.v4.app.FragmentTransaction;
import android.view.LayoutInflater;
import android.view.View;
import android.view.WindowManager;
import android.widget.FrameLayout;

import com.actionbarsherlock.app.SherlockFragmentActivity;
import com.actionbarsherlock.view.Window;
import com.resonos.app.library.R;
import com.resonos.apps.library.AlertFragment.Result;
import com.resonos.apps.library.BaseFragment.FragmentAnimation;
import com.resonos.apps.library.util.AppUtils;
import com.resonos.apps.library.util.ErrorReporter;
import com.resonos.apps.library.util.LifecycleTaskQueue;
import com.resonos.apps.library.util.ParameterList;
import com.resonos.apps.library.util.ViewServer;

//----------------------------------------------------------------------

/**
 * This is the base activity for anything containing fragments and an actionbar.
 */
public abstract class FragmentBaseActivity extends SherlockFragmentActivity {

  // constants
  public static int AB_HEIGHT;
  public static final String STATE_APP = "appState";
 
  // objects
    public App mApp;
  public Handler mHandler = new Handler();
  private LifecycleTaskQueue mTaskQueue = new LifecycleTaskQueue();
  
  // vars
  private boolean isLowMemory = false;
  private boolean isCreated = false, isStarted = false, isResumed = false;
  private boolean isChangingConfig = false;

  /** Parameters used to create a FragmentBaseActivity */
  public enum Param {
    /** progress bar in actionbar */
    PROGRESS,
    /** progress icon in actionbar */
    PROGRESS_INDETERMINATE,
    /** action bar functions as an overlay, fragments are given spacers to compensate */
    ACTION_BAR_OVERLAY,
    /** use this to designate that an activity is not the root of an application */
    NON_ROOT_ACTIVITY,
    NON_FULL_SCREEN,
    DONT_KEEP_SCREEN_ON};
  private ParameterList<Param> mParams;
  private Map<String, Object> mCustomRetain;
  private SizeFrameLayout mContentView;
    
    // abstract methods
  
  /**
   * @param savedInstanceState : The saved state, if we are restoring an activity, otherwise null
   * @return the an instance of a subclass of App. Create it if this is the root activity.
   * Return the root activity's instance otherwise.
   */
  protected abstract App createApp(Bundle savedInstanceState);

  /**
   * @return return the root fragment of this activity
   */
  protected abstract BaseFragment getMainFragment();
  
  /**
   * @return the resource id of the layout for this app
   */
  protected abstract int getLayoutID();

  /**
   * @return the id of the ViewGroup that fragments will go into
   */
  protected abstract int getFragmentContainerID();
  
  /**
   * @return the id of the view that will be used as a spacer for fragments
   * when an action bar overlay is used
   */
  protected abstract int getABSpacerID();

  /**
   * @return whatever parameters you need for this activity
   * @see FragmentBaseActivity.Param
   */
  protected abstract Param[] getParams();
  
  /**
   * Enum representing the events we mark in activities as points which
   * queued tasks can run.
   */
  public enum ActivityEvent {OnCreate, OnStart, OnResume, OnPause, OnStop, OnDestroy};
  
  /**
   * Add a runnable to a queue to be run one single
   *  occurrence the next time a distinct event occurs.
   * This task will NOT survive a configuration change
   *  or past the onDestroy method.
   * @param event : the {@link ActivityEvent} to trigger the runnable.
   * @param task : the Runnable to run
   */
  public void queueTask(ActivityEvent event, Runnable task) {
    mTaskQueue.addTask(event, task);
  }
  
  /**
   * Get the task queue
   * @return the {@link LifecycleTaskQueue} object
   */
  public LifecycleTaskQueue getTaskQueue() {
    return mTaskQueue;
  }
  
  /**
   * Get a custom retained object.  This function will return null
   *  values by the time onResume is called.
   * @param key : app-wide string key
   * @return the object, or null
   */
  public Object getCustomRetainedObject(String key) {
    return mCustomRetain == null ? null : mCustomRetain.get(key);
  }
  
  /**
   * Override this function to have access to retained data
   *  before the super.onCreate function is called.
   * @param customRetain : the objects, or null if no retained data
   */
  public void onLoadRetainedData(Map<String, Object> customRetain) {
    //
  }
  
  /**
   * Extended framelayout so we can know updates to the size of our app
   */
  public class SizeFrameLayout extends FrameLayout {
    View realContent;

    /**
     * Create the extended frame layout
     * @param context : activity context
     * @param resID : the layout resource id
     */
    public SizeFrameLayout(Context context, int resID) {
      super(context);
      realContent = LayoutInflater.from(context).inflate(resID, null);
      this.addView(realContent, new FrameLayout.LayoutParams(
          LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
    }
    
    @Override
    public void onSizeChanged(int w, int h, int oldw, int oldh) {
      if (w > 0 && h > 0) {
        mApp.readScreenConfiguration(w, h);
        FragmentBaseActivity.this.onSizeChanged(w, h);
      }
    }
  }

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    mParams = new ParameterList<Param>(getParams());
    
    // Hide the window title.
      if (!mParams.has(Param.NON_FULL_SCREEN))
        getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
      if (!mParams.has(Param.DONT_KEEP_SCREEN_ON))
        getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
      
    boolean overlay = false;
      if (mParams.has(Param.PROGRESS))
        requestWindowFeature(Window.FEATURE_PROGRESS);
      if (mParams.has(Param.PROGRESS_INDETERMINATE))
        requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
      if (mParams.has(Param.ACTION_BAR_OVERLAY)) {
      overlay = true;
        requestWindowFeature(Window.FEATURE_ACTION_BAR_OVERLAY);
        requestWindowFeature(Window.FEATURE_ACTION_MODE_OVERLAY);
      }
      
        getWindow().setFormat(PixelFormat.RGBA_8888);
        
        // locks in state
        getWindow().getDecorView();
        
    Bundle appState = (savedInstanceState == null) ? null : savedInstanceState.getBundle(STATE_APP);
    mApp = createApp(appState);
    
    isChangingConfig = false;
    
    // retain instance
    @SuppressWarnings("unchecked")
    Map<String,Object> customRetain = (Map<String,Object>)getLastCustomNonConfigurationInstance();
    if (customRetain != null)
      mCustomRetain = customRetain;
    
    onLoadRetainedData(customRetain);
    
    super.onCreate(savedInstanceState);
    isCreated = true;
    
    // set some global vars
    AB_HEIGHT = getActionBarHeight();
        
    mContentView = new SizeFrameLayout(this, getLayoutID());
        setContentView(mContentView);
        
    if (savedInstanceState == null) {
      toFirstFragment(getMainFragment());
    }
    
    View spacer = findViewById(getABSpacerID());
    spacer.getLayoutParams().height = overlay ? AB_HEIGHT : 0;
    spacer.requestLayout();

    // for hierarchy viewer
    if (mApp.isDebugging())
          ViewServer.get(this).addWindow(this);

    mTaskQueue.runEvent(ActivityEvent.OnCreate);
    
      if (mParams.has(Param.PROGRESS_INDETERMINATE))
        this.setSupportProgressBarIndeterminateVisibility(false);
  }
  
  /**
   * Get the default actionbar height. This may not reflect the actual actionbar height
   * @return default abar height
   */
  public int getActionBarHeight() {
    return getResources().getDimensionPixelSize(R.dimen.abs__action_bar_default_height);
  }
  
  /**
   * Override this to get notifications about size changes to the app
   * @param w : width
   * @param h : height
   */
  public void onSizeChanged(int w, int h) {
    //
  }

  @Override
  public void onSaveInstanceState(Bundle outState) {
    super.onSaveInstanceState(outState);
    outState.putBundle(STATE_APP, mApp.onSaveInstanceState());
  }
  
  @Override
  public final Object onRetainCustomNonConfigurationInstance() {
    isChangingConfig = true;
    Map<String,Object> customRetain = new HashMap<String,Object>();
    onRetainCustomObjects(customRetain);
    BaseFragment fCur = getCurFragment();
    if (fCur != null)
      fCur.onRetainCustomObjects(customRetain);
    return customRetain;
  }

  /**
   * Override this to retain custom objects across instances rather than the whole fragment, 
   *  as the API allows
   * @param customRetain : the map to put objects in
   */
  public void onRetainCustomObjects(Map<String, Object> customRetain) {
    //
  }
  
  /**
   * Sets whether the indeterminate progress bar is visible,
   *  clearing any waiting message
   * @param visible
   */
    public void setActionBarProgressVisible(boolean visible) {
        setSupportProgressBarIndeterminateVisibility(visible);
        if (!visible)
          getSupportActionBar().setTitle(
              (getCurFragment() == null || getCurFragment().getTitle() == null)
                ? mApp.getAppName() : getCurFragment().getTitle());
    }
  
  /**
   * Sets whether the indeterminate progress bar is visible,
   *  displaying a message
   * @param visible
   * @param msg : the waiting message
   */
    public void setActionBarProgressVisible(boolean visible, int msg) {
      setActionBarProgressVisible(visible, getString(msg));
    }
  
    /**
     * Sets whether the indeterminate progress bar is visible,
     *  displaying a message
     * @param visible
     * @param string : the waiting message
     */
  public void setActionBarProgressVisible(boolean visible, String string) {
    setActionBarProgressVisible(visible);
    if (visible)
      getSupportActionBar().setTitle(string);
  }

  @Override
  public void onConfigurationChanged(Configuration newConfig) {
    super.onConfigurationChanged(newConfig);
    mApp.readScreenConfiguration();
  }
  
  @Override
  protected void onStart() {
    super.onStart();
    isStarted = true;
    if (!mParams.has(Param.NON_ROOT_ACTIVITY));
      mApp.onStart();

      mTaskQueue.runEvent(ActivityEvent.OnStart);
  }

  @Override
  protected void onResume() {
    super.onResume();
    mCustomRetain = null;
    isResumed = true;
    
    if (mApp.isDebugging())
          ViewServer.get(this).setFocusedWindow(this);

    mTaskQueue.runEvent(ActivityEvent.OnResume);
   }

  /**
   * @return Are we between onCreate and onDestroy?
   */
  public boolean isCreated() {
    return isCreated;
  }

  /**
   * @return Are we between onStart and onStop?
   */
  public boolean isStarted() {
    return isStarted;
  }

  /**
   * @return Are we NOT between onResume and onPause?
   */
  public boolean isPaused() {
    return !isResumed;
  }

  /**
   * @return Has a low memory warning been encountered?
   * It is possible there is no longer low memory. The flag will stay set forever.
   */
  public boolean isLowMemory() {
    return isLowMemory;
  }

  @Override
  protected void onPause() {
    super.onPause();
    isResumed = false;

    // for hierarchy viewer
    if (mApp.isDebugging())
          ViewServer.get(this).setFocusedWindow(this);

    mTaskQueue.runEvent(ActivityEvent.OnPause);
  }
  
  @Override
  protected void onStop() {
    super.onStop();
    isStarted = false;
    if (!mParams.has(Param.NON_ROOT_ACTIVITY));
      mApp.onStop();

    mTaskQueue.runEvent(ActivityEvent.OnStop);
  }
  
    @Override
    protected void onDestroy() {
        super.onDestroy();
        isCreated = false;

    // for hierarchy viewer
        if (mApp.isDebugging())
          ViewServer.get(this).removeWindow(this);
    mTaskQueue.runEvent(ActivityEvent.OnDestroy);
    mTaskQueue.empty();
    }
    
    /**
     * Determine if a call to onDestroy is due to a changing configuration.
     * This function is undefined at any other time.  This is required because 
     * this similar API function was not added until API 11
     * @return true if the activity is about to be restarted
     */
    public boolean isChangingConfig() {
      return isChangingConfig;
    }

  @Override
  public void onLowMemory() {
    isLowMemory = true;
    super.onLowMemory();
  }

  /**
   * Switch main fragment to a new one as a child of the current fragment, adding the last to the backstack
   * @param new fragment
   */
  public void toChildFragment(BaseFragment f) {
    toChildFragment(f, false);
  }

  /**
   * Switch main fragment to a new one as a child of the current fragment
   * @param new fragment
   * @param noHistory : true to not add this change to the backstack
   */
  public void toChildFragment(BaseFragment f, boolean noHistory) {
    FragmentTransaction xact = getSupportFragmentManager().beginTransaction();
    
    // a child fragment, so we need to override parent animation params
    xact.setCustomAnimations(f.getAnimation(FragmentAnimation.ENTER_FORWARD, f),
        f.getAnimation(FragmentAnimation.EXIT_FORWARD, f),
        f.getAnimation(FragmentAnimation.ENTER_BACKWARD, f),
        f.getAnimation(FragmentAnimation.EXIT_BACKWARD, f));
      xact.replace(getFragmentContainerID(), f, f.getClass().getSimpleName());
    
    xact.addToBackStack(f.getClass().getSimpleName());
    
      xact.commit();
  }

  /**
   * Switch main fragment to a new one as a child of the current fragment's parent
   * @param f : the new fragment
   * @param noHistory : true to not add this change to the backstack
   */
  public void toSiblingFragment(BaseFragment f, boolean noHistory) {
    FragmentTransaction xact = getSupportFragmentManager().beginTransaction();
    
    BaseFragment fCur = getCurFragment();
    
    // a sibling fragment so animate both
    xact.setCustomAnimations(f.getAnimation(FragmentAnimation.ENTER_FORWARD, fCur),
        fCur.getAnimation(FragmentAnimation.EXIT_FORWARD, f),
        fCur.getAnimation(FragmentAnimation.ENTER_BACKWARD, f),
        f.getAnimation(FragmentAnimation.EXIT_BACKWARD, fCur));
      xact.replace(getFragmentContainerID(), f, f.getClass().getSimpleName());
      
    if (!noHistory)
      xact.addToBackStack(f.getClass().getSimpleName());
      xact.commit();
  }
  
  /**
   * Places the first main fragment in the app.
   * @param f : the main fragment
   */
  private void toFirstFragment(BaseFragment f) {
    FragmentTransaction xact = getSupportFragmentManager().beginTransaction();
      xact.add(getFragmentContainerID(), f, f.getClass().getSimpleName());
    xact.addToBackStack(f.getClass().getSimpleName());
      f.setTransactionID(xact.commit());
  }

  /**
   * Traverse up the back stack searching for the target fragment
   * @param target fragment
   */
  public void returnToFragment(BaseFragment f) {
    if (getCurFragment() == f) // already here!
      return;
    int trID = f.getTransactionID();
    if (trID != -1)
      getSupportFragmentManager().popBackStackImmediate(trID, 0);
  }

  /**
   * Traverse up the back stack searching for the target fragment,
   *  but not immediately going back (in case calling this inside a transaction)
   * @param target fragment
   */
  public void returnToFragmentSafe(BaseFragment f) {
    if (getCurFragment() == f) // already here!
      return;
    int trID = f.getTransactionID();
    if (trID != -1)
      getSupportFragmentManager().popBackStack(trID, 0);
  }

  /**
   * Traverse up the back stack one step
   */
  public void backOneFragment() {
    getSupportFragmentManager().popBackStackImmediate();
  }

  /**
   * Traverse up the back stack one step, but not immediately (in case calling this inside a transaction)
   */
  public void backOneFragmentSafe() {
    getSupportFragmentManager().popBackStack();
  }
  
  /**
   * @return the current fragment in the main fragment container
   */
  public BaseFragment getCurFragment() {
    return (BaseFragment)getSupportFragmentManager()
        .findFragmentById(getFragmentContainerID());
  }
  
  @Override
  public void onBackPressed() {
    // custom app-level back button stuff
    if (onBackPressedCustom())
      return;
    
    BaseFragment cur = getCurFragment();
    if (cur == null) { // shouldn't ever happen, just a safeguard
      finish();
      return;
    }
    
    // custom fragment-level back button stuff
    if (!cur.isPaused())
      if (cur.onBackPressed())
        return;
    
    if (cur == getMainFragment())
      finish();
    else {
      try {
        super.onBackPressed();
      } catch (IllegalStateException ex) {
        // in an app that uses this, we're getting an extremely rare crash when popping the backstack
        // this may give us more details
        String curDesc = cur == null ? "null" : cur.toString();
        ErrorReporter.getInstance().report("ErrorPoppingStack", ex, "fragment: " + curDesc);
        throw new RuntimeException(ex);
      }
    }
  }
  
  /**
   * Custom actions to take if the back button is pressed
   * @return true to capture the back button and override default behavior
   */
  protected abstract boolean onBackPressedCustom();

  /**
   * Calculates the x position of a button on the action bar, assuming the buttons are all icons
   * We do this because there is no public API in the action bar to get the position of buttons
   * @param the index of button, counting from the right, 0 is the first
   * @return the x screen position of the center of the button, in pixels
   */
  public int getActionBarButtonX(int i) {
    float n = (48 * (i + 0.5f) + 2)
            * App.DENSITY
            * ((App.SCREEN_SIZE == Configuration.SCREENLAYOUT_SIZE_XLARGE) ? 1.666666667f
                : 1);
    if (android.os.Build.VERSION.SDK_INT >= 14)
      n = n*1.1566667f;
    return (int)(-0.5f + App.SCREEN_WIDTH - n);
  }

  /**
   * Calculates the y position of a button on the action bar,
   * assuming the action bar is at the top of the screen.
   * We do this because there is no public API in the action bar to get the position of buttons
   * @return the yx screen position of the bottom of the button, in pixels
   */
  public int getActionBarButtonY() {
    Rect r = new Rect();
    android.view.Window window = getWindow();
    window.getDecorView().getWindowVisibleDisplayFrame(r);
    int statusBarHeight = r.top;
    return statusBarHeight + getActionBarHeight();
  }

  /**
   * Called when a dialog has returned
   * @param id : the id the dialog was created with
   * @param button : the button, DialogInterface.BUTTON_x values
   */
  protected void onDialogResult(int id, Result button) {
    switch (id) {
    case App.DIALOG_USER_RATE:
      if (button == Result.YES)
        AppUtils.launchMarketThisApp(mApp);
      else if (button == Result.MAYBE)
        AppUtils.remindMeLater(this);
      return;
    }
    if (getCurFragment() != null) {
      getCurFragment().onDialogResult(id, button);
    }
  }

  /**
   * Called when a dialog needs a custom view during creation
   * @param id : the id the dialog was created with
   */
  protected View onDialogCreateCustomView(int id) {
    if (getCurFragment() != null) {
      return getCurFragment().onDialogCreateCustomView(id);
    }
    return null;
  }
}




Java Source Code List

com.resonos.apps.library.Action.java
com.resonos.apps.library.AlertFragment.java
com.resonos.apps.library.App.java
com.resonos.apps.library.BaseFragment.java
com.resonos.apps.library.FragmentBaseActivity.java
com.resonos.apps.library.file.AltAndroidFileHandle.java
com.resonos.apps.library.file.AltAndroidFiles.java
com.resonos.apps.library.file.AltFileHandle.java
com.resonos.apps.library.file.FileCache.java
com.resonos.apps.library.media.AudioVisualizer.java
com.resonos.apps.library.media.BitmapMemoryCache.java
com.resonos.apps.library.media.HueColorFilter.java
com.resonos.apps.library.media.ImageLoader.java
com.resonos.apps.library.media.MediaScannerNotifier.java
com.resonos.apps.library.model.Coord.java
com.resonos.apps.library.model.ImmutableCoord.java
com.resonos.apps.library.tabviewpager.CustomViewPager.java
com.resonos.apps.library.tabviewpager.PageIndicator.java
com.resonos.apps.library.tabviewpager.TabPageIndicator.java
com.resonos.apps.library.tabviewpager.TabViewPagerAdapter.java
com.resonos.apps.library.tabviewpager.TabViewPagerFragment.java
com.resonos.apps.library.tabviewpager.TitleProvider.java
com.resonos.apps.library.util.AppUtils.java
com.resonos.apps.library.util.ErrorReporter.java
com.resonos.apps.library.util.LifecycleTaskQueue.java
com.resonos.apps.library.util.M.java
com.resonos.apps.library.util.NetworkClient.java
com.resonos.apps.library.util.NetworkRequest.java
com.resonos.apps.library.util.ParameterList.java
com.resonos.apps.library.util.SensorReader.java
com.resonos.apps.library.util.TouchViewWorker.java
com.resonos.apps.library.util.ViewServer.java
com.resonos.apps.library.widget.DashboardLayout.java
com.resonos.apps.library.widget.FormBuilder.java
com.resonos.apps.library.widget.FormElement.java
com.resonos.apps.library.widget.ListFormBuilder.java
com.resonos.apps.library.widget.PopupWindows3D.java
com.resonos.apps.library.widget.QuickAction3D.java
com.resonos.apps.library.widget.RangeSeekBar.java
com.resonos.apps.library.widget.SeekBar.java
com.resonos.apps.library.widget.ToolBarButton.java
com.resonos.apps.library.widget.ToolBar.java