Android Open Source - FPlayAndroid Activity Host






From Project

Back to project page FPlayAndroid.

License

The source code is released under:

Copyright (c) 2013-2014, Carlos Rafael Gimenes das Neves All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the followin...

If you think the Android project FPlayAndroid 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

//
// FPlayAndroid is distributed under the FreeBSD License
///*from www  . j  a  va2  s. c om*/
// Copyright (c) 2013-2014, Carlos Rafael Gimenes das Neves
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
//    list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright notice,
//    this list of conditions and the following disclaimer in the documentation
//    and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// The views and conclusions contained in the software and documentation are those
// of the authors and should not be interpreted as representing official policies,
// either expressed or implied, of the FreeBSD Project.
//
// https://github.com/carlosrafaelgn/FPlayAndroid
//
package br.com.carlosrafaelgn.fplay.activity;

import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.res.Configuration;
import android.net.Uri;
import android.os.Bundle;
import android.view.KeyEvent;
import android.view.Menu;
import android.view.View;
import android.view.ViewGroup;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityManager;
import android.view.animation.AccelerateDecelerateInterpolator;
import android.view.animation.AlphaAnimation;
import android.view.animation.Animation;
import android.view.animation.AnimationSet;
import android.view.animation.ScaleAnimation;
import android.view.animation.TranslateAnimation;
import android.widget.FrameLayout;

import br.com.carlosrafaelgn.fplay.ActivityMain;
import br.com.carlosrafaelgn.fplay.playback.Player;
import br.com.carlosrafaelgn.fplay.ui.CustomContextMenu;
import br.com.carlosrafaelgn.fplay.ui.SongAddingMonitor;
import br.com.carlosrafaelgn.fplay.ui.UI;
import br.com.carlosrafaelgn.fplay.ui.drawable.NullDrawable;

//
//Handling Runtime Changes
//http://developer.android.com/guide/topics/resources/runtime-changes.html
//
//<activity> (all attributes, including android:configChanges)
//http://developer.android.com/guide/topics/manifest/activity-element.html
//
public final class ActivityHost extends Activity implements Player.PlayerDestroyedObserver, Animation.AnimationListener {
  private ClientActivity top;
  private boolean exitOnDestroy, isFading, useFadeOutNextTime, ignoreFadeNextTime;
  private FrameLayout parent;
  private View oldView, newView;
  private AnimationSet anim;

