package com.airplayer.activity;
import android.Manifest;
import android.app.ProgressDialog;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.ServiceConnection;
import android.content.pm.PackageManager;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.os.IBinder;
import android.support.annotation.NonNull;
import android.support.design.widget.AppBarLayout;
import android.support.design.widget.NavigationView;
import android.support.design.widget.TabLayout;
import android.support.v4.app.ActivityCompat;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.view.GravityCompat;
import android.support.v4.widget.DrawerLayout;
import android.support.v7.app.ActionBarDrawerToggle;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.util.Log;
import android.view.MenuItem;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;
import com.airplayer.R;
import com.airplayer.fragment.PlayMusicFragment;
import com.airplayer.fragment.child.EqualizerFragment;
import com.airplayer.fragment.child.MyLibraryFragment;
import com.airplayer.fragment.child.RecentFragment;
import com.airplayer.model.AirModel;
import com.airplayer.model.PictureGettable;
import com.airplayer.service.PlayMusicService;
import com.airplayer.util.BitmapUtils;
import com.airplayer.util.StorageUtils;
import com.facebook.drawee.backends.pipeline.Fresco;
import com.sothree.slidinguppanel.SlidingUpPanelLayout;
import java.io.File;
import java.io.IOException;
import rx.Observable;
import rx.Observer;
import rx.android.schedulers.AndroidSchedulers;
import rx.functions.Action1;
import rx.functions.Func1;
import rx.schedulers.Schedulers;
public class AirMainActivity extends AppCompatActivity implements ActivityCompat.OnRequestPermissionsResultCallback {
public static final String TAG = "AirMainActivity";
public static final String EXTERNAL_PICTURE_FOLDER = Environment.getExternalStoragePublicDirectory(
Environment.DIRECTORY_PICTURES).getPath() + "/AirPlayer/";
// handle replace theme picture operation
public static final int PICK_PHOTO = 9;
// progress dialog when saving background picture
private ProgressDialog mProgress;
// ===== user interface =====
// ----- Left NavigationView -----
private DrawerLayout mDrawerLayout;
private NavigationView mNavigationView;
private ImageView mNavigationHeadImageView;
private TextView mNavigationHintTextView;
// ----- Top ActionBar -----
private Toolbar mToolbar;
private AppBarLayout mAppBarLayout;
private TabLayout mTabs;
// ----- Bottom SlidingUpPanel
private SlidingUpPanelLayout mSlidingUpPanelLayout;
// ===== service =====
private PlayMusicService.PlayerControlBinder playerControlBinder;
private ServiceConnection connection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
playerControlBinder = (PlayMusicService.PlayerControlBinder) service;
// set up bottom sliding fragment when service is connected
mPlayMusicFragment = new PlayMusicFragment();
mFragmentManager.beginTransaction().replace(R.id.sliding_fragment_container, mPlayMusicFragment).commit();
// set sliding up panel invisible when activity create
if (!playerControlBinder.isPlaying()) {
mSlidingUpPanelLayout.setTouchEnabled(false);
mSlidingUpPanelLayout.setPanelHeight(0);
} else {
mSlidingUpPanelLayout.setTouchEnabled(true);
mSlidingUpPanelLayout.setPanelHeight(mSize);
}
Log.d(TAG, "service has connected");
}
@Override
public void onServiceDisconnected(ComponentName name) {
Log.d(TAG, "service has disconnected");
}
};
// ===== receiver =====
private PlayerStateReceiver mPlayerStateReceiver;
// ===== helper classes =====
private FragmentManager mFragmentManager;
private PlayMusicFragment mPlayMusicFragment;
// ===== other resource =====
private int mSize;
private boolean hasInitialized = false;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// grant permission
ActivityCompat.requestPermissions(AirMainActivity.this, new String[]{ Manifest.permission.WRITE_EXTERNAL_STORAGE }, 1);
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
if (requestCode == 1) {
if (grantResults.length == 1 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// start to initialize when permission is granted
init();
} else {
// finish activity when permission is not granted
finish();
}
} else {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
}
}
private void init() {
Fresco.initialize(this);
AirModel.initModels(this);
// ===== get actionbarSize in attrs =====
int defaultInt = getResources().getDimensionPixelOffset(R.dimen.sliding_up_fragment_bottom_bar_height);
int[] attrsArray = { R.attr.actionBarSize };
TypedArray typedArray = obtainStyledAttributes(attrsArray);
mSize = typedArray.getDimensionPixelOffset(0, defaultInt);
typedArray.recycle();
// ===== bind service =====
Intent playMusicServiceIntent = new Intent(this, PlayMusicService.class);
playMusicServiceIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startService(playMusicServiceIntent);
bindService(playMusicServiceIntent, connection, BIND_AUTO_CREATE);
// ===== getup sliding up panel and set a listener =====
mSlidingUpPanelLayout = (SlidingUpPanelLayout) findViewById(R.id.sliding_up_panel_layout);
mSlidingUpPanelLayout.setPanelSlideListener(new SlidingUpPanelLayout.PanelSlideListener() {
@Override
public void onPanelSlide(View view, float v) { }
@Override
public void onPanelCollapsed(View view) {
Toolbar toolbar = mPlayMusicFragment.getSlidingUpPanelTopBar();
toolbar.getMenu().clear();
if (playerControlBinder.isPause()) {
toolbar.inflateMenu(R.menu.menu_sliding_panel_down_play_menu);
} else {
toolbar.inflateMenu(R.menu.menu_sliding_panel_down_pause_menu);
}
mDrawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED);
}
@Override
public void onPanelExpanded(View view) {
Toolbar toolbar = mPlayMusicFragment.getSlidingUpPanelTopBar();
toolbar.getMenu().clear();
toolbar.inflateMenu(R.menu.menu_sliding_panel_up_menu);
mDrawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED);
}
@Override
public void onPanelAnchored(View view) { }
@Override
public void onPanelHidden(View view) { }
});
// ===== get fragment manager =====
mFragmentManager = getSupportFragmentManager();
// ===== setup tool bar =====
mToolbar = (Toolbar) findViewById(R.id.global_toolbar);
mAppBarLayout = (AppBarLayout) findViewById(R.id.main_appbar_layout);
mTabs = (TabLayout) findViewById(R.id.tabs);
// ===== setup navigation drawer fragment =====
mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
mNavigationView = (NavigationView) findViewById(R.id.navigation_view);
setupNavigationDrawer();
mNavigationView.setCheckedItem(R.id.action_recent);
onNavigationDrawItemSelected(0);
// ===== setup and register receiver =====
mPlayerStateReceiver = new PlayerStateReceiver();
IntentFilter filter = new IntentFilter(PlayMusicService.PLAY_STATE_CHANGE);
registerReceiver(mPlayerStateReceiver, filter);
hasInitialized = true;
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (resultCode == RESULT_OK) {
switch (requestCode) {
case PictureGettable.REQUEST_CODE_FETCH_PICTURE:
mFragmentManager.findFragmentById(R.id.fragment_container)
.onActivityResult(requestCode, resultCode, data);
break;
case PICK_PHOTO:
Uri uri = data.getData();
Bitmap bm = BitmapUtils.getBitmap(this, uri);
if (bm.getByteCount() > 5120000) {
Toast.makeText(this, R.string.navigation_top_toast, Toast.LENGTH_SHORT).show();
} else {
mProgress = new ProgressDialog(this);
mProgress.setMessage("saving picture");
mProgress.show();
// use RxJava to save bitmap of ImageView which is the head of NavigationView
Observable.just(bm).map(new Func1<Bitmap, String>() {
@Override
public String call(Bitmap bitmap) {
try {
File file = StorageUtils.saveImage(AirMainActivity.this, "Theme.jpg", bitmap);
return file.getPath();
} catch (IOException e) {
e.printStackTrace();
return null;
}
}
}).subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<String>() {
@Override
public void onCompleted() {
mProgress.dismiss();
}
@Override
public void onError(Throwable e) {
e.printStackTrace();
Toast.makeText(AirMainActivity.this, "fail to save picture into external storage", Toast.LENGTH_SHORT).show();
}
@Override
public void onNext(String s) {
if (s != null) setNavigationImage(s);
else Toast.makeText(AirMainActivity.this, "fail to save picture into external storage", Toast.LENGTH_SHORT).show();
}
});
}
break;
}
} else {
super.onActivityResult(requestCode, resultCode, data);
}
}
@Override
protected void onDestroy() {
if (hasInitialized) {
unbindService(connection); /* unbind service */
unregisterReceiver(mPlayerStateReceiver); /* unregister receiver */
}
super.onDestroy();
}
@Override
public void onBackPressed() {
if (mDrawerLayout.isDrawerOpen(GravityCompat.START)) {
mDrawerLayout.closeDrawers();
} else if (mSlidingUpPanelLayout.getPanelState() == SlidingUpPanelLayout.PanelState.EXPANDED) {
if (mPlayMusicFragment.isPlayListShow()) {
super.onBackPressed();
mPlayMusicFragment.setIsPlayListShow(false);
} else {
mSlidingUpPanelLayout.setPanelState(SlidingUpPanelLayout.PanelState.COLLAPSED);
}
} else if (mSlidingUpPanelLayout.getPanelState() == SlidingUpPanelLayout.PanelState.COLLAPSED){
if (mPlayMusicFragment.isPlayListShow()) {
super.onBackPressed();
super.onBackPressed();
mPlayMusicFragment.setIsPlayListShow(false);
} else {
super.onBackPressed();
}
} else {
super.onBackPressed();
}
}
/**
* a convenient method to package codes of setting up NavigationView
*/
private void setupNavigationDrawer() {
mDrawerLayout.setDrawerShadow(R.drawable.drawer_shadow, GravityCompat.START);
final ActionBarDrawerToggle toggle;
toggle = new ActionBarDrawerToggle(
AirMainActivity.this,
mDrawerLayout,
mToolbar,
R.string.app_name,
R.string.app_name
);
mDrawerLayout.setDrawerListener(toggle);
mToolbar.setNavigationOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (mDrawerLayout.isDrawerOpen(mNavigationView)) {
mDrawerLayout.closeDrawers();
} else {
mDrawerLayout.openDrawer(mNavigationView);
}
}
});
mDrawerLayout.post(new Runnable() {
@Override
public void run() {
toggle.syncState();
}
});
mNavigationView.setNavigationItemSelectedListener(
new NavigationView.OnNavigationItemSelectedListener() {
@Override
public boolean onNavigationItemSelected(MenuItem menuItem) {
menuItem.setChecked(true);
mDrawerLayout.closeDrawers();
int position;
switch (menuItem.getItemId()) {
case R.id.action_recent:
position = 0;
break;
case R.id.action_library:
position = 1;
break;
case R.id.action_equalizer:
position = 2;
break;
default:
position = -1;
break;
}
onNavigationDrawItemSelected(position);
return true;
}
});
setupNavigationHeadView();
}
private void setupNavigationHeadView() {
View headView = mNavigationView.inflateHeaderView(R.layout.navigation_header);
mNavigationHeadImageView = (ImageView) headView.findViewById(R.id.navigation_image);
mNavigationHintTextView = (TextView) headView.findViewById(R.id.navigation_top_image_hint);
setNavigationImage(null);
mNavigationHeadImageView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
intent.setType("image/*");
startActivityForResult(intent, PICK_PHOTO);
}
});
}
private void setNavigationImage(String path) {
if (path == null || path.equals("")) {
File file = new File(AirMainActivity.EXTERNAL_PICTURE_FOLDER + "Theme.jpg");
if (file.exists()) {
path = file.getPath();
} else {
mNavigationHintTextView.setVisibility(View.VISIBLE);
return;
}
}
// user RxJava to set navigation head image
Observable.just(path)
.map(new Func1<String, Bitmap>() {
@Override
public Bitmap call(String path) {
return BitmapFactory.decodeFile(path);
}
})
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Action1<Bitmap>() {
@Override
public void call(Bitmap bitmap) {
mNavigationHeadImageView.setImageBitmap(bitmap);
}
});
mNavigationHintTextView.setVisibility(View.INVISIBLE);
}
/**
* handle NavigationDraw selected action
* @param position of NavigationDrawer item selected
*/
private void onNavigationDrawItemSelected(int position) {
if (position == -1) return;
String[] titles = { getResources().getString(R.string.toolbar_title_recent), getResources().getString(R.string.toolbar_title_Library), getResources().getString(R.string.toolbar_title_equalizer) };
mToolbar.setTitle(titles[position]);
mFragmentManager.beginTransaction()
.replace(R.id.fragment_container, switchFragment(position)).commit();
}
/**
* a convenient method to switch fragment with the position of selected item
* @param position of selected item
* @return a new Fragment whose name was selected in NavigationDrawer
*/
private Fragment switchFragment(int position) {
// pop all fragments in back stack
mFragmentManager.popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
// set play list is not showing when it popped
if (mPlayMusicFragment != null) {
mPlayMusicFragment.setIsPlayListShow(false);
}
switch (position) {
case 0:
return new RecentFragment();
case 1:
return new MyLibraryFragment();
case 2:
return new EqualizerFragment();
default:
return null;
}
}
/**
* getter of main tool bar
* @return main Toolbar
*/
public Toolbar getToolbar() {
return mToolbar;
}
/**
* getter of main AppbarLayout, use to add a TabLayout in { @link com.airplayer.fragment.child.MyLibraryFragment}
* @return main AppBarLayout
*/
public AppBarLayout getAppBarLayout() {
return mAppBarLayout;
}
/**
* getter of main PaddingTabs, use to setup a 1px tab to block the hiding action
* @return padding tabs
*/
public TabLayout getTabLayout() {
return mTabs;
}
/**
* getter of main DrawerLayout, use to lock in child fragment
* @return main DrawerLayout
*/
public DrawerLayout getDrawerLayout() {
return mDrawerLayout;
}
/**
* getter of binder of service
* @return service which control the music player and music play action
*/
public PlayMusicService.PlayerControlBinder getPlayerControlBinder() {
return playerControlBinder;
}
/**
* inside receiver to receiver player state broadcast
* to control the sliding up panel visible
*/
public class PlayerStateReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
int playState = intent.getIntExtra(PlayMusicService.PLAY_STATE_KEY, -1);
if (playState == PlayMusicService.PLAY_STATE_PLAY) {
if (!mSlidingUpPanelLayout.isTouchEnabled()) {
mSlidingUpPanelLayout.setTouchEnabled(true);
mSlidingUpPanelLayout.setPanelHeight(mSize);
}
if (mSlidingUpPanelLayout.getPanelState() == SlidingUpPanelLayout.PanelState.COLLAPSED) {
Toolbar toolbar = mPlayMusicFragment.getSlidingUpPanelTopBar();
toolbar.getMenu().clear();
toolbar.inflateMenu(R.menu.menu_sliding_panel_down_pause_menu);
}
} else if (playState == PlayMusicService.PLAY_STATE_PAUSE) {
if (mSlidingUpPanelLayout.getPanelState() == SlidingUpPanelLayout.PanelState.COLLAPSED) {
Toolbar toolbar = mPlayMusicFragment.getSlidingUpPanelTopBar();
toolbar.getMenu().clear();
toolbar.inflateMenu(R.menu.menu_sliding_panel_down_play_menu);
}
}
}
}
}