/* * Copyright (C) 2012-2016 The Android Money Manager Ex Project Team * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 3 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package com.money.manager.ex.widget; import android.app.PendingIntent; import android.appwidget.AppWidgetManager; import android.appwidget.AppWidgetProvider; import android.content.Context; import android.content.Intent; import android.os.Build; import android.os.Bundle; import android.util.Log; import android.widget.RemoteViews; import com.money.manager.ex.BuildConfig; import com.money.manager.ex.R; import com.money.manager.ex.servicelayer.AccountService; import com.money.manager.ex.currency.CurrencyService; import com.money.manager.ex.datalayer.AccountRepository; import com.money.manager.ex.database.QueryAccountBills; import com.money.manager.ex.database.WhereStatementGenerator; import com.money.manager.ex.domainmodel.Account; import com.money.manager.ex.home.MainActivity; import com.money.manager.ex.settings.AppSettings; import com.money.manager.ex.transactions.CheckingTransactionEditActivity; import info.javaperformance.money.Money; import timber.log.Timber; /** * Implementation of App Widget functionality. * App Widget Configuration implemented in {@link SingleAccountWidgetConfigureActivity SingleAccountWidgetConfigureActivity} */ public class SingleAccountWidget extends AppWidgetProvider { // Static /** * Returns number of cells needed for given size of the widget. * * @param size Widget size in dp. * @return Size in number of cells. */ private static int getCellsForSize(int size) { int n = 2; while (70 * n - 30 < size) { ++n; } return n - 1; } // Dynamic @Override public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) { // There may be multiple widgets active, so update all of them final int N = appWidgetIds.length; for (int i = 0; i < N; i++) { updateAppWidget(context, appWidgetManager, appWidgetIds[i]); } } @Override public void onDeleted(Context context, int[] appWidgetIds) { // When the user deletes the widget, delete the preference associated with it. final int N = appWidgetIds.length; for (int i = 0; i < N; i++) { SingleAccountWidgetConfigureActivity.deleteTitlePref(context, appWidgetIds[i]); } } @Override public void onEnabled(Context context) { // Enter relevant functionality for when the first widget is created } @Override public void onDisabled(Context context) { // Enter relevant functionality for when the last widget is disabled } @Override public void onAppWidgetOptionsChanged (Context context, AppWidgetManager appWidgetManager, int appWidgetId, Bundle newOptions) { // Here you can update your widget view int minWidth = newOptions.getInt(AppWidgetManager.OPTION_APPWIDGET_MIN_WIDTH); // int maxWidth = newOptions.getInt(AppWidgetManager.OPTION_APPWIDGET_MAX_WIDTH); int minHeight = newOptions.getInt(AppWidgetManager.OPTION_APPWIDGET_MIN_HEIGHT); // int maxHeight = newOptions.getInt(AppWidgetManager.OPTION_APPWIDGET_MAX_HEIGHT); Timber.d("resized"); // Obtain appropriate widget and update it. appWidgetManager.updateAppWidget(appWidgetId, getRemoteViews(context, minWidth, minHeight)); super.onAppWidgetOptionsChanged(context, appWidgetManager, appWidgetId, newOptions); this.updateAppWidget(context, appWidgetManager, appWidgetId); } private RemoteViews mRemoteViews; private RemoteViews getRemoteViews(Context context, AppWidgetManager appWidgetManager, int appWidgetId) { if (mRemoteViews == null) { // this call is available only on API 16! if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { int width, height; Bundle options = appWidgetManager.getAppWidgetOptions(appWidgetId); width = options.getInt(AppWidgetManager.OPTION_APPWIDGET_MIN_WIDTH); height = options.getInt(AppWidgetManager.OPTION_APPWIDGET_MIN_HEIGHT); //AppWidgetProviderInfo info = appWidgetManager.getAppWidgetInfo(appWidgetId); // width = info.minResizeWidth; // height = info.minResizeHeight; // width = info.minWidth; // height = info.minHeight; mRemoteViews = getRemoteViews(context, width, height); } else { mRemoteViews = new RemoteViews(context.getPackageName(), R.layout.widget_single_account); } } return mRemoteViews; } /** * Determine appropriate view based on width provided. * * @param width current width * @param height current height * @return Remote views for the current widget. */ private RemoteViews getRemoteViews(Context context, int width, int height) { // First find out rows and columns based on width provided. //int rows = getCellsForSize(minHeight); int columns = getCellsForSize(width); if (columns <= 2) { // Get 1 column widget remote view and return mRemoteViews = new RemoteViews(context.getPackageName(), R.layout.widget_single_account_1x1); } else { // Get appropriate remote view. mRemoteViews = new RemoteViews(context.getPackageName(), R.layout.widget_single_account); } return mRemoteViews; } private void updateAppWidget(Context context, AppWidgetManager appWidgetManager, int appWidgetId) { RemoteViews views = getRemoteViews(context, appWidgetManager, appWidgetId); // todo: allow selecting the account from a list. // todo: load the configured account id AppSettings settings = new AppSettings(context); Integer defaultAccountId = settings.getGeneralSettings().getDefaultAccountId(); // if (StringUtils.isNotEmpty(defaultAccountId)) { if (defaultAccountId != null) { String defaultAccountString = Integer.toString(defaultAccountId); displayAccountInfo(context, defaultAccountString, views); } // e + click -> open the new transaction screen for this account. // todo: pass the account id? initializeNewTransactionCommand(context, views); // e logo click -> open the app. initializeStartAppCommand(context, views); // click account name -> refresh the balance. initializeRefreshDataCommand(context, views, appWidgetId); // Instruct the widget manager to update the widget appWidgetManager.updateAppWidget(appWidgetId, views); } private void displayAccountInfo(Context context, String defaultAccountId, RemoteViews views) { int accountId = Integer.parseInt(defaultAccountId); Account account = loadAccount(context, accountId); if (account == null) return; // CharSequence widgetText = SingleAccountWidgetConfigureActivity.loadTitlePref(context, appWidgetId); // views.setTextViewText(R.id.appwidget_text, widgetText); // display the account name // String accountName = getAccountName(context, accountId); String accountName = account.getName(); views.setTextViewText(R.id.accountNameTextView, accountName); // get account balance (for this account?) String balance = getFormattedAccountBalance(context, account); views.setTextViewText(R.id.balanceTextView, balance); } private void initializeNewTransactionCommand(Context context, RemoteViews views) { Intent intent = new Intent(context, CheckingTransactionEditActivity.class); intent.setAction(Intent.ACTION_INSERT); intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP); // intent.addFlags(Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED); // intent.addFlags(Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP); // intent.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY); intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK); intent.addCategory(Intent.CATEGORY_LAUNCHER); PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, 0); views.setOnClickPendingIntent(R.id.newTransactionPanel, pendingIntent); // for now, the button requires a separate setup. try to find a way to propagate click. views.setOnClickPendingIntent(R.id.newTransactionButton, pendingIntent); } private String getFormattedAccountBalance(Context context, Account account) { WhereStatementGenerator where = new WhereStatementGenerator(); where.addStatement(QueryAccountBills.ACCOUNTID, "=", account.getId()); String selection = where.getWhere(); AccountService service = new AccountService(context); Money total = service.loadBalance(selection); // format the amount CurrencyService currencyService = new CurrencyService(context); String summary = currencyService.getCurrencyFormatted( account.getCurrencyId(), total); return summary; } private Account loadAccount(Context context, int accountId) { AccountRepository repository = new AccountRepository(context); return repository.load(accountId); } private void initializeStartAppCommand(Context context, RemoteViews views) { Intent intent = new Intent(context, MainActivity.class); PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, 0); // Get the layout for the App Widget and attach an on-click listener to the button // RemoteViews views = new RemoteViews(context.getPackageName(),R.layout.appwidget_provider_layout); views.setOnClickPendingIntent(R.id.appLogoImage, pendingIntent); } private void initializeRefreshDataCommand(Context context, RemoteViews views, int appWidgetId) { // refresh the balance on tap. Intent intent = new Intent(context, SingleAccountWidget.class); intent.setAction(AppWidgetManager.ACTION_APPWIDGET_UPDATE); intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, new int[]{appWidgetId}); PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT); views.setOnClickPendingIntent(R.id.refreshDataPanel, pendingIntent); } }