  private void updateTitle(CharSequence title, boolean announce) {
    setTitle(title);
    //announce should be false when starting/finishing an activity from a menu
    //because in those cases AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED will
    //already happen due to a change in the active window, making the user hear
    //the title twice!
    if (announce) {
      final AccessibilityManager manager = (AccessibilityManager)getSystemService(Context.ACCESSIBILITY_SERVICE);
      if (manager != null && manager.isEnabled()) {
        final AccessibilityEvent e = AccessibilityEvent.obtain();
        e.setEventType(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
        e.setClassName(getClass().getName());
        e.setPackageName(getApplication().getPackageName());
        e.getText().add(title);
        manager.sendAccessibilityEvent(e);
      }
    }
  }

  public ClientActivity getTopActivity() {
    return top;
  }
  
  public void setExitOnDestroy(boolean exitOnDestroy) {
    this.exitOnDestroy = exitOnDestroy;
  }
  
  @Override
  public void onAnimationEnd(Animation animation) {
    if (isFading) {
      isFading = false;
      if (parent != null) {
        if (oldView != null) {
          parent.removeView(oldView);
          oldView = null;
        }
        if (newView != null) {
          newView.setEnabled(true);
          newView = null;
        }
        parent = null;
      }
    }
    if (anim != null) {
      anim.setAnimationListener(null);
      anim = null;
    }
    if (animation != null)
      SongAddingMonitor.start(this);
  }
  
  @Override
  public void onAnimationRepeat(Animation animation) {
  }
  
  @Override
  public void onAnimationStart(Animation animation) {
  }

  public View findViewByIdDirect(int id) {
    return super.findViewById(id);
  }

  @Override
  public View findViewById(int id) {
    return ((newView != null) ? newView.findViewById(id) : super.findViewById(id));
  }

  @Override
  public void setContentView(View view) {
    super.setContentView(view);
    SongAddingMonitor.start(this);
  }

  @Override
  public void setContentView(View view, ViewGroup.LayoutParams params) {
    super.setContentView(view, params);
    SongAddingMonitor.start(this);
  }

  @Override
  public void setContentView(int layoutResID) {
    super.setContentView(layoutResID);
    SongAddingMonitor.start(this);
  }

  void setContentViewWithTransition(View view, boolean fadeAllowed, boolean forceFadeOut) {
    final int transition = UI.getTransition();
    if (fadeAllowed && !ignoreFadeNextTime && transition != UI.TRANSITION_NONE) {
      try {
        parent = (FrameLayout)findViewById(android.R.id.content);
      } catch (Throwable ex) {
        parent = null;
      }
    } else {
      parent = null;
    }
    if (parent != null) {
      anim = null;
      try {
        oldView = parent.getChildAt(0);
        if (oldView != null) {
          newView = view;
          anim = new AnimationSet(true);
          int x, y;
          if (transition == UI.TRANSITION_FADE) {
            x = oldView.getWidth() >> 1;
            y = 0;
          } else {
            x = UI.lastViewCenterLocation[0];
            y = UI.lastViewCenterLocation[1];
          }
          try {
            parent.getLocationOnScreen(UI.lastViewCenterLocation);
            x -= UI.lastViewCenterLocation[0];
            y -= UI.lastViewCenterLocation[1];
          } catch (Throwable ex) {
          }
          //leave prepared for next time
          UI.storeViewCenterLocationForFade(null);
          if (useFadeOutNextTime || forceFadeOut) {
            if (transition == UI.TRANSITION_FADE) {
              anim.addAnimation(new ScaleAnimation(1, 0.75f, 1, 1, x, y));
              anim.addAnimation(new TranslateAnimation(0, 0, 0, oldView.getHeight() >> 3));
            } else {
              anim.addAnimation(new ScaleAnimation(1, 0.3f, 1, 0.3f, x, y));
            }
            anim.addAnimation(new AlphaAnimation(1, 0));
          } else {
            if (transition == UI.TRANSITION_FADE) {
              anim.addAnimation(new ScaleAnimation(0.75f, 1, 1, 1, x, y));
              anim.addAnimation(new TranslateAnimation(0, 0, -(oldView.getHeight() >> 3), 0));
            } else {
              anim.addAnimation(new ScaleAnimation(0.3f, 1, 0.3f, 1, x, y));
            }
            anim.addAnimation(new AlphaAnimation(0, 1));
          }
          anim.setDuration(330);
          anim.setInterpolator(new AccelerateDecelerateInterpolator());
          anim.setRepeatCount(0);
          anim.setFillAfter(false);
        } else {
          parent = null;
        }
      } catch (Throwable ex) {
        anim = null;
        parent = null;
      }
      if (anim != null) {
        SongAddingMonitor.stop();
        anim.setAnimationListener(this);
        oldView.setEnabled(false);
        view.setEnabled(false);
        parent.addView(view, new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT));
        if (useFadeOutNextTime || forceFadeOut) {
          oldView.bringToFront();
          oldView.startAnimation(anim);
        } else {
          view.bringToFront();
          view.startAnimation(anim);
        }
        isFading = true;
      }
    }
    if (parent == null) {
      oldView = null;
      newView = null;
      setContentView(view);
    }
    useFadeOutNextTime = false;
  }
  
  private void startActivityInternal(ClientActivity activity, boolean announce) {
    activity.finished = false;
    activity.activity = this;
    activity.previousActivity = top;
    top = activity;
    updateTitle(activity.getTitle(), announce);
    activity.paused = true;
    activity.onCreate();
    if (!activity.finished) {
      activity.onCreateLayout(true);
      if (!activity.finished && activity.paused) {
        activity.paused = false;
        activity.onResume();
      }
    }
  }
  
