package com.seafile.seadroid2.ui.activity;
import android.accounts.AccountManagerCallback;
import android.accounts.AccountManagerFuture;
import android.accounts.OnAccountsUpdateListener;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.IBinder;
import android.support.v7.widget.Toolbar;
import android.util.Log;
import android.view.ContextMenu;
import android.view.ContextMenu.ContextMenuInfo;
import android.view.LayoutInflater;
import android.view.MenuItem;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.AdapterContextMenuInfo;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.Button;
import android.widget.ListView;
import com.google.common.collect.Lists;
import com.seafile.seadroid2.R;
import com.seafile.seadroid2.SeafConnection;
import com.seafile.seadroid2.SeafException;
import com.seafile.seadroid2.account.Account;
import com.seafile.seadroid2.account.AccountManager;
import com.seafile.seadroid2.account.Authenticator;
import com.seafile.seadroid2.avatar.Avatar;
import com.seafile.seadroid2.avatar.AvatarManager;
import com.seafile.seadroid2.monitor.FileMonitorService;
import com.seafile.seadroid2.ui.adapter.AccountAdapter;
import com.seafile.seadroid2.ui.adapter.SeafAccountAdapter;
import com.seafile.seadroid2.util.ConcurrentAsyncTask;
import com.seafile.seadroid2.util.Utils;
import java.util.ArrayList;
import java.util.List;
public class AccountsActivity extends BaseActivity implements Toolbar.OnMenuItemClickListener{
private static final String DEBUG_TAG = "AccountsActivity";
public static final int DETAIL_ACTIVITY_REQUEST = 1;
private ListView accountsView;
private android.accounts.AccountManager mAccountManager;
private AccountManager accountManager;
private AvatarManager avatarManager;
private AccountAdapter adapter;
private List<Account> accounts;
private FileMonitorService mMonitorService;
private Account currentDefaultAccount;
private OnAccountsUpdateListener accountsUpdateListener = new OnAccountsUpdateListener() {
@Override
public void onAccountsUpdated(android.accounts.Account[] accounts) {
refreshView();
}
};
private ServiceConnection mMonitorConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName className, IBinder binder) {
FileMonitorService.MonitorBinder monitorBinder = (FileMonitorService.MonitorBinder)binder;
mMonitorService = monitorBinder.getService();
}
@Override
public void onServiceDisconnected(ComponentName className) {
mMonitorService = null;
}
};
@Override
public void onCreate(Bundle savedInstanceState) {
Log.d(DEBUG_TAG, "AccountsActivity.onCreate is called");
super.onCreate(savedInstanceState);
setContentView(R.layout.start);
mAccountManager = android.accounts.AccountManager.get(this);
accountsView = (ListView) findViewById(R.id.account_list_view);
accountManager = new AccountManager(this);
avatarManager = new AvatarManager();
currentDefaultAccount = accountManager.getCurrentAccount();
View footerView = ((LayoutInflater) this
.getSystemService(Context.LAYOUT_INFLATER_SERVICE)).inflate(
R.layout.account_list_footer, null, false);
Button addAccount = (Button) footerView.findViewById(R.id.account_footer_btn);
addAccount.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View btn) {
mAccountManager.addAccount(Account.ACCOUNT_TYPE,
Authenticator.AUTHTOKEN_TYPE, null, null,
AccountsActivity.this, accountCallback, null);
}
});
accountsView.addFooterView(footerView, null, true);
accountsView.setFooterDividersEnabled(false);
adapter = new SeafAccountAdapter(this);
accountsView.setAdapter(adapter);
accountsView.setOnItemClickListener(new OnItemClickListener() {
public void onItemClick(AdapterView<?> parent, View view, int position,
long id) {
Account account = accounts.get(position);
if (!account.hasValidToken()) {
// user already signed out, input password first
startEditAccountActivity(account);
} else {
// update current Account info from SharedPreference
accountManager.saveCurrentAccount(account.getSignature());
startFilesActivity();
}
}
});
mAccountManager.addOnAccountsUpdatedListener(accountsUpdateListener, null, false);
registerForContextMenu(accountsView);
Toolbar toolbar = getActionBarToolbar();
toolbar.setOnMenuItemClickListener(this);
setSupportActionBar(toolbar);
accounts = accountManager.getAccountList();
// updates toolbar back button
if (currentDefaultAccount == null || !currentDefaultAccount.hasValidToken()) {
getSupportActionBar().setDisplayHomeAsUpEnabled(false);
} else {
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
}
getSupportActionBar().setTitle(R.string.accounts);
}
@Override
public void onStart() {
Log.d(DEBUG_TAG, "onStart");
super.onStart();
Intent bIntent = new Intent(this, FileMonitorService.class);
bindService(bIntent, mMonitorConnection, Context.BIND_AUTO_CREATE);
}
@Override
public void onStop() {
Log.d(DEBUG_TAG, "onStop");
super.onStop();
}
@Override
protected void onDestroy() {
Log.d(DEBUG_TAG, "onDestroy");
super.onDestroy();
if (mMonitorService != null) {
unbindService(mMonitorConnection);
mMonitorService = null;
}
mAccountManager.removeOnAccountsUpdatedListener(accountsUpdateListener);
}
// Always reload accounts on resume, so that when user add a new account,
// it will be shown.
@Override
public void onResume() {
Log.d(DEBUG_TAG, "onResume");
super.onResume();
refreshView();
}
@Override
public boolean onMenuItemClick(MenuItem item) {
return super.onOptionsItemSelected(item);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
// if the current account sign out and no account was to logged in,
// then always goes to AccountsActivity
if (accountManager.getCurrentAccount() == null) {
Intent intent = new Intent(this, BrowserActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(intent);
}
this.finish();
default:
return super.onOptionsItemSelected(item);
}
}
private void refreshView() {
Log.d(DEBUG_TAG, "refreshView");
accounts = accountManager.getAccountList();
adapter.clear();
adapter.setItems(accounts);
// if the user switched default account while we were in background,
// switch to BrowserActivity
Account newCurrentAccount = accountManager.getCurrentAccount();
if (newCurrentAccount != null && !newCurrentAccount.equals(currentDefaultAccount)) {
startFilesActivity();
}
// updates toolbar back button
if (newCurrentAccount == null || !newCurrentAccount.hasValidToken()) {
getSupportActionBar().setDisplayHomeAsUpEnabled(false);
}
loadAvatarUrls(48);
adapter.notifyChanged();
}
private void startFilesActivity() {
Intent intent = new Intent(this, BrowserActivity.class);
// first finish this activity, so the BrowserActivity is again "on top"
finish();
startActivity(intent);
}
AccountManagerCallback<Bundle> accountCallback = new AccountManagerCallback<Bundle>() {
@Override
public void run(AccountManagerFuture<Bundle> future) {
if (future.isCancelled())
return;
try {
Bundle b = future.getResult();
if (b.getBoolean(android.accounts.AccountManager.KEY_BOOLEAN_RESULT)) {
String accountName = b.getString(android.accounts.AccountManager.KEY_ACCOUNT_NAME);
Log.d(DEBUG_TAG, "switching to account " + accountName);
accountManager.saveCurrentAccount(accountName);
startFilesActivity();
}
} catch (Exception e) {
Log.e(DEBUG_TAG, "unexpected error: " + e);
}
}
};
private void startEditAccountActivity(Account account) {
mAccountManager.updateCredentials(account.getAndroidAccount(), Authenticator.AUTHTOKEN_TYPE, null, this, accountCallback, null);
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
switch (requestCode) {
case DETAIL_ACTIVITY_REQUEST:
if (resultCode == RESULT_OK) {
startFilesActivity();
}
break;
default:
break;
}
}
@Override
public void onCreateContextMenu(ContextMenu menu, View v,
ContextMenuInfo menuInfo) {
super.onCreateContextMenu(menu, v, menuInfo);
android.view.MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.account_menu, menu);
}
@Override
public boolean onContextItemSelected(android.view.MenuItem item) {
AdapterContextMenuInfo info = (AdapterContextMenuInfo) item.getMenuInfo();
Account account;
switch (item.getItemId()) {
case R.id.edit:
account = adapter.getItem((int)info.id);
startEditAccountActivity(account);
return true;
case R.id.delete:
account = adapter.getItem((int)info.id);
Log.d(DEBUG_TAG, "removing account "+account);
mAccountManager.removeAccount(account.getAndroidAccount(), null, null);
if (mMonitorService != null) {
mMonitorService.removeAccount(account);
}
return true;
default:
return super.onContextItemSelected(item);
}
}
@Override
public void onBackPressed() {
Account account = accountManager.getCurrentAccount();
if (account != null) {
// force exit when current account was deleted
Intent i = new Intent(this, BrowserActivity.class);
i.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(i);
finish();
} else
super.onBackPressed();
}
/**
* asynchronously load avatars
*
* @param avatarSize set a avatar size in one of 24*24, 32*32, 48*48, 64*64, 72*72, 96*96
*/
public void loadAvatarUrls(int avatarSize) {
List<Avatar> avatars;
if (!Utils.isNetworkOn() || !avatarManager.isNeedToLoadNewAvatars()) {
// Toast.makeText(AccountsActivity.this, getString(R.string.network_down), Toast.LENGTH_SHORT).show();
// use cached avatars
avatars = avatarManager.getAvatarList();
if (avatars == null) {
return;
}
// set avatars url to adapter
adapter.setAvatars((ArrayList<Avatar>) avatars);
// notify adapter data changed
adapter.notifyDataSetChanged();
return;
}
LoadAvatarUrlsTask task = new LoadAvatarUrlsTask(avatarSize);
ConcurrentAsyncTask.execute(task);
}
private class LoadAvatarUrlsTask extends AsyncTask<Void, Void, List<Avatar>> {
private List<Avatar> avatars;
private int avatarSize;
private SeafConnection httpConnection;
public LoadAvatarUrlsTask(int avatarSize) {
this.avatarSize = avatarSize;
this.avatars = Lists.newArrayList();
}
@Override
protected List<Avatar> doInBackground(Void... params) {
// reuse cached avatars
avatars = avatarManager.getAvatarList();
// contains accounts who don`t have avatars yet
List<Account> acts = avatarManager.getAccountsWithoutAvatars();
// contains new avatars in order to persist them to database
List<Avatar> newAvatars = new ArrayList<Avatar>(acts.size());
// load avatars from server
for (Account account : acts) {
httpConnection = new SeafConnection(account);
String avatarRawData = null;
try {
avatarRawData = httpConnection.getAvatar(account.getEmail(), avatarSize);
} catch (SeafException e) {
e.printStackTrace();
return avatars;
}
Avatar avatar = avatarManager.parseAvatar(avatarRawData);
if (avatar == null)
continue;
avatar.setSignature(account.getSignature());
avatars.add(avatar);
newAvatars.add(avatar);
}
// save new added avatars to database
avatarManager.saveAvatarList(newAvatars);
return avatars;
}
@Override
protected void onPostExecute(List<Avatar> avatars) {
if (avatars == null) {
return;
}
// set avatars url to adapter
adapter.setAvatars((ArrayList<Avatar>) avatars);
// notify adapter data changed
adapter.notifyDataSetChanged();
}
}
}