preserve drawer state on screen rotation and resumes, move color calculation code to utils class

This commit is contained in:
Andy Scherzinger 2016-03-24 13:16:52 +01:00
parent f32493c6f1
commit 0f8f714645
2 changed files with 148 additions and 130 deletions

View file

@ -7,7 +7,6 @@ import android.accounts.AccountManagerFuture;
import android.accounts.OperationCanceledException;
import android.content.Intent;
import android.content.res.Configuration;
import android.graphics.Color;
import android.os.Bundle;
import android.support.design.widget.NavigationView;
import android.support.v4.view.GravityCompat;
@ -30,49 +29,71 @@ import com.owncloud.android.lib.resources.status.OCCapability;
import com.owncloud.android.ui.TextDrawable;
import com.owncloud.android.utils.BitmapUtils;
import java.io.UnsupportedEncodingException;
import java.math.BigInteger;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
/**
* Base class to handle setup of the drawer implementation.
*/
public abstract class DrawerActivity extends ToolbarActivity {
private static final String TAG = DrawerActivity.class.getSimpleName();
private static final String KEY_IS_ACCOUNT_CHOOSER_ACTIVE = "IS_ACCOUNT_CHOOSER_ACTIVE";
// Navigation Drawer
/**
* Reference to the drawer layout.
*/
private DrawerLayout mDrawerLayout;
/**
* Reference to the drawer toggle.
*/
private ActionBarDrawerToggle mDrawerToggle;
/**
* Reference to the navigation view.
*/
private NavigationView mNavigationView;
/**
* Reference to the account chooser toogle.
*/
private ImageView mAccountChooserToggle;
/** OwnCloud {@link Account} where the main {@link OCFile} handled by the activity is located.*/
/**
* ownCloud {@link Account} where the main {@link OCFile} handled by the activity is located.
*/
private Account mCurrentAccount;
/**
* Flag to signal if the account chooser is active.
*/
private boolean mIsAccountChooserActive;
/** Flag to signal that the activity will is finishing to enforce the creation of an ownCloud
* {@link Account} */
/**
* Flag to signal that the activity will is finishing to enforce the creation of an ownCloud {@link Account}.
*/
private boolean mRedirectingToSetupAccount = false;
/** Flag to signal when the value of mAccount was set */
/**
* Flag to signal when the value of mAccount was set.
*/
protected boolean mAccountWasSet;
/** Flag to signal when the value of mAccount was restored from a saved state */
/**
* Flag to signal when the value of mAccount was restored from a saved state.
*/
protected boolean mAccountWasRestored;
/** Capabilites of the server where {@link #mCurrentAccount} lives */
/**
* Capabilites of the server where {@link #mCurrentAccount} lives.
*/
private OCCapability mCapabilities;
/** Access point to the cached database for the current ownCloud {@link Account} */
/**
* Access point to the cached database for the current ownCloud {@link Account}.
*/
private FileDataStorageManager mStorageManager = null;
/**
* Initializes the drawer and its content. This method needs to be called after the content view has been set.
* Initializes the drawer and its content.
* This method needs to be called after the content view has been set.
*/
protected void setupDrawer() {
mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
@ -93,52 +114,15 @@ public abstract class DrawerActivity extends ToolbarActivity {
});
}
// TODO re-enable when "Accounts" is available in Navigation Drawer
// // load Account in the Drawer Title
// // User-Icon
// ImageView userIcon = (ImageView) navigationDrawerLayout.findViewById(R.id.drawer_userIcon);
// userIcon.setImageResource(DisplayUtils.getSeasonalIconId());
//
// // Username
// TextView username = (TextView) navigationDrawerLayout.findViewById(R.id.drawer_username);
// Account account = AccountUtils.getCurrentOwnCloudAccount(getApplicationContext());
//
// if (account != null) {
// int lastAtPos = account.name.lastIndexOf("@");
// username.setText(account.name.substring(0, lastAtPos));
// }
/*
// Display username in drawer
setUsernameInDrawer(navigationDrawerLayout, AccountUtils.getCurrentOwnCloudAccount(getApplicationContext()));
// load slide menu items
mDrawerTitles = getResources().getStringArray(R.array.drawer_items);
// nav drawer content description from resources
mDrawerContentDescriptions = getResources().
getStringArray(R.array.drawer_content_descriptions);
// nav drawer items
mDrawerItems = new ArrayList<NavigationDrawerItem>();
// adding nav drawer items to array
// TODO re-enable when "Accounts" is available in Navigation Drawer
// Accounts
// mDrawerItems.add(new NavigationDrawerItem(mDrawerTitles[0],
// mDrawerContentDescriptions[0]));
// All Files
mDrawerItems.add(new NavigationDrawerItem(mDrawerTitles[0], mDrawerContentDescriptions[0],
R.drawable.ic_folder_open));
// TODO Enable when "On Device" is recovered
// On Device
//mDrawerItems.add(new NavigationDrawerItem(mDrawerTitles[2],
// mDrawerContentDescriptions[2]));
*/
mDrawerToggle = new ActionBarDrawerToggle(this, mDrawerLayout, R.string.drawer_open, R.string.drawer_close) {
/** Called when a drawer has settled in a completely closed state. */
public void onDrawerClosed(View view) {
super.onDrawerClosed(view);
// standard behavior of drawer is to switch to the standard menu on closing
if (mIsAccountChooserActive) {
toggleAccountList();
}
updateActionBarTitleAndHomeButton(null);
invalidateOptionsMenu();
}
@ -151,10 +135,7 @@ public abstract class DrawerActivity extends ToolbarActivity {
invalidateOptionsMenu();
}
};
/*
// Set the list's click listener
mDrawerList.setOnItemClickListener(new DrawerItemClickListener());
*/
// Set the drawer toggle as the DrawerListener
mDrawerLayout.setDrawerListener(mDrawerToggle);
mDrawerToggle.setDrawerIndicatorEnabled(false);
@ -193,18 +174,22 @@ public abstract class DrawerActivity extends ToolbarActivity {
case Menu.NONE:
// account clicked
AccountUtils.setCurrentOwnCloudAccount(
getApplicationContext(),menuItem.getTitle().toString());
getApplicationContext(), menuItem.getTitle().toString());
restart();
default:
Log_OC.i(TAG,"Unknown drawer menu item clicked: " + menuItem.getTitle());
Log_OC.i(TAG, "Unknown drawer menu item clicked: " + menuItem.getTitle());
}
return true;
}
});
// hide accounts
mNavigationView.getMenu().setGroupVisible(R.id.drawer_menu_accounts, false);
// handle correct state
if (mIsAccountChooserActive) {
mNavigationView.getMenu().setGroupVisible(R.id.drawer_menu_accounts, true);
} else {
mNavigationView.getMenu().setGroupVisible(R.id.drawer_menu_accounts, false);
}
}
/**
@ -281,7 +266,7 @@ public abstract class DrawerActivity extends ToolbarActivity {
// add all accounts to list
for (int i = 0; i < accounts.length; i++) {
try {
int[] rgb = calculateRGB(accounts[i].name);
int[] rgb = BitmapUtils.calculateRGB(accounts[i].name);
TextDrawable icon = new TextDrawable(accounts[i].name.substring(0, 1).toUpperCase()
, rgb[0], rgb[1], rgb[2]);
mNavigationView.getMenu().add(R.id.drawer_menu_accounts, Menu.NONE, 0, accounts[i].name).setIcon(icon);
@ -293,26 +278,7 @@ public abstract class DrawerActivity extends ToolbarActivity {
}
// adding sets menu group back to visible, so safety check and setting invisible
if (!mIsAccountChooserActive) {
mNavigationView.getMenu().setGroupVisible(R.id.drawer_menu_accounts, false);
}
}
private int[] calculateRGB(String accountName) throws UnsupportedEncodingException, NoSuchAlgorithmException {
// using adapted algorithm from /core/js/placeholder.js:50
int lastAtPos = accountName.lastIndexOf("@");
String username = accountName.substring(0, lastAtPos);
byte[] seed = username.getBytes("UTF-8");
MessageDigest md = MessageDigest.getInstance("MD5");
// Integer seedMd5Int = Math.abs(new String(Hex.encodeHex(seedMd5))
// .hashCode());
Integer seedMd5Int = String.format(Locale.ROOT, "%032x",
new BigInteger(1, md.digest(seed))).hashCode();
double maxRange = Integer.MAX_VALUE;
float hue = (float) (seedMd5Int / maxRange * 360);
return BitmapUtils.HSLtoRGB(hue, 90.0f, 65.0f, 1.0f);
showMenu();
}
/**
@ -348,38 +314,67 @@ public abstract class DrawerActivity extends ToolbarActivity {
int lastAtPos = accountName.lastIndexOf("@");
username.setText(accountName.substring(0, lastAtPos));
ImageView usericon = (ImageView) ((NavigationView) findViewById(R.id.nav_view))
ImageView userIcon = (ImageView) ((NavigationView) findViewById(R.id.nav_view))
.getHeaderView(0).findViewById(R.id.drawer_usericon);
try {
int[] rgb = calculateRGB(accountName);
int[] rgb = BitmapUtils.calculateRGB(accountName);
TextDrawable icon = new TextDrawable(
accountName.substring(0, 1).toUpperCase(), rgb[0], rgb[1], rgb[2]);
usericon.setImageDrawable(icon);
userIcon.setImageDrawable(icon);
} catch (Exception e) {
Log_OC.e(TAG, "Error calculating RGB value for active account icon.", e);
usericon.setImageResource(R.drawable.ic_account_circle);
userIcon.setImageResource(R.drawable.ic_account_circle);
}
}
}
/**
* Toggle between drawer menu and account list.
* Toggle between standard menu and account list including saving the state.
*/
private void toggleAccountList() {
if (mIsAccountChooserActive) {
// TODO close accounts list and display drawer menu again
mAccountChooserToggle.setImageResource(R.drawable.ic_down);
mNavigationView.getMenu().setGroupVisible(R.id.drawer_menu_accounts, false);
mNavigationView.getMenu().setGroupVisible(R.id.drawer_menu_standard, true);
mIsAccountChooserActive = !mIsAccountChooserActive;
showMenu();
}
} else {
// TODO show accounts list
/**
* depending on the #mIsAccountChooserActive flag shows the account chooser or the standard menu.
*/
private void showMenu() {
if (mIsAccountChooserActive) {
mAccountChooserToggle.setImageResource(R.drawable.ic_up);
mNavigationView.getMenu().setGroupVisible(R.id.drawer_menu_accounts, true);
mNavigationView.getMenu().setGroupVisible(R.id.drawer_menu_standard, false);
} else {
mAccountChooserToggle.setImageResource(R.drawable.ic_down);
mNavigationView.getMenu().setGroupVisible(R.id.drawer_menu_accounts, false);
mNavigationView.getMenu().setGroupVisible(R.id.drawer_menu_standard, true);
}
}
mIsAccountChooserActive = !mIsAccountChooserActive;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (savedInstanceState != null) {
mIsAccountChooserActive = savedInstanceState.getBoolean(KEY_IS_ACCOUNT_CHOOSER_ACTIVE, false);
}
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putBoolean(KEY_IS_ACCOUNT_CHOOSER_ACTIVE, mIsAccountChooserActive);
}
@Override
public void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
mIsAccountChooserActive = savedInstanceState.getBoolean(KEY_IS_ACCOUNT_CHOOSER_ACTIVE, false);
// (re-)setup drawer state
showMenu();
}
@Override
@ -423,21 +418,21 @@ public abstract class DrawerActivity extends ToolbarActivity {
return ((NavigationView) findViewById(R.id.nav_view)).getHeaderView(0).findViewById(id);
}
public void restart(){
public void restart() {
Intent i = new Intent(this, FileDisplayActivity.class);
i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(i);
}
/**
* Sets and validates the ownCloud {@link Account} associated to the Activity.
* Sets and validates the ownCloud {@link Account} associated to the Activity.
* <p/>
* If not valid, tries to swap it for other valid and existing ownCloud {@link Account}.
* <p/>
* POSTCONDITION: updates {@link #mAccountWasSet} and {@link #mAccountWasRestored}.
*
* If not valid, tries to swap it for other valid and existing ownCloud {@link Account}.
*
* POSTCONDITION: updates {@link #mAccountWasSet} and {@link #mAccountWasRestored}.
*
* @param account New {@link Account} to set.
* @param savedAccount When 'true', account was retrieved from a saved instance state.
* @param account New {@link Account} to set.
* @param savedAccount When 'true', account was retrieved from a saved instance state.
*/
protected void setAccount(Account account, boolean savedAccount) {
Account oldAccount = mCurrentAccount;
@ -454,14 +449,13 @@ public abstract class DrawerActivity extends ToolbarActivity {
}
}
/**
* Tries to swap the current ownCloud {@link Account} for other valid and existing.
*
* If no valid ownCloud {@link Account} exists, the the user is requested
* to create a new ownCloud {@link Account}.
*
* POSTCONDITION: updates {@link #mAccountWasSet} and {@link #mAccountWasRestored}.
* Tries to swap the current ownCloud {@link Account} for other valid and existing.
* <p/>
* If no valid ownCloud {@link Account} exists, the the user is requested
* to create a new ownCloud {@link Account}.
* <p/>
* POSTCONDITION: updates {@link #mAccountWasSet} and {@link #mAccountWasRestored}.
*/
protected void swapToDefaultAccount() {
// default to the most recently used account
@ -480,9 +474,8 @@ public abstract class DrawerActivity extends ToolbarActivity {
}
}
/**
* Launches the account creation activity. To use when no ownCloud account is available
* Launches the account creation activity. To use when no ownCloud account is available.
*/
private void createFirstAccount() {
AccountManager am = AccountManager.get(getApplicationContext());
@ -498,7 +491,7 @@ public abstract class DrawerActivity extends ToolbarActivity {
/**
* Helper class handling a callback from the {@link AccountManager} after the creation of
* a new ownCloud {@link Account} finished, successfully or not.
*
* <p/>
* At this moment, only called after the creation of the first account.
*/
public class AccountCreationCallback implements AccountManagerCallback<Bundle> {
@ -534,15 +527,14 @@ public abstract class DrawerActivity extends ToolbarActivity {
}
/**
* Called when the ownCloud {@link Account} associated to the Activity was just updated.
*
* Child classes must grant that state depending on the {@link Account} is updated.
* Called when the ownCloud {@link Account} associated to the Activity was just updated.
* <p/>
* Child classes must grant that state depending on the {@link Account} is updated.
*/
protected void onAccountSet(boolean stateWasRecovered) {
if (getAccount() != null) {
mStorageManager = new FileDataStorageManager(getAccount(), getContentResolver());
mCapabilities = mStorageManager.getCapability(mCurrentAccount.name);
} else {
Log_OC.wtf(TAG, "onAccountChanged was called with NULL account associated!");
}
@ -552,24 +544,22 @@ public abstract class DrawerActivity extends ToolbarActivity {
mCurrentAccount = account;
}
/**
* Getter for the capabilities of the server where the current OC account lives.
*
* @return Capabilities of the server where the current OC account lives. Null if the account is not
* set yet.
* @return Capabilities of the server where the current OC account lives. Null if the account is not
* set yet.
*/
public OCCapability getCapabilities() {
return mCapabilities;
}
/**
* Getter for the ownCloud {@link Account} where the main {@link OCFile} handled by the activity
* is located.
*
* @return OwnCloud {@link Account} where the main {@link OCFile} handled by the activity
* is located.
* @return OwnCloud {@link Account} where the main {@link OCFile} handled by the activity
* is located.
*/
public Account getAccount() {
return mCurrentAccount;

View file

@ -30,6 +30,11 @@ import android.net.Uri;
import android.webkit.MimeTypeMap;
import java.io.File;
import java.io.UnsupportedEncodingException;
import java.math.BigInteger;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Locale;
/**
* Utility class with methods for decoding Bitmaps.
@ -266,5 +271,28 @@ public class BitmapUtils {
return (mimeType != null && mimeType.startsWith("image/"));
}
/**
* calculates the RGB value based on a given account name.
*
* @param accountName The account name
* @return corresponding RGB color
* @throws UnsupportedEncodingException if the charset is not supported
* @throws NoSuchAlgorithmException if the specified algorithm is not available
*/
public static int[] calculateRGB(String accountName) throws UnsupportedEncodingException, NoSuchAlgorithmException {
// using adapted algorithm from /core/js/placeholder.js:50
int lastAtPos = accountName.lastIndexOf("@");
String username = accountName.substring(0, lastAtPos);
byte[] seed = username.getBytes("UTF-8");
MessageDigest md = MessageDigest.getInstance("MD5");
// Integer seedMd5Int = Math.abs(new String(Hex.encodeHex(seedMd5)).hashCode());
Integer seedMd5Int = String.format(Locale.ROOT, "%032x",
new BigInteger(1, md.digest(seed))).hashCode();
double maxRange = Integer.MAX_VALUE;
float hue = (float) (seedMd5Int / maxRange * 360);
return BitmapUtils.HSLtoRGB(hue, 90.0f, 65.0f, 1.0f);
}
}