  public void startActivity(ClientActivity activity, boolean announce) {
    if (top != null) {
      if (!top.paused) {
        top.paused = true;
        top.onPause();
      }
      if (top != null)
        top.onCleanupLayout();
    }
    startActivityInternal(activity, announce);
  }
  
  public void finishActivity(ClientActivity activity, ClientActivity newActivity, int code, boolean announce) {
    if (activity.finished || activity != top)
      return;
    useFadeOutNextTime = true;
    activity.finished = true;
    if (!activity.paused) {
      activity.paused = true;
      activity.onPause();
    }
    activity.onCleanupLayout();
    activity.onDestroy();
    if (top != null)
      top = top.previousActivity;
    else
      top = null;
    if (top != null)
      updateTitle(top.getTitle(), announce);
    else
      //prevent the title from being said by TalkBack when the
      //application finishes in response to a menu item
      setTitle("\u00A0");
    activity.activity = null;
    activity.previousActivity = null;
    final ClientActivity oldTop = top;
    if (oldTop != null && !oldTop.finished)
      oldTop.activityFinished(activity, activity.requestCode, code);
    if (newActivity != null) {
      startActivityInternal(newActivity, announce);
    } else {
      if (top == null) {
        finish();
      } else if (top == oldTop) {
        //we must check because the top activity could have
        //changed as a consequence of oldTop.activityFinished()
        //being called
        top.onCreateLayout(false);
        if (top != null && !top.finished && top.paused) {
          top.paused = false;
          top.onResume();
        }
      }
    }
    System.gc();
  }

  @Override
  public void onBackPressed() {
    if (isFading)
      return;
    if (top != null) {
      if (top.onBackPressed())
        return;
      if (top != null && top.previousActivity != null) {
        finishActivity(top, null, 0, true);
        return;
      }
    }
    super.onBackPressed();
  }
  
  @Override
  public boolean onPrepareOptionsMenu(Menu menu) {
    if (isFading)
      return false;
    if (top != null) {
      final View v = top.getNullContextMenuView();
      if (v != null)
        CustomContextMenu.openContextMenu(v, top);
    }
    return false;
  }
  
  //replace onKeyDown with dispatchKeyEvent + event.getAction() + event.getKeyCode()?!?!?!
  @Override
  public boolean onKeyDown(int keyCode, KeyEvent event) {
    //
    //Allowing applications to play nice(r) with each other: Handling remote control buttons
    //http://android-developers.blogspot.com.br/2010/06/allowing-applications-to-play-nicer.html
    //
    //...In a media playback application, this is used to react to headset button
    //presses when your activity doesnt have the focus. For when it does, we override
    //the Activity.onKeyDown() or onKeyUp() methods for the user interface to trap the
    //headset button-related events...
    if ((event == null || event.getRepeatCount() == 0) && Player.handleMediaButton(keyCode))
      return true;
    return super.onKeyDown(keyCode, event);
  }

  @Override
  protected void onNewIntent(Intent intent) {
    super.onNewIntent(intent);
    final Uri data;
    if (Player.getState() == Player.STATE_INITIALIZED && intent != null && Intent.ACTION_VIEW.equals(intent.getAction()) && (data = intent.getData()) != null) {
      System.out.println(data.getPath());
    }
  }

