Loading app/build.gradle +3 −0 Original line number Diff line number Diff line Loading @@ -53,6 +53,9 @@ android { //includeAndroidResources = true } } buildFeatures { viewBinding true } } Loading app/src/main/AndroidManifest.xml +102 −95 Original line number Diff line number Diff line <!-- Copyright © Vincent Bourgmayer (/e/ foundation). All rights reserved. This program and the accompanying materials are made available under the terms of the GNU Public License v3.0 which accompanies this distribution, and is available at http://www.gnu.org/licenses/gpl.html --> <!-- @author Vincent Bourgmayer --> <?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="foundation.e.drive"> Loading @@ -15,8 +8,10 @@ http://www.gnu.org/licenses/gpl.html <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" /> <!-- needed for PersistedJob --> <uses-permission android:name="android.permission.GET_ACCOUNTS" /> <uses-permission android:name="android.permission.READ_CONTACTS" /> <uses-permission android:name="android.permission.READ_SYNC_SETTINGS" /> <uses-permission android:name="android.permission.KILL_BACKGROUND_PROCESSES" /> <uses-permission android:name="android.permission.QUERY_ALL_PACKAGES" /> <permission android:name="android.permission.FORCE_STOP_PACKAGES" Loading @@ -30,6 +25,20 @@ http://www.gnu.org/licenses/gpl.html android:icon="@mipmap/ic_eelo" android:label="@string/app_name" android:roundIcon="@mipmap/ic_eelo_round"> <receiver android:name=".widgets.EDriveWidget" android:exported="true"> <intent-filter> <action android:name="android.intent.action.BOOT_COMPLETED" /> <action android:name="android.appwidget.action.APPWIDGET_UPDATE" /> <action android:name="android.accounts.LOGIN_ACCOUNTS_CHANGED"/> </intent-filter> <meta-data android:name="android.appwidget.provider" android:resource="@xml/e_drive_widget_info" /> </receiver> <!-- Providers --> <provider android:name=".providers.MediasSyncProvider" Loading @@ -42,9 +51,7 @@ http://www.gnu.org/licenses/gpl.html android:authorities="foundation.e.drive.providers.SettingsSyncProvider" android:enabled="true" android:exported="true" android:label="Application settings" /> <!-- Services --> android:label="Application settings" /> <!-- Services --> <service android:name=".services.InitializerService" android:enabled="true" Loading app/src/main/java/foundation/e/drive/operations/GetAliasOperation.java 0 → 100644 +82 −0 Original line number Diff line number Diff line /* * Copyright © ECORP SAS 2022. * All rights reserved. This program and the accompanying materials * are made available under the terms of the GNU Public License v3.0 * which accompanies this distribution, and is available at * http://www.gnu.org/licenses/gpl.html */ package foundation.e.drive.operations; import com.owncloud.android.lib.common.OwnCloudClient; import com.owncloud.android.lib.common.operations.RemoteOperation; import com.owncloud.android.lib.common.operations.RemoteOperationResult; import com.owncloud.android.lib.common.utils.Log_OC; import org.apache.commons.httpclient.HttpStatus; import org.apache.commons.httpclient.NameValuePair; import org.apache.commons.httpclient.methods.GetMethod; import org.json.JSONArray; import org.json.JSONObject; import java.util.ArrayList; /** * @author TheScarastic */ public class GetAliasOperation extends RemoteOperation { private static final String TAG = GetAliasOperation.class.getSimpleName(); private static final String ALIAS_PATH = "/ocs/v1.php/cloud/hide-my-email/"; // JSON Node names private static final String NODE_OCS = "ocs"; private static final String NODE_DATA = "data"; private static final String NODE_ALIASES = "aliases"; private boolean isSuccess(int status) { return (status == HttpStatus.SC_OK); } @Override protected RemoteOperationResult run(OwnCloudClient client) { RemoteOperationResult result; GetMethod get = null; final String uri = client.getBaseUri() + ALIAS_PATH + client.getCredentials().getUsername(); try { get = new GetMethod(uri); get.addRequestHeader(OCS_API_HEADER, OCS_API_HEADER_VALUE); get.setQueryString(new NameValuePair[]{new NameValuePair("format", "json")}); if (isSuccess(client.executeMethod(get))) { String response = get.getResponseBodyAsString(); // parse final JSONArray aliases = new JSONObject(response).getJSONObject(NODE_OCS) .getJSONObject(NODE_DATA).getJSONArray(NODE_ALIASES); final ArrayList<Object> resultAliases = new ArrayList<>(); for (int i = 0; i < aliases.length(); i++) { resultAliases.add(aliases.get(i)); } result = new RemoteOperationResult(true, get); result.setData(resultAliases); } else { result = new RemoteOperationResult(false, get); } } catch (Exception e) { e.printStackTrace(); result = new RemoteOperationResult(e); Log_OC.e(TAG, "Fetching aliases failed"); } finally { if (get != null) get.releaseConnection(); } return result; } } app/src/main/java/foundation/e/drive/utils/CommonUtils.java +25 −0 Original line number Diff line number Diff line Loading @@ -32,6 +32,9 @@ import com.owncloud.android.lib.common.accounts.AccountUtils; import com.owncloud.android.lib.resources.files.FileUtils; import java.io.File; import java.text.CharacterIterator; import java.text.StringCharacterIterator; import java.util.Locale; import foundation.e.drive.receivers.ScreenOffReceiver; Loading Loading @@ -293,4 +296,26 @@ public abstract class CommonUtils { + "\n File can be read?: " + f.canRead() + "\n File can be written?: " + f.canWrite(); } /** * Formatter class is not used since bytes passed by server are in SI unit aka 1kb = 1024byte * https://stackoverflow.com/questions/3758606/how-can-i-convert-byte-size-into-a-human-readable-format-in-java/3758880#3758880 * * @param bytes file/data size in bytes * @return String in human readable format */ public static String humanReadableByteCountBin(long bytes) { long absB = bytes == Long.MIN_VALUE ? Long.MAX_VALUE : Math.abs(bytes); if (absB < 1024) { return bytes + " B"; } long value = absB; CharacterIterator ci = new StringCharacterIterator("KMGTPE"); for (int i = 40; i >= 0 && absB > 0xfffccccccccccccL >> i; i -= 10) { value >>= 10; ci.next(); } value *= Long.signum(bytes); return String.format(Locale.getDefault(),"%.1f %cB", value / 1024.0, ci.current()); } } No newline at end of file app/src/main/java/foundation/e/drive/widgets/EDriveWidget.java 0 → 100644 +279 −0 Original line number Diff line number Diff line /* * Copyright © ECORP SAS 2022. * All rights reserved. This program and the accompanying materials * are made available under the terms of the GNU Public License v3.0 * which accompanies this distribution, and is available at * http://www.gnu.org/licenses/gpl.html */ package foundation.e.drive.widgets; import android.accounts.Account; import android.accounts.AccountManager; import android.app.PendingIntent; import android.appwidget.AppWidgetManager; import android.appwidget.AppWidgetProvider; import android.content.ClipData; import android.content.ClipboardManager; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.net.Uri; import android.os.Handler; import android.os.HandlerThread; import android.provider.Settings; import android.view.View; import android.widget.RemoteViews; import com.owncloud.android.lib.common.OwnCloudClient; import com.owncloud.android.lib.common.UserInfo; import com.owncloud.android.lib.common.operations.RemoteOperationResult; import com.owncloud.android.lib.resources.users.GetRemoteUserInfoOperation; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Calendar; import java.util.Locale; import foundation.e.drive.R; import foundation.e.drive.operations.GetAliasOperation; import foundation.e.drive.utils.CommonUtils; /** * @author TheScarastic * Implementation of App Widget functionality. */ public class EDriveWidget extends AppWidgetProvider { private static final String webpage = "https://esolutions.shop/ecloud-subscriptions/?username=%s&token=%s¤t-quota=%s&from=nextcloud"; private static final String ADD_ACCOUNT_WEBPAGE = "https://e.foundation/e-email-invite/"; private static final String ACCOUNT_MANAGER_PACKAGE_NAME = "foundation.e.accountmanager"; private static final String GET_ACCOUNT_MANAGER_COMPONENT_NAME = ACCOUNT_MANAGER_PACKAGE_NAME + ".ui.setup.LoginActivity"; private static final String SETUP_ACCOUNT_PROVIDER_TYPE = "setup_account_provider_type"; private static final String ACCOUNT_PROVIDER_EELO = "eelo"; private static final String SHOW_ALIAS = "show_alias"; private static final String HIDE_ALIAS = "hide_alias"; private static final String COPY_ALIAS = "copy_alias"; private static boolean showAlias = false; private final Calendar calender = Calendar.getInstance(); private final SimpleDateFormat sdf = new SimpleDateFormat("HH:mm", Locale.getDefault()); private final GetRemoteUserInfoOperation getRemoteUserInfoOperation = new GetRemoteUserInfoOperation(); private final GetAliasOperation getAliasOperation = new GetAliasOperation(); private ArrayList<Object> aliases; private UserInfo userInfo = null; private RemoteViews views = null; public void updateAppWidget(final Context context) { AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context); final ComponentName provider = new ComponentName(context, getClass()); int[] appWidgetIds = appWidgetManager.getAppWidgetIds(provider); for (int appWidgetId : appWidgetIds) { updateAppWidget(context, appWidgetManager, appWidgetId); } } public void updateAppWidget(final Context context, final AppWidgetManager appWidgetManager, final int appWidgetId) { final AccountManager accountManager = AccountManager.get(context); final Account account = CommonUtils.getAccount(context.getString(R.string.eelo_account_type), accountManager); final OwnCloudClient client = CommonUtils.getOwnCloudClient(account, context); views = new RemoteViews(context.getPackageName(), R.layout.e_drive_widget); final HandlerThread handlerThread = new HandlerThread("Network Request"); handlerThread.start(); final Handler mHandler = new Handler(handlerThread.getLooper()); final EDriveWidgetCallback callback = new EDriveWidgetCallback() { @Override public void onComplete() { onNetworkRequestCompleted(context, appWidgetManager, appWidgetId, client, account); } }; mHandler.post(new Runnable() { @Override public void run() { if (client != null) { RemoteOperationResult ocsResult = getRemoteUserInfoOperation.execute(client); if (ocsResult.isSuccess() && ocsResult.getData() != null) { userInfo = (UserInfo) ocsResult.getData().get(0); } RemoteOperationResult aliasResult = getAliasOperation.execute(client); if (aliasResult.isSuccess() && aliasResult.getData() != null) { aliases = aliasResult.getData(); } } callback.onComplete(); } }); } @Override public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) { // There may be multiple widgets active, so update all of them for (int appWidgetId : appWidgetIds) { updateAppWidget(context, appWidgetManager, appWidgetId); } super.onUpdate(context, appWidgetManager, appWidgetIds); } @Override public void onEnabled(Context context) { updateAppWidget(context); } @Override public void onDisabled(Context context) { // Enter relevant functionality for when the last widget is disabled } @Override public void onReceive(Context context, Intent intent) { final String action = intent.getAction(); if (action == null) return; switch (action) { case Intent.ACTION_BOOT_COMPLETED: case AccountManager.LOGIN_ACCOUNTS_CHANGED_ACTION: updateAppWidget(context); break; case SHOW_ALIAS: showAlias = true; updateAppWidget(context); break; case HIDE_ALIAS: showAlias = false; updateAppWidget(context); break; case COPY_ALIAS: copyToClipboard(intent.getData(), context); break; } } private String dataForWeb(Long bytes) { final String space = CommonUtils.humanReadableByteCountBin(bytes); final String[] split = space.split(" "); return Math.round(Double.parseDouble(split[0])) + split[1]; } private Intent buildIntent(String name, String extra) { final Intent intent = new Intent(name); if (!extra.isEmpty()) { intent.setData(Uri.parse(extra)); } intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); return intent; } private void onNetworkRequestCompleted(Context context, AppWidgetManager appWidgetManager, int appWidgetId, OwnCloudClient client, Account account) { if (account == null || userInfo == null) { views = new RemoteViews(context.getPackageName(), R.layout.e_drive_widget_login); Intent accountIntent = buildIntent("", "") .setComponent(new ComponentName(ACCOUNT_MANAGER_PACKAGE_NAME, GET_ACCOUNT_MANAGER_COMPONENT_NAME)) .putExtra(SETUP_ACCOUNT_PROVIDER_TYPE, ACCOUNT_PROVIDER_EELO); PendingIntent addAccountIntent = PendingIntent.getActivity(context, 0, accountIntent, PendingIntent.FLAG_IMMUTABLE); views.setOnClickPendingIntent(R.id.login, addAccountIntent); PendingIntent pendingIntentNewAccount = PendingIntent.getActivity(context, 0, buildIntent(Intent.ACTION_VIEW, ADD_ACCOUNT_WEBPAGE), PendingIntent.FLAG_IMMUTABLE); views.setOnClickPendingIntent(R.id.newAccount, pendingIntentNewAccount); appWidgetManager.updateAppWidget(appWidgetId, views); return; } // Construct the RemoteViews object final int usedMB = convertIntoMB(userInfo.quota.used); final int totalMB = convertIntoMB(userInfo.quota.total); views.setTextViewText(R.id.email, userInfo.id); if (!userInfo.alternateDisplayName.isEmpty()) { views.setTextViewText(R.id.name, userInfo.alternateDisplayName); } else { views.setTextViewText(R.id.name, userInfo.displayName); } views.setProgressBar(R.id.progress, totalMB, usedMB, false); views.setTextViewText(R.id.planName, context.getString(R.string.free_plan, CommonUtils.humanReadableByteCountBin(userInfo.quota.total))); for (String group : userInfo.groups) { if (group.contains("premium-")) { views.setTextViewText(R.id.planName, context.getString(R.string.premium_plan, group.split("-")[1])); break; } } views.setTextViewText(R.id.status, context.getString(R.string.progress_status, CommonUtils.humanReadableByteCountBin(userInfo.quota.used), CommonUtils.humanReadableByteCountBin(userInfo.quota.total))); views.setTextViewText(R.id.sync, context.getString(R.string.last_synced, sdf.format(calender.getTime()))); if (aliases.isEmpty()) { views.setViewVisibility(R.id.show_alias, View.GONE); views.setViewVisibility(R.id.alias1_container, View.GONE); views.setViewVisibility(R.id.hide_alias, View.GONE); } else { views.setTextViewText(R.id.alias1, context.getString(R.string.alias_dot) + aliases.get(0)); views.setOnClickPendingIntent(R.id.show_alias, getPendingSelfIntent(context, SHOW_ALIAS, null)); views.setOnClickPendingIntent(R.id.hide_alias, getPendingSelfIntent(context, HIDE_ALIAS, null)); views.setOnClickPendingIntent(R.id.alias1_clipboard, getPendingSelfIntent(context, COPY_ALIAS, String.valueOf(aliases.get(0)))); } if (showAlias) { views.setViewVisibility(R.id.show_alias, View.GONE); views.setViewVisibility(R.id.hide_alias, View.VISIBLE); views.setViewVisibility(R.id.alias1_container, View.VISIBLE); } else { views.setViewVisibility(R.id.show_alias, View.VISIBLE); views.setViewVisibility(R.id.hide_alias, View.GONE); views.setViewVisibility(R.id.alias1_container, View.GONE); } final PendingIntent pendingIntentSettings = PendingIntent.getActivity(context, 0, buildIntent(Settings.ACTION_SYNC_SETTINGS, ""), PendingIntent.FLAG_IMMUTABLE); views.setOnClickPendingIntent(R.id.settings, pendingIntentSettings); final PendingIntent pendingIntentUpgrade = PendingIntent.getActivity(context, 0, buildIntent(Intent.ACTION_VIEW, String.format(webpage, userInfo.id, client.getCredentials().getAuthToken(), dataForWeb(userInfo.quota.total))), PendingIntent.FLAG_IMMUTABLE); views.setOnClickPendingIntent(R.id.upgrade, pendingIntentUpgrade); // Instruct the widget manager to update the widget appWidgetManager.updateAppWidget(appWidgetId, views); } private PendingIntent getPendingSelfIntent(Context context, String action, String data) { final Intent intent = new Intent(context, getClass()); intent.setAction(action); if (data != null) { intent.setData(Uri.parse(data)); } return PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_IMMUTABLE); } private void copyToClipboard(Uri data, Context context) { final ClipboardManager clipboard = (ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE); final ClipData clip = ClipData.newPlainText("alias", String.valueOf(data)); clipboard.setPrimaryClip(clip); } private int convertIntoMB(Long quota) { return (int) (quota / 1048576); // 1024.0 * 1024.0 = 1048576.0 } } No newline at end of file Loading
app/build.gradle +3 −0 Original line number Diff line number Diff line Loading @@ -53,6 +53,9 @@ android { //includeAndroidResources = true } } buildFeatures { viewBinding true } } Loading
app/src/main/AndroidManifest.xml +102 −95 Original line number Diff line number Diff line <!-- Copyright © Vincent Bourgmayer (/e/ foundation). All rights reserved. This program and the accompanying materials are made available under the terms of the GNU Public License v3.0 which accompanies this distribution, and is available at http://www.gnu.org/licenses/gpl.html --> <!-- @author Vincent Bourgmayer --> <?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="foundation.e.drive"> Loading @@ -15,8 +8,10 @@ http://www.gnu.org/licenses/gpl.html <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" /> <!-- needed for PersistedJob --> <uses-permission android:name="android.permission.GET_ACCOUNTS" /> <uses-permission android:name="android.permission.READ_CONTACTS" /> <uses-permission android:name="android.permission.READ_SYNC_SETTINGS" /> <uses-permission android:name="android.permission.KILL_BACKGROUND_PROCESSES" /> <uses-permission android:name="android.permission.QUERY_ALL_PACKAGES" /> <permission android:name="android.permission.FORCE_STOP_PACKAGES" Loading @@ -30,6 +25,20 @@ http://www.gnu.org/licenses/gpl.html android:icon="@mipmap/ic_eelo" android:label="@string/app_name" android:roundIcon="@mipmap/ic_eelo_round"> <receiver android:name=".widgets.EDriveWidget" android:exported="true"> <intent-filter> <action android:name="android.intent.action.BOOT_COMPLETED" /> <action android:name="android.appwidget.action.APPWIDGET_UPDATE" /> <action android:name="android.accounts.LOGIN_ACCOUNTS_CHANGED"/> </intent-filter> <meta-data android:name="android.appwidget.provider" android:resource="@xml/e_drive_widget_info" /> </receiver> <!-- Providers --> <provider android:name=".providers.MediasSyncProvider" Loading @@ -42,9 +51,7 @@ http://www.gnu.org/licenses/gpl.html android:authorities="foundation.e.drive.providers.SettingsSyncProvider" android:enabled="true" android:exported="true" android:label="Application settings" /> <!-- Services --> android:label="Application settings" /> <!-- Services --> <service android:name=".services.InitializerService" android:enabled="true" Loading
app/src/main/java/foundation/e/drive/operations/GetAliasOperation.java 0 → 100644 +82 −0 Original line number Diff line number Diff line /* * Copyright © ECORP SAS 2022. * All rights reserved. This program and the accompanying materials * are made available under the terms of the GNU Public License v3.0 * which accompanies this distribution, and is available at * http://www.gnu.org/licenses/gpl.html */ package foundation.e.drive.operations; import com.owncloud.android.lib.common.OwnCloudClient; import com.owncloud.android.lib.common.operations.RemoteOperation; import com.owncloud.android.lib.common.operations.RemoteOperationResult; import com.owncloud.android.lib.common.utils.Log_OC; import org.apache.commons.httpclient.HttpStatus; import org.apache.commons.httpclient.NameValuePair; import org.apache.commons.httpclient.methods.GetMethod; import org.json.JSONArray; import org.json.JSONObject; import java.util.ArrayList; /** * @author TheScarastic */ public class GetAliasOperation extends RemoteOperation { private static final String TAG = GetAliasOperation.class.getSimpleName(); private static final String ALIAS_PATH = "/ocs/v1.php/cloud/hide-my-email/"; // JSON Node names private static final String NODE_OCS = "ocs"; private static final String NODE_DATA = "data"; private static final String NODE_ALIASES = "aliases"; private boolean isSuccess(int status) { return (status == HttpStatus.SC_OK); } @Override protected RemoteOperationResult run(OwnCloudClient client) { RemoteOperationResult result; GetMethod get = null; final String uri = client.getBaseUri() + ALIAS_PATH + client.getCredentials().getUsername(); try { get = new GetMethod(uri); get.addRequestHeader(OCS_API_HEADER, OCS_API_HEADER_VALUE); get.setQueryString(new NameValuePair[]{new NameValuePair("format", "json")}); if (isSuccess(client.executeMethod(get))) { String response = get.getResponseBodyAsString(); // parse final JSONArray aliases = new JSONObject(response).getJSONObject(NODE_OCS) .getJSONObject(NODE_DATA).getJSONArray(NODE_ALIASES); final ArrayList<Object> resultAliases = new ArrayList<>(); for (int i = 0; i < aliases.length(); i++) { resultAliases.add(aliases.get(i)); } result = new RemoteOperationResult(true, get); result.setData(resultAliases); } else { result = new RemoteOperationResult(false, get); } } catch (Exception e) { e.printStackTrace(); result = new RemoteOperationResult(e); Log_OC.e(TAG, "Fetching aliases failed"); } finally { if (get != null) get.releaseConnection(); } return result; } }
app/src/main/java/foundation/e/drive/utils/CommonUtils.java +25 −0 Original line number Diff line number Diff line Loading @@ -32,6 +32,9 @@ import com.owncloud.android.lib.common.accounts.AccountUtils; import com.owncloud.android.lib.resources.files.FileUtils; import java.io.File; import java.text.CharacterIterator; import java.text.StringCharacterIterator; import java.util.Locale; import foundation.e.drive.receivers.ScreenOffReceiver; Loading Loading @@ -293,4 +296,26 @@ public abstract class CommonUtils { + "\n File can be read?: " + f.canRead() + "\n File can be written?: " + f.canWrite(); } /** * Formatter class is not used since bytes passed by server are in SI unit aka 1kb = 1024byte * https://stackoverflow.com/questions/3758606/how-can-i-convert-byte-size-into-a-human-readable-format-in-java/3758880#3758880 * * @param bytes file/data size in bytes * @return String in human readable format */ public static String humanReadableByteCountBin(long bytes) { long absB = bytes == Long.MIN_VALUE ? Long.MAX_VALUE : Math.abs(bytes); if (absB < 1024) { return bytes + " B"; } long value = absB; CharacterIterator ci = new StringCharacterIterator("KMGTPE"); for (int i = 40; i >= 0 && absB > 0xfffccccccccccccL >> i; i -= 10) { value >>= 10; ci.next(); } value *= Long.signum(bytes); return String.format(Locale.getDefault(),"%.1f %cB", value / 1024.0, ci.current()); } } No newline at end of file
app/src/main/java/foundation/e/drive/widgets/EDriveWidget.java 0 → 100644 +279 −0 Original line number Diff line number Diff line /* * Copyright © ECORP SAS 2022. * All rights reserved. This program and the accompanying materials * are made available under the terms of the GNU Public License v3.0 * which accompanies this distribution, and is available at * http://www.gnu.org/licenses/gpl.html */ package foundation.e.drive.widgets; import android.accounts.Account; import android.accounts.AccountManager; import android.app.PendingIntent; import android.appwidget.AppWidgetManager; import android.appwidget.AppWidgetProvider; import android.content.ClipData; import android.content.ClipboardManager; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.net.Uri; import android.os.Handler; import android.os.HandlerThread; import android.provider.Settings; import android.view.View; import android.widget.RemoteViews; import com.owncloud.android.lib.common.OwnCloudClient; import com.owncloud.android.lib.common.UserInfo; import com.owncloud.android.lib.common.operations.RemoteOperationResult; import com.owncloud.android.lib.resources.users.GetRemoteUserInfoOperation; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Calendar; import java.util.Locale; import foundation.e.drive.R; import foundation.e.drive.operations.GetAliasOperation; import foundation.e.drive.utils.CommonUtils; /** * @author TheScarastic * Implementation of App Widget functionality. */ public class EDriveWidget extends AppWidgetProvider { private static final String webpage = "https://esolutions.shop/ecloud-subscriptions/?username=%s&token=%s¤t-quota=%s&from=nextcloud"; private static final String ADD_ACCOUNT_WEBPAGE = "https://e.foundation/e-email-invite/"; private static final String ACCOUNT_MANAGER_PACKAGE_NAME = "foundation.e.accountmanager"; private static final String GET_ACCOUNT_MANAGER_COMPONENT_NAME = ACCOUNT_MANAGER_PACKAGE_NAME + ".ui.setup.LoginActivity"; private static final String SETUP_ACCOUNT_PROVIDER_TYPE = "setup_account_provider_type"; private static final String ACCOUNT_PROVIDER_EELO = "eelo"; private static final String SHOW_ALIAS = "show_alias"; private static final String HIDE_ALIAS = "hide_alias"; private static final String COPY_ALIAS = "copy_alias"; private static boolean showAlias = false; private final Calendar calender = Calendar.getInstance(); private final SimpleDateFormat sdf = new SimpleDateFormat("HH:mm", Locale.getDefault()); private final GetRemoteUserInfoOperation getRemoteUserInfoOperation = new GetRemoteUserInfoOperation(); private final GetAliasOperation getAliasOperation = new GetAliasOperation(); private ArrayList<Object> aliases; private UserInfo userInfo = null; private RemoteViews views = null; public void updateAppWidget(final Context context) { AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context); final ComponentName provider = new ComponentName(context, getClass()); int[] appWidgetIds = appWidgetManager.getAppWidgetIds(provider); for (int appWidgetId : appWidgetIds) { updateAppWidget(context, appWidgetManager, appWidgetId); } } public void updateAppWidget(final Context context, final AppWidgetManager appWidgetManager, final int appWidgetId) { final AccountManager accountManager = AccountManager.get(context); final Account account = CommonUtils.getAccount(context.getString(R.string.eelo_account_type), accountManager); final OwnCloudClient client = CommonUtils.getOwnCloudClient(account, context); views = new RemoteViews(context.getPackageName(), R.layout.e_drive_widget); final HandlerThread handlerThread = new HandlerThread("Network Request"); handlerThread.start(); final Handler mHandler = new Handler(handlerThread.getLooper()); final EDriveWidgetCallback callback = new EDriveWidgetCallback() { @Override public void onComplete() { onNetworkRequestCompleted(context, appWidgetManager, appWidgetId, client, account); } }; mHandler.post(new Runnable() { @Override public void run() { if (client != null) { RemoteOperationResult ocsResult = getRemoteUserInfoOperation.execute(client); if (ocsResult.isSuccess() && ocsResult.getData() != null) { userInfo = (UserInfo) ocsResult.getData().get(0); } RemoteOperationResult aliasResult = getAliasOperation.execute(client); if (aliasResult.isSuccess() && aliasResult.getData() != null) { aliases = aliasResult.getData(); } } callback.onComplete(); } }); } @Override public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) { // There may be multiple widgets active, so update all of them for (int appWidgetId : appWidgetIds) { updateAppWidget(context, appWidgetManager, appWidgetId); } super.onUpdate(context, appWidgetManager, appWidgetIds); } @Override public void onEnabled(Context context) { updateAppWidget(context); } @Override public void onDisabled(Context context) { // Enter relevant functionality for when the last widget is disabled } @Override public void onReceive(Context context, Intent intent) { final String action = intent.getAction(); if (action == null) return; switch (action) { case Intent.ACTION_BOOT_COMPLETED: case AccountManager.LOGIN_ACCOUNTS_CHANGED_ACTION: updateAppWidget(context); break; case SHOW_ALIAS: showAlias = true; updateAppWidget(context); break; case HIDE_ALIAS: showAlias = false; updateAppWidget(context); break; case COPY_ALIAS: copyToClipboard(intent.getData(), context); break; } } private String dataForWeb(Long bytes) { final String space = CommonUtils.humanReadableByteCountBin(bytes); final String[] split = space.split(" "); return Math.round(Double.parseDouble(split[0])) + split[1]; } private Intent buildIntent(String name, String extra) { final Intent intent = new Intent(name); if (!extra.isEmpty()) { intent.setData(Uri.parse(extra)); } intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); return intent; } private void onNetworkRequestCompleted(Context context, AppWidgetManager appWidgetManager, int appWidgetId, OwnCloudClient client, Account account) { if (account == null || userInfo == null) { views = new RemoteViews(context.getPackageName(), R.layout.e_drive_widget_login); Intent accountIntent = buildIntent("", "") .setComponent(new ComponentName(ACCOUNT_MANAGER_PACKAGE_NAME, GET_ACCOUNT_MANAGER_COMPONENT_NAME)) .putExtra(SETUP_ACCOUNT_PROVIDER_TYPE, ACCOUNT_PROVIDER_EELO); PendingIntent addAccountIntent = PendingIntent.getActivity(context, 0, accountIntent, PendingIntent.FLAG_IMMUTABLE); views.setOnClickPendingIntent(R.id.login, addAccountIntent); PendingIntent pendingIntentNewAccount = PendingIntent.getActivity(context, 0, buildIntent(Intent.ACTION_VIEW, ADD_ACCOUNT_WEBPAGE), PendingIntent.FLAG_IMMUTABLE); views.setOnClickPendingIntent(R.id.newAccount, pendingIntentNewAccount); appWidgetManager.updateAppWidget(appWidgetId, views); return; } // Construct the RemoteViews object final int usedMB = convertIntoMB(userInfo.quota.used); final int totalMB = convertIntoMB(userInfo.quota.total); views.setTextViewText(R.id.email, userInfo.id); if (!userInfo.alternateDisplayName.isEmpty()) { views.setTextViewText(R.id.name, userInfo.alternateDisplayName); } else { views.setTextViewText(R.id.name, userInfo.displayName); } views.setProgressBar(R.id.progress, totalMB, usedMB, false); views.setTextViewText(R.id.planName, context.getString(R.string.free_plan, CommonUtils.humanReadableByteCountBin(userInfo.quota.total))); for (String group : userInfo.groups) { if (group.contains("premium-")) { views.setTextViewText(R.id.planName, context.getString(R.string.premium_plan, group.split("-")[1])); break; } } views.setTextViewText(R.id.status, context.getString(R.string.progress_status, CommonUtils.humanReadableByteCountBin(userInfo.quota.used), CommonUtils.humanReadableByteCountBin(userInfo.quota.total))); views.setTextViewText(R.id.sync, context.getString(R.string.last_synced, sdf.format(calender.getTime()))); if (aliases.isEmpty()) { views.setViewVisibility(R.id.show_alias, View.GONE); views.setViewVisibility(R.id.alias1_container, View.GONE); views.setViewVisibility(R.id.hide_alias, View.GONE); } else { views.setTextViewText(R.id.alias1, context.getString(R.string.alias_dot) + aliases.get(0)); views.setOnClickPendingIntent(R.id.show_alias, getPendingSelfIntent(context, SHOW_ALIAS, null)); views.setOnClickPendingIntent(R.id.hide_alias, getPendingSelfIntent(context, HIDE_ALIAS, null)); views.setOnClickPendingIntent(R.id.alias1_clipboard, getPendingSelfIntent(context, COPY_ALIAS, String.valueOf(aliases.get(0)))); } if (showAlias) { views.setViewVisibility(R.id.show_alias, View.GONE); views.setViewVisibility(R.id.hide_alias, View.VISIBLE); views.setViewVisibility(R.id.alias1_container, View.VISIBLE); } else { views.setViewVisibility(R.id.show_alias, View.VISIBLE); views.setViewVisibility(R.id.hide_alias, View.GONE); views.setViewVisibility(R.id.alias1_container, View.GONE); } final PendingIntent pendingIntentSettings = PendingIntent.getActivity(context, 0, buildIntent(Settings.ACTION_SYNC_SETTINGS, ""), PendingIntent.FLAG_IMMUTABLE); views.setOnClickPendingIntent(R.id.settings, pendingIntentSettings); final PendingIntent pendingIntentUpgrade = PendingIntent.getActivity(context, 0, buildIntent(Intent.ACTION_VIEW, String.format(webpage, userInfo.id, client.getCredentials().getAuthToken(), dataForWeb(userInfo.quota.total))), PendingIntent.FLAG_IMMUTABLE); views.setOnClickPendingIntent(R.id.upgrade, pendingIntentUpgrade); // Instruct the widget manager to update the widget appWidgetManager.updateAppWidget(appWidgetId, views); } private PendingIntent getPendingSelfIntent(Context context, String action, String data) { final Intent intent = new Intent(context, getClass()); intent.setAction(action); if (data != null) { intent.setData(Uri.parse(data)); } return PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_IMMUTABLE); } private void copyToClipboard(Uri data, Context context) { final ClipboardManager clipboard = (ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE); final ClipData clip = ClipData.newPlainText("alias", String.valueOf(data)); clipboard.setPrimaryClip(clip); } private int convertIntoMB(Long quota) { return (int) (quota / 1048576); // 1024.0 * 1024.0 = 1048576.0 } } No newline at end of file