368 lines
12 KiB
Java
368 lines
12 KiB
Java
package max.music_cyclon;
|
|
|
|
|
|
import android.Manifest;
|
|
import android.app.ActivityManager;
|
|
import android.app.Dialog;
|
|
import android.app.ProgressDialog;
|
|
import android.content.ComponentName;
|
|
import android.content.Context;
|
|
import android.content.DialogInterface;
|
|
import android.content.Intent;
|
|
import android.content.ServiceConnection;
|
|
import android.content.pm.PackageManager;
|
|
import android.database.DataSetObserver;
|
|
import android.os.Bundle;
|
|
import android.os.Handler;
|
|
import android.os.IBinder;
|
|
import android.os.Message;
|
|
import android.os.Messenger;
|
|
import android.os.RemoteException;
|
|
import android.support.v4.app.ActivityCompat;
|
|
import android.support.v4.content.ContextCompat;
|
|
import android.support.v4.view.ViewPager;
|
|
import android.support.v7.app.AlertDialog;
|
|
import android.support.v7.app.AppCompatActivity;
|
|
import android.support.v7.widget.Toolbar;
|
|
import android.util.Log;
|
|
import android.view.Menu;
|
|
import android.view.MenuItem;
|
|
import android.view.View;
|
|
import android.widget.TextView;
|
|
import android.widget.Toast;
|
|
|
|
import com.google.samples.apps.iosched.ui.widget.SlidingTabLayout;
|
|
|
|
import org.json.JSONException;
|
|
|
|
import java.io.FileInputStream;
|
|
import java.io.FileOutputStream;
|
|
import java.io.IOException;
|
|
import java.lang.ref.WeakReference;
|
|
import java.util.Collections;
|
|
import java.util.List;
|
|
import java.util.UUID;
|
|
|
|
import max.music_cyclon.preference.MainPreferenceActivity;
|
|
import max.music_cyclon.service.LibraryService;
|
|
|
|
/**
|
|
* The main activity for synchronisation
|
|
* <p/>
|
|
* This class manages:
|
|
* <ul>
|
|
* <li>
|
|
* the {@link PagerAdapter} with the references to all configs and their loading and saving.
|
|
* </li>
|
|
* <li>the link to the {@link LibraryService} with bi-directional message dispatching</li>
|
|
* <li>the general layout</li>
|
|
* <li>permission requests</li>
|
|
* </ul>
|
|
*/
|
|
public class SynchronizeActivity extends AppCompatActivity {
|
|
|
|
public static final String DEFAULT_CONFIG_PATH = "configs.json";
|
|
|
|
private PagerAdapter pagerAdapter;
|
|
|
|
/**
|
|
* Messenger for communicating with service.
|
|
*/
|
|
private Messenger serviceObject = null;
|
|
/**
|
|
* Flag indicating whether we have called bind on the service.
|
|
*/
|
|
private boolean isBound;
|
|
|
|
/**
|
|
* The dialog which is being displayed while a sync is in progress
|
|
*/
|
|
private ProgressDialog syncProgress = null;
|
|
|
|
/**
|
|
* Target we publish for clients to send messages to IncomingHandler.
|
|
*/
|
|
private final Messenger mMessenger = new Messenger(
|
|
new IncomingHandler(new WeakReference<>(this))
|
|
);
|
|
|
|
@Override
|
|
protected void onCreate(Bundle savedInstanceState) {
|
|
super.onCreate(savedInstanceState);
|
|
setContentView(R.layout.activity_synchronize);
|
|
|
|
Toolbar toolbar = (Toolbar) findViewById(R.id.my_toolbar);
|
|
setSupportActionBar(toolbar);
|
|
|
|
List<SynchronizeConfig> configs = Collections.emptyList();
|
|
try {
|
|
FileInputStream in = openFileInput(DEFAULT_CONFIG_PATH);
|
|
configs = SynchronizeConfig.load(in);
|
|
in.close();
|
|
} catch (IOException | JSONException e) {
|
|
Log.e("CONFIG", "Failed loading the config", e);
|
|
}
|
|
|
|
pagerAdapter = new PagerAdapter(configs, getSupportFragmentManager());
|
|
|
|
if (pagerAdapter.getCount() == 0) {
|
|
pagerAdapter.add(getString(R.string.default_config_name));
|
|
}
|
|
|
|
final ViewPager pager = (ViewPager) findViewById(R.id.container);
|
|
assert pager != null;
|
|
pager.setAdapter(pagerAdapter);
|
|
|
|
|
|
// Initialize tabs
|
|
final SlidingTabLayout tabs = (SlidingTabLayout) findViewById(R.id.tabs);
|
|
assert tabs != null;
|
|
|
|
tabs.setTabLongClickListener(new View.OnLongClickListener() {
|
|
@Override
|
|
public boolean onLongClick(View v) {
|
|
CharSequence name = ((TextView) v).getText();
|
|
RenameDialogFragment dialog = new RenameDialogFragment();
|
|
dialog.setPreviousName(name.toString());
|
|
dialog.setAdapter(getPagerAdapter());
|
|
dialog.show(getSupportFragmentManager(), dialog.getClass().getName());
|
|
return true;
|
|
}
|
|
});
|
|
|
|
tabs.setDistributeEvenly(true);
|
|
tabs.setCustomTabColorizer(new SlidingTabLayout.TabColorizer() {
|
|
@Override
|
|
public int getIndicatorColor(int position) {
|
|
return ContextCompat.getColor(SynchronizeActivity.this, R.color.accentColor);
|
|
}
|
|
});
|
|
|
|
tabs.setViewPager(pager);
|
|
|
|
// Update tabs on dataset change
|
|
pagerAdapter.registerDataSetObserver(new DataSetObserver() {
|
|
@Override
|
|
public void onChanged() {
|
|
tabs.setViewPager(pager);
|
|
}
|
|
});
|
|
|
|
View addButton = findViewById(R.id.add_button);
|
|
assert addButton != null;
|
|
addButton.setOnClickListener(new View.OnClickListener() {
|
|
@Override
|
|
public void onClick(View v) {
|
|
pagerAdapter.add(UUID.randomUUID().toString().substring(0, 5));
|
|
pagerAdapter.notifyDataSetChanged();
|
|
}
|
|
});
|
|
|
|
// Request permissions
|
|
requestPermissions();
|
|
}
|
|
|
|
private void requestPermissions() {
|
|
if (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE)
|
|
!= PackageManager.PERMISSION_GRANTED) {
|
|
ActivityCompat.requestPermissions(
|
|
this,
|
|
new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},
|
|
0
|
|
);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
protected void onStop() {
|
|
super.onStop();
|
|
|
|
unbindLibraryService();
|
|
|
|
try {
|
|
FileOutputStream fos = openFileOutput(DEFAULT_CONFIG_PATH, Context.MODE_PRIVATE);
|
|
getPagerAdapter().save(fos);
|
|
fos.close();
|
|
} catch (IOException | JSONException e) {
|
|
Log.e("CONFIG", "Failed saving the config", e);
|
|
}
|
|
}
|
|
|
|
public PagerAdapter getPagerAdapter() {
|
|
return pagerAdapter;
|
|
}
|
|
|
|
public Dialog getSyncProgress() {
|
|
return syncProgress;
|
|
}
|
|
|
|
public void clearSyncProgress() {
|
|
syncProgress = null;
|
|
}
|
|
|
|
@Override
|
|
public boolean onCreateOptionsMenu(Menu menu) {
|
|
getMenuInflater().inflate(R.menu.menu_main, menu);
|
|
return true;
|
|
}
|
|
|
|
@Override
|
|
public boolean onOptionsItemSelected(MenuItem item) {
|
|
switch (item.getItemId()) {
|
|
case R.id.action_settings:
|
|
Intent preferenceIntent = new Intent(this, MainPreferenceActivity.class);
|
|
startActivity(preferenceIntent);
|
|
return true;
|
|
case R.id.action_version:
|
|
notYetImplemented(this);
|
|
break;
|
|
case R.id.action_help:
|
|
notYetImplemented(this);
|
|
break;
|
|
case R.id.action_sync:
|
|
if (isServiceRunning(LibraryService.class)) {
|
|
Toast.makeText(this, R.string.already_synchronizing, Toast.LENGTH_LONG).show();
|
|
return false;
|
|
}
|
|
|
|
startLibraryService();
|
|
|
|
bindLibraryService();
|
|
|
|
// Show sync control dialog
|
|
syncProgress = new ProgressDialog(SynchronizeActivity.this);
|
|
syncProgress.setMessage(getString(R.string.synchronizing));
|
|
syncProgress.setCancelable(false);
|
|
// syncProgress.setButton(
|
|
// DialogInterface.BUTTON_NEGATIVE,
|
|
// getString(android.R.string.cancel),
|
|
// new DialogInterface.OnClickListener() {
|
|
// @Override
|
|
// public void onClick(DialogInterface dialog, int which) {
|
|
// dialog.dismiss();
|
|
// }
|
|
// });
|
|
// syncProgress.show();
|
|
return true;
|
|
default:
|
|
return super.onOptionsItemSelected(item);
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
public static void notYetImplemented(Context context) {
|
|
new AlertDialog.Builder(context).setMessage("Not yet implemented!").show();
|
|
}
|
|
|
|
private static class IncomingHandler extends Handler {
|
|
private final WeakReference<SynchronizeActivity> activity;
|
|
|
|
private IncomingHandler(WeakReference<SynchronizeActivity> activity) {
|
|
this.activity = activity;
|
|
}
|
|
|
|
@Override
|
|
public void handleMessage(Message msg) {
|
|
SynchronizeActivity activity = this.activity.get();
|
|
if (activity == null) {
|
|
return;
|
|
}
|
|
|
|
switch (msg.what) {
|
|
case LibraryService.MSG_FINISHED:
|
|
activity.unbindLibraryService();
|
|
|
|
Dialog dialog = activity.getSyncProgress();
|
|
if (dialog != null) {
|
|
dialog.dismiss();
|
|
activity.clearSyncProgress();
|
|
}
|
|
|
|
break;
|
|
default:
|
|
super.handleMessage(msg);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Class for interacting with the main interface of the service.
|
|
*/
|
|
private ServiceConnection mConnection = new ServiceConnection() {
|
|
public void onServiceConnected(ComponentName className, IBinder service) {
|
|
serviceObject = new Messenger(service);
|
|
|
|
try {
|
|
Message msg = Message.obtain(null, LibraryService.MSG_REGISTER_CLIENT);
|
|
msg.replyTo = mMessenger;
|
|
serviceObject.send(msg);
|
|
} catch (RemoteException ignored) {
|
|
// In this case the service has crashed before we could even
|
|
// do anything with it; we can count on soon being
|
|
// disconnected (and then reconnected if it can be restarted)
|
|
// so there is no need to do anything here.
|
|
}
|
|
}
|
|
|
|
public void onServiceDisconnected(ComponentName className) {
|
|
serviceObject = null;
|
|
}
|
|
};
|
|
|
|
private void startLibraryService() {
|
|
Intent intent = new Intent(SynchronizeActivity.this, LibraryService.class);
|
|
List<SynchronizeConfig> configs = getPagerAdapter().getConfigs();
|
|
|
|
// Update last updated
|
|
for (SynchronizeConfig config : configs) {
|
|
config.updateLastUpdated(); // fixme the result of LibraryService does not affect this (for example: Remote not available)
|
|
}
|
|
|
|
intent.putExtra(
|
|
LibraryService.ARGUMENT_CONFIGS,
|
|
configs.toArray(new SynchronizeConfig[configs.size()])
|
|
);
|
|
startService(intent);
|
|
}
|
|
|
|
private boolean isServiceRunning(Class<?> serviceClass) {
|
|
ActivityManager manager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
|
|
List<ActivityManager.RunningServiceInfo> services =
|
|
manager.getRunningServices(Integer.MAX_VALUE);
|
|
|
|
for (ActivityManager.RunningServiceInfo service : services) {
|
|
if (serviceClass.getName().equals(service.service.getClassName())) {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
private void bindLibraryService() {
|
|
bindService(new Intent(
|
|
SynchronizeActivity.this,
|
|
LibraryService.class
|
|
), mConnection, Context.BIND_AUTO_CREATE);
|
|
isBound = true;
|
|
}
|
|
|
|
private void unbindLibraryService() {
|
|
if (isBound) {
|
|
if (serviceObject != null) {
|
|
try {
|
|
Message msg = Message.obtain(null, LibraryService.MSG_UNREGISTER_CLIENT);
|
|
msg.replyTo = mMessenger;
|
|
serviceObject.send(msg);
|
|
} catch (RemoteException ignored) {
|
|
}
|
|
}
|
|
|
|
// Detach our existing connection.
|
|
unbindService(mConnection);
|
|
isBound = false;
|
|
}
|
|
}
|
|
}
|