  @Override
  protected final void onCreate(Bundle savedInstanceState) {
    //StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder()
    //  .detectAll()
    //  .penaltyLog()
    //  .build());
    //StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder()
    //  .detectAll()
    //  .penaltyLog()
    //  .build());
    //top is null everytime onCreate is called, which means
    //everytime a new ActivityMain is created
    //if top was any ClientActivity other than ActivityMain when
    //onSaveInstanceState was called, then the android:viewHierarchyState
    //in the savedInstanceState Bundle will not match the actual view
    //structure that belongs to ActivityMain
    //that's why we pass null to super.onCreate!
    super.onCreate(null);
    UI.initialize(getApplication());
    MainHandler.initialize();
    if (Player.startService(getApplication()))
      UI.setAndroidThemeAccordingly13(this);
    UI.storeViewCenterLocationForFade(null);
    top = new ActivityMain();
    top.finished = false;
    top.activity = this;
    top.previousActivity = null;
    setTitle(top.getTitle());
    getWindow().setBackgroundDrawable(new NullDrawable());
    top.paused = true;
    top.onCreate();
    if (top != null && !top.finished) {
      top.onCreateLayout(true);
      if (top != null && !top.finished)
        Player.addDestroyedObserver(this);
      else
        finish();
    } else {
      finish();
    }
  }
  
  @Override
  protected void onStart() {
    super.onStart();
    //when the user is returning to the app, just reset the
    //previously stored position, allowing for the current song
    //to be displayed instead
    Player.listFirst = -1;
    Player.listTop = 0;
  }
  
  @Override
  protected void onSaveInstanceState(Bundle outState) {
    super.onSaveInstanceState(outState);
    outState.clear(); //see the comments in the method above
  }
  
  @Override
  public void onConfigurationChanged(Configuration newConfig) {
    super.onConfigurationChanged(newConfig);
    final boolean i = UI.isLandscape;
    UI.initialize(this);
    if (i != UI.isLandscape) {
      if (top != null) {
        ignoreFadeNextTime = true;
        top.onOrientationChanged();
        ignoreFadeNextTime = false;
        System.gc();
      }
    }
  }
  
  @Override
  protected void onPause() {
    SongAddingMonitor.stop();
    onAnimationEnd(null);
    if (top != null && !top.paused) {
      top.paused = true;
      top.onPause();
    }
    Player.setAppIdle(true);
    super.onPause();
  }

  @Override
  protected void onResume() {
    Player.setAppIdle(false);
    if (UI.getForcedLocale() != UI.LOCALE_NONE)
      UI.reapplyForcedLocale(getApplication());
    if (top != null && top.paused) {
      top.paused = false;
      top.onResume();
    }
    SongAddingMonitor.start(this);
    super.onResume();
  }
  
  private void finalCleanup() {
    ClientActivity c = top, p;
    top = null;
    parent = null;
    oldView = null;
    newView = null;
    if (anim != null) {
      anim.setAnimationListener(null);
      anim = null;
    }
    while (c != null) {
      if (!c.finished) {
        c.finished = true;
        if (!c.paused) {
          c.paused = true;
          c.onPause();
        }
        c.onCleanupLayout();
        c.onDestroy();
      }
      p = c.previousActivity;
      c.activity = null;
      c.previousActivity = null;
      c = p;
    }
  }
  
  @Override
  protected void onDestroy() {
    Player.removeDestroyedObserver(this);
    finalCleanup();
    super.onDestroy();
    if (exitOnDestroy)
      System.exit(0);
  }
  
  @Override
  public void onPlayerDestroyed() {
    finalCleanup();
    finish();
  }
}




Java Source Code List

br.com.carlosrafaelgn.fplay.ActivityAbout.java
br.com.carlosrafaelgn.fplay.ActivityBrowser2.java
br.com.carlosrafaelgn.fplay.ActivityBrowserRadio.java
br.com.carlosrafaelgn.fplay.ActivityBrowserView.java
br.com.carlosrafaelgn.fplay.ActivityEffects.java
br.com.carlosrafaelgn.fplay.ActivityFileSelection.java
br.com.carlosrafaelgn.fplay.ActivityItemView.java
br.com.carlosrafaelgn.fplay.ActivityMain.java
br.com.carlosrafaelgn.fplay.ActivitySettings.java
br.com.carlosrafaelgn.fplay.ExternalReceiver.java
br.com.carlosrafaelgn.fplay.WidgetMain.java
br.com.carlosrafaelgn.fplay.activity.ActivityHost.java
br.com.carlosrafaelgn.fplay.activity.ActivityVisualizer.java
br.com.carlosrafaelgn.fplay.activity.ClientActivity.java
br.com.carlosrafaelgn.fplay.activity.MainHandler.java
br.com.carlosrafaelgn.fplay.list.AlbumArtFetcher.java
br.com.carlosrafaelgn.fplay.list.BaseItem.java
br.com.carlosrafaelgn.fplay.list.BaseList.java
br.com.carlosrafaelgn.fplay.list.FileFetcher.java
br.com.carlosrafaelgn.fplay.list.FileList.java
br.com.carlosrafaelgn.fplay.list.FileSt.java
br.com.carlosrafaelgn.fplay.list.RadioStationList.java
br.com.carlosrafaelgn.fplay.list.RadioStation.java
br.com.carlosrafaelgn.fplay.list.SongList.java
br.com.carlosrafaelgn.fplay.list.Song.java
br.com.carlosrafaelgn.fplay.playback.BassBoost.java
br.com.carlosrafaelgn.fplay.playback.Equalizer.java
br.com.carlosrafaelgn.fplay.playback.MetadataExtractor.java
br.com.carlosrafaelgn.fplay.playback.Player.java
br.com.carlosrafaelgn.fplay.playback.PresetReverb.java
br.com.carlosrafaelgn.fplay.playback.Virtualizer.java
br.com.carlosrafaelgn.fplay.ui.BgButton.java
br.com.carlosrafaelgn.fplay.ui.BgColorStateList.java
br.com.carlosrafaelgn.fplay.ui.BgListView.java
br.com.carlosrafaelgn.fplay.ui.BgSeekBar.java
br.com.carlosrafaelgn.fplay.ui.BgTextView.java
br.com.carlosrafaelgn.fplay.ui.ColorPickerView.java
br.com.carlosrafaelgn.fplay.ui.CustomContextMenu.java
br.com.carlosrafaelgn.fplay.ui.FileView.java
br.com.carlosrafaelgn.fplay.ui.InterceptableLayout.java
br.com.carlosrafaelgn.fplay.ui.ObservableScrollView.java
br.com.carlosrafaelgn.fplay.ui.RadioStationView.java
br.com.carlosrafaelgn.fplay.ui.SettingView.java
br.com.carlosrafaelgn.fplay.ui.SongAddingMonitor.java
br.com.carlosrafaelgn.fplay.ui.SongView.java
br.com.carlosrafaelgn.fplay.ui.UI.java
br.com.carlosrafaelgn.fplay.ui.drawable.BorderDrawable.java
br.com.carlosrafaelgn.fplay.ui.drawable.ColorDrawable.java
br.com.carlosrafaelgn.fplay.ui.drawable.NullDrawable.java
br.com.carlosrafaelgn.fplay.ui.drawable.StateDrawable.java
br.com.carlosrafaelgn.fplay.ui.drawable.TextIconDrawable.java
br.com.carlosrafaelgn.fplay.util.ArraySorter.java
br.com.carlosrafaelgn.fplay.util.BitmapLruCache.java
br.com.carlosrafaelgn.fplay.util.BluetoothConnectionManager.java
br.com.carlosrafaelgn.fplay.util.ColorUtils.java
br.com.carlosrafaelgn.fplay.util.ReleasableBitmapWrapper.java
br.com.carlosrafaelgn.fplay.util.SafeURLSpan.java
br.com.carlosrafaelgn.fplay.util.SerializableMap.java
br.com.carlosrafaelgn.fplay.util.Serializer.java
br.com.carlosrafaelgn.fplay.util.SlimLock.java
br.com.carlosrafaelgn.fplay.util.Timer.java
br.com.carlosrafaelgn.fplay.visualizer.BluetoothVisualizerJni.java
br.com.carlosrafaelgn.fplay.visualizer.OpenGLVisualizerJni.java
br.com.carlosrafaelgn.fplay.visualizer.SimpleVisualizerJni.java
br.com.carlosrafaelgn.fplay.visualizer.VisualizerView.java
br.com.carlosrafaelgn.fplay.visualizer.Visualizer.java