From ef34333d4ffe2ff049ce684d9df745f6cde94c65 Mon Sep 17 00:00:00 2001 From: Leonid Plyushch Date: Mon, 25 Feb 2019 14:06:42 +0200 Subject: [PATCH] merge sources of Termux:Widget --- app/src/main/AndroidManifest.xml | 31 +++- .../widget/TermuxCreateShortcutActivity.java | 98 ++++++++++++ .../widget/TermuxLaunchShortcutActivity.java | 69 ++++++++ .../termux/widget/TermuxWidgetProvider.java | 132 ++++++++++++++++ .../termux/widget/TermuxWidgetService.java | 149 ++++++++++++++++++ app/src/main/res/drawable/ripple_mask.xml | 11 ++ app/src/main/res/drawable/widgetpreview.png | Bin 0 -> 31564 bytes .../main/res/layout/shortcuts_listview.xml | 6 + app/src/main/res/layout/widget_item.xml | 20 +++ app/src/main/res/layout/widget_layout.xml | 65 ++++++++ app/src/main/res/values/strings.xml | 91 ++++++----- .../main/res/xml/termux_appwidget_info.xml | 14 ++ 12 files changed, 643 insertions(+), 43 deletions(-) create mode 100644 app/src/main/java/com/termux/widget/TermuxCreateShortcutActivity.java create mode 100644 app/src/main/java/com/termux/widget/TermuxLaunchShortcutActivity.java create mode 100644 app/src/main/java/com/termux/widget/TermuxWidgetProvider.java create mode 100644 app/src/main/java/com/termux/widget/TermuxWidgetService.java create mode 100644 app/src/main/res/drawable/ripple_mask.xml create mode 100644 app/src/main/res/drawable/widgetpreview.png create mode 100644 app/src/main/res/layout/shortcuts_listview.xml create mode 100644 app/src/main/res/layout/widget_item.xml create mode 100644 app/src/main/res/layout/widget_layout.xml create mode 100644 app/src/main/res/xml/termux_appwidget_info.xml diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 51a15c27..66ccb306 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -128,6 +128,35 @@ android:name="com.termux.app.TermuxOpenReceiver$ContentProvider" /> - + + + + + + + + + + + + + + + + diff --git a/app/src/main/java/com/termux/widget/TermuxCreateShortcutActivity.java b/app/src/main/java/com/termux/widget/TermuxCreateShortcutActivity.java new file mode 100644 index 00000000..b8ae41b9 --- /dev/null +++ b/app/src/main/java/com/termux/widget/TermuxCreateShortcutActivity.java @@ -0,0 +1,98 @@ +package com.termux.widget; + +import android.app.Activity; +import android.app.AlertDialog; +import android.content.Context; +import android.content.Intent; +import android.net.Uri; +import android.os.Bundle; +import android.view.MenuItem; +import android.widget.ArrayAdapter; +import android.widget.ListView; + +import com.termux.R; + +import java.io.File; +import java.util.Arrays; + +public class TermuxCreateShortcutActivity extends Activity { + + private ListView mListView; + private File mCurrentDirectory; + private File[] mCurrentFiles; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.shortcuts_listview); + mListView = findViewById(R.id.list); + } + + @Override + protected void onResume() { + super.onResume(); + + updateListview(TermuxWidgetService.SHORTCUTS_DIR); + + mListView.setOnItemClickListener((parent, view, position, id) -> { + final Context context = TermuxCreateShortcutActivity.this; + File clickedFile = mCurrentFiles[position]; + if (clickedFile.isDirectory()) { + updateListview(clickedFile); + return; + } + + Intent.ShortcutIconResource icon = Intent.ShortcutIconResource.fromContext(context, R.drawable.ic_launcher); + + Uri scriptUri = new Uri.Builder().scheme("com.termux.file").path(clickedFile.getAbsolutePath()).build(); + Intent executeIntent = new Intent(context, TermuxLaunchShortcutActivity.class); + executeIntent.setData(scriptUri); + executeIntent.putExtra(TermuxLaunchShortcutActivity.TOKEN_NAME, TermuxLaunchShortcutActivity.getGeneratedToken(context)); + + Intent intent = new Intent(); + intent.putExtra(Intent.EXTRA_SHORTCUT_INTENT, executeIntent); + intent.putExtra(Intent.EXTRA_SHORTCUT_NAME, clickedFile.getName()); + intent.putExtra(Intent.EXTRA_SHORTCUT_ICON_RESOURCE, icon); + + setResult(RESULT_OK, intent); + finish(); + }); + } + + private void updateListview(File directory) { + mCurrentDirectory = directory; + mCurrentFiles = directory.listFiles(pathname -> !pathname.getName().startsWith(".")); + if (mCurrentFiles == null) mCurrentFiles = new File[0]; + + Arrays.sort(mCurrentFiles, (f1, f2) -> f1.getName().compareTo(f2.getName())); + + final boolean isTopDir = directory.equals(TermuxWidgetService.SHORTCUTS_DIR); + getActionBar().setDisplayHomeAsUpEnabled(!isTopDir); + + if (isTopDir && mCurrentFiles.length == 0) { + // Create if necessary so user can more easily add. + TermuxWidgetService.SHORTCUTS_DIR.mkdirs(); + new AlertDialog.Builder(this) + .setMessage(R.string.no_shortcut_scripts) + .setOnDismissListener(dialog -> finish()).show(); + return; + } + + final String[] values = new String[mCurrentFiles.length]; + for (int i = 0; i < values.length; i++) + values[i] = mCurrentFiles[i].getName() + + (mCurrentFiles[i].isDirectory() ? "/" : ""); + + ArrayAdapter adapter = new ArrayAdapter<>(this, android.R.layout.simple_list_item_1, android.R.id.text1, values); + mListView.setAdapter(adapter); + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + if (item.getItemId() == android.R.id.home) { + updateListview(mCurrentDirectory.getParentFile()); + return true; + } + return super.onOptionsItemSelected(item); + } +} diff --git a/app/src/main/java/com/termux/widget/TermuxLaunchShortcutActivity.java b/app/src/main/java/com/termux/widget/TermuxLaunchShortcutActivity.java new file mode 100644 index 00000000..e935c173 --- /dev/null +++ b/app/src/main/java/com/termux/widget/TermuxLaunchShortcutActivity.java @@ -0,0 +1,69 @@ +package com.termux.widget; + +import android.app.Activity; +import android.content.Context; +import android.content.Intent; +import android.content.SharedPreferences; +import android.net.Uri; +import android.util.Log; +import android.view.Gravity; +import android.widget.Toast; + +import com.termux.R; + +import java.io.File; +import java.util.UUID; + +/** + * An activity to launch a shortcut. We want to a launch a service directly, but a shortcut + * cannot be used to launch a service, only activities, so have to go through this activity. + */ +public class TermuxLaunchShortcutActivity extends Activity { + + static final String TOKEN_NAME = "com.termux.shortcut.token"; + + public static String getGeneratedToken(Context context) { + SharedPreferences prefs = context.getSharedPreferences("token", Context.MODE_PRIVATE); + String token = prefs.getString("token", null); + if (token == null) { + token = UUID.randomUUID().toString(); + prefs.edit().putString("token", token).apply(); + } + return token; + } + + @Override + protected void onResume() { + super.onResume(); + + Intent intent = getIntent(); + String token = intent.getStringExtra(TOKEN_NAME); + if (token == null || !token.equals(getGeneratedToken(this))) { + Log.w("termux", "Strange token: " + token); + Toast.makeText(this, R.string.bad_token_message, Toast.LENGTH_LONG).show(); + finish(); + return; + } + + File clickedFile = new File(intent.getData().getPath()); + TermuxWidgetProvider.ensureFileReadableAndExecutable(clickedFile); + + // Do not use the intent data passed in, since that may be an old one with a file:// uri + // which is not allowed starting with Android 7. + Uri scriptUri = new Uri.Builder().scheme("com.termux.file").path(clickedFile.getAbsolutePath()).build(); + + Intent executeIntent = new Intent(TermuxWidgetProvider.ACTION_EXECUTE, scriptUri); + executeIntent.setClassName("com.termux", TermuxWidgetProvider.TERMUX_SERVICE); + if (clickedFile.getParentFile().getName().equals("tasks")) { + executeIntent.putExtra("com.termux.execute.background", true); + // Show feedback for executed background task. + String message = "Task executed: " + clickedFile.getName(); + Toast toast = Toast.makeText(this, message, Toast.LENGTH_SHORT); + toast.setGravity(Gravity.CENTER, 0, 0); + toast.show(); + } + + TermuxWidgetProvider.startTermuxService(this, executeIntent); + finish(); + } +} diff --git a/app/src/main/java/com/termux/widget/TermuxWidgetProvider.java b/app/src/main/java/com/termux/widget/TermuxWidgetProvider.java new file mode 100644 index 00000000..13e21a2e --- /dev/null +++ b/app/src/main/java/com/termux/widget/TermuxWidgetProvider.java @@ -0,0 +1,132 @@ +package com.termux.widget; + +import android.app.PendingIntent; +import android.appwidget.AppWidgetManager; +import android.appwidget.AppWidgetProvider; +import android.content.Context; +import android.content.Intent; +import android.net.Uri; +import android.os.Build; +import android.view.Gravity; +import android.widget.RemoteViews; +import android.widget.Toast; + +import com.termux.R; + +import java.io.File; + +/** + * Widget providing a list to launch scripts in $HOME/.termux/shortcuts/. + *

+ * See https://developer.android.com/guide/topics/appwidgets/index.html + */ +public final class TermuxWidgetProvider extends AppWidgetProvider { + + private static final String LIST_ITEM_CLICKED_ACTION = "com.termux.widgets.LIST_ITEM_CLICKED_ACTION"; + private static final String REFRESH_WIDGET_ACTION = "com.termux.widgets.REFRESH_WIDGET_ACTION"; + public static final String EXTRA_CLICKED_FILE = "com.termux.widgets.EXTRA_CLICKED_FILE"; + + public static final String TERMUX_SERVICE = "com.termux.app.TermuxService"; + public static final String ACTION_EXECUTE = "com.termux.service_execute"; + + + /** + * "This is called to update the App Widget at intervals defined by the updatePeriodMillis attribute in the + * AppWidgetProviderInfo (see Adding the AppWidgetProviderInfo Metadata above). This method is also called when the + * user adds the App Widget, so it should perform the essential setup, such as define event handlers for Views and + * start a temporary Service, if necessary. However, if you have declared a configuration Activity, this method is + * not called when the user adds the App Widget, but is called for the subsequent updates. It is the responsibility + * of the configuration Activity to perform the first update when configuration is done. (See Creating an App Widget + * Configuration Activity below.)" + */ + @Override + public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) { + for (int appWidgetId : appWidgetIds) { + RemoteViews rv = new RemoteViews(context.getPackageName(), R.layout.widget_layout); + + // The empty view is displayed when the collection has no items. It should be a sibling + // of the collection view: + rv.setEmptyView(R.id.widget_list, R.id.empty_view); + + // Setup intent which points to the TermuxWidgetService which will provide the views for this collection. + Intent intent = new Intent(context, TermuxWidgetService.class); + intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId); + // When intents are compared, the extras are ignored, so we need to embed the extras + // into the data so that the extras will not be ignored. + intent.setData(Uri.parse(intent.toUri(Intent.URI_INTENT_SCHEME))); + rv.setRemoteAdapter(R.id.widget_list, intent); + + // Setup refresh button: + Intent refreshIntent = new Intent(context, TermuxWidgetProvider.class); + refreshIntent.setAction(TermuxWidgetProvider.REFRESH_WIDGET_ACTION); + refreshIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId); + refreshIntent.setData(Uri.parse(refreshIntent.toUri(Intent.URI_INTENT_SCHEME))); + PendingIntent refreshPendingIntent = PendingIntent.getBroadcast(context, 0, refreshIntent, PendingIntent.FLAG_UPDATE_CURRENT); + rv.setOnClickPendingIntent(R.id.refresh_button, refreshPendingIntent); + + // Here we setup the a pending intent template. Individuals items of a collection + // cannot setup their own pending intents, instead, the collection as a whole can + // setup a pending intent template, and the individual items can set a fillInIntent + // to create unique before on an item to item basis. + Intent toastIntent = new Intent(context, TermuxWidgetProvider.class); + toastIntent.setAction(TermuxWidgetProvider.LIST_ITEM_CLICKED_ACTION); + toastIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId); + intent.setData(Uri.parse(intent.toUri(Intent.URI_INTENT_SCHEME))); + PendingIntent toastPendingIntent = PendingIntent.getBroadcast(context, 0, toastIntent, PendingIntent.FLAG_UPDATE_CURRENT); + rv.setPendingIntentTemplate(R.id.widget_list, toastPendingIntent); + + appWidgetManager.updateAppWidget(appWidgetId, rv); + } + } + + @Override + public void onReceive(Context context, Intent intent) { + super.onReceive(context, intent); + + switch (intent.getAction()) { + case LIST_ITEM_CLICKED_ACTION: + String clickedFilePath = intent.getStringExtra(EXTRA_CLICKED_FILE); + File clickedFile = new File(clickedFilePath); + if (clickedFile.isDirectory()) return; + ensureFileReadableAndExecutable(clickedFile); + Uri scriptUri = new Uri.Builder().scheme("com.termux.file").path(clickedFilePath).build(); + + // Note: Must match TermuxService#ACTION_EXECUTE constant: + Intent executeIntent = new Intent(ACTION_EXECUTE, scriptUri); + executeIntent.setClassName("com.termux", TERMUX_SERVICE); + if (clickedFile.getParentFile().getName().equals("tasks")) { + executeIntent.putExtra("com.termux.execute.background", true); + // Show feedback for executed background task. + String message = "Task executed: " + clickedFile.getName(); + Toast toast = Toast.makeText(context, message, Toast.LENGTH_SHORT); + toast.setGravity(Gravity.CENTER, 0, 0); + toast.show(); + } + startTermuxService(context, executeIntent); + break; + case REFRESH_WIDGET_ACTION: + int appWidgetId = intent.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, AppWidgetManager.INVALID_APPWIDGET_ID); + AppWidgetManager.getInstance(context).notifyAppWidgetViewDataChanged(appWidgetId, R.id.widget_list); + + Toast toast = Toast.makeText(context, R.string.scripts_reloaded, Toast.LENGTH_SHORT); + toast.setGravity(Gravity.CENTER, 0, 0); + toast.show(); + break; + } + } + + static void startTermuxService(Context context, Intent executeIntent) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + // https://developer.android.com/about/versions/oreo/background.html + context.startForegroundService(executeIntent); + } else { + context.startService(executeIntent); + } + } + + /** Ensure readable and executable file if user forgot to do so. */ + static void ensureFileReadableAndExecutable(File file) { + if (!file.canRead()) file.setReadable(true); + if (!file.canExecute()) file.setExecutable(true); + } +} diff --git a/app/src/main/java/com/termux/widget/TermuxWidgetService.java b/app/src/main/java/com/termux/widget/TermuxWidgetService.java new file mode 100644 index 00000000..3048db07 --- /dev/null +++ b/app/src/main/java/com/termux/widget/TermuxWidgetService.java @@ -0,0 +1,149 @@ +package com.termux.widget; + +import android.annotation.SuppressLint; +import android.content.Context; +import android.content.Intent; +import android.widget.RemoteViews; +import android.widget.RemoteViewsService; + +import com.termux.R; + +import java.io.File; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +public final class TermuxWidgetService extends RemoteViewsService { + + @SuppressLint("SdCardPath") + public static final File SHORTCUTS_DIR = new File("/data/data/com.termux/files/home/.shortcuts"); + + public static final class TermuxWidgetItem { + + /** Label to display in the list. */ + public final String mLabel; + /** The file which this item represents, sent with the {@link TermuxWidgetProvider#EXTRA_CLICKED_FILE} extra. */ + public final String mFile; + + public TermuxWidgetItem(File file, int depth) { + this.mLabel = (depth > 0 ? (file.getParentFile().getName() + "/") : "") + + file.getName().replace('-', ' '); + this.mFile = file.getAbsolutePath(); + } + + } + + @Override + public RemoteViewsFactory onGetViewFactory(Intent intent) { + return new ListRemoteViewsFactory(getApplicationContext()); + } + + public static class ListRemoteViewsFactory implements RemoteViewsService.RemoteViewsFactory { + private final List mWidgetItems = new ArrayList<>(); + private final Context mContext; + + public ListRemoteViewsFactory(Context context) { + mContext = context; + } + + @Override + public void onCreate() { + // In onCreate() you setup any connections / cursors to your data source. Heavy lifting, + // for example downloading or creating content etc, should be deferred to onDataSetChanged() + // or getViewAt(). Taking more than 20 seconds in this call will result in an ANR. + } + + @Override + public void onDestroy() { + mWidgetItems.clear(); + } + + @Override + public int getCount() { + return mWidgetItems.size(); + } + + @Override + public RemoteViews getViewAt(int position) { + // Position will always range from 0 to getCount() - 1. + TermuxWidgetItem widgetItem = mWidgetItems.get(position); + + // Construct remote views item based on the item xml file and set text based on position. + RemoteViews rv = new RemoteViews(mContext.getPackageName(), R.layout.widget_item); + rv.setTextViewText(R.id.widget_item, widgetItem.mLabel); + + // Next, we set a fill-intent which will be used to fill-in the pending intent template + // which is set on the collection view in TermuxAppWidgetProvider. + Intent fillInIntent = new Intent().putExtra(TermuxWidgetProvider.EXTRA_CLICKED_FILE, widgetItem.mFile); + rv.setOnClickFillInIntent(R.id.widget_item_layout, fillInIntent); + + // You can do heaving lifting in here, synchronously. For example, if you need to + // process an image, fetch something from the network, etc., it is ok to do it here, + // synchronously. A loading view will show up in lieu of the actual contents in the + // interim. + + return rv; + } + + @Override + public RemoteViews getLoadingView() { + // You can create a custom loading view (for instance when getViewAt() is slow.) If you + // return null here, you will get the default loading view. + return null; + } + + @Override + public int getViewTypeCount() { + return 1; + } + + @Override + public long getItemId(int position) { + return position; + } + + @Override + public boolean hasStableIds() { + return true; + } + + @SuppressLint("SdCardPath") + @Override + public void onDataSetChanged() { + // This is triggered when you call AppWidgetManager notifyAppWidgetViewDataChanged + // on the collection view corresponding to this factory. You can do heaving lifting in + // here, synchronously. For example, if you need to process an image, fetch something + // from the network, etc., it is ok to do it here, synchronously. The widget will remain + // in its current state while work is being done here, so you don't need to worry about + // locking up the widget. + mWidgetItems.clear(); + // Create directory if necessary so user more easily finds where to put shortcuts: + SHORTCUTS_DIR.mkdirs(); + + addFile(SHORTCUTS_DIR, mWidgetItems, 0); + } + } + + private static void addFile(File dir, List widgetItems, int depth) { + if (depth > 5) return; + + File[] files = dir.listFiles(pathname -> !pathname.getName().startsWith(".")); + + if (files == null) return; + Arrays.sort(files, (lhs, rhs) -> { + if (lhs.isDirectory() != rhs.isDirectory()) { + return lhs.isDirectory() ? 1 : -1; + } + return lhs.getName().compareToIgnoreCase(rhs.getName()); + }); + + for (File file : files) { + if (file.isDirectory()) { + addFile(file, widgetItems, depth + 1); + } else { + widgetItems.add(new TermuxWidgetItem(file, depth)); + } + } + + } +} diff --git a/app/src/main/res/drawable/ripple_mask.xml b/app/src/main/res/drawable/ripple_mask.xml new file mode 100644 index 00000000..fe34991e --- /dev/null +++ b/app/src/main/res/drawable/ripple_mask.xml @@ -0,0 +1,11 @@ + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/widgetpreview.png b/app/src/main/res/drawable/widgetpreview.png new file mode 100644 index 0000000000000000000000000000000000000000..8052608a898d86e6aea5ef2a6905f278fba04ce2 GIT binary patch literal 31564 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 + + diff --git a/app/src/main/res/layout/widget_item.xml b/app/src/main/res/layout/widget_item.xml new file mode 100644 index 00000000..0df4d30e --- /dev/null +++ b/app/src/main/res/layout/widget_item.xml @@ -0,0 +1,20 @@ + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/widget_layout.xml b/app/src/main/res/layout/widget_layout.xml new file mode 100644 index 00000000..00df7d14 --- /dev/null +++ b/app/src/main/res/layout/widget_layout.xml @@ -0,0 +1,65 @@ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 615bc147..e0a4c6b5 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1,56 +1,63 @@ - Termux - Termux user - New session - Failsafe - Keyboard - Reset - Style - Terminal transcript - Help - Keep screen on + Termux + Termux user + New session + Failsafe + Keyboard + Reset + Style + Terminal transcript + Help + Keep screen on - Installing… - Unable to install - Termux was unable to install the bootstrap packages.\n\nCheck your network connection and try again. - Abort - Try again - Termux can only be installed on the primary user account. + Installing… + Unable to install + Termux was unable to install the bootstrap packages.\n\nCheck your network connection and try again. + Abort + Try again + Termux can only be installed on the primary user account. - Max terminals reached - Close down existing ones before creating new. + Max terminals reached + Close down existing ones before creating new. - Terminal reset. + Terminal reset. - Select URL - Click URL to copy or long press to open - Share transcript - No URL found in the terminal. - URL copied to clipboard - Send text to: + Select URL + Click URL to copy or long press to open + Share transcript + No URL found in the terminal. + URL copied to clipboard + Send text to: - Kill process (%d) - Really kill this session? + Kill process (%d) + Really kill this session? - Set session name - Set - New named session - Create + Set session name + Set + New named session + Create - The Termux:Style add-on is not installed. - Install + The Termux:Style add-on is not installed. + Install - Exit - Acquire wakelock - Release wakelock + Exit + Acquire wakelock + Release wakelock - Save file in ~/downloads/ - Edit - Open folder + Save file in ~/downloads/ + Edit + Open folder + Choose color + Choose font + Failed to install file:\n\n - Choose color - Choose font - Failed to install file:\n\n + All shortcuts + Single shortcut + No files in\n$HOME/.shortcuts/ + Refresh + Termux + Termux shortcuts reloaded + This shortcut has become invalid - remove and add again. diff --git a/app/src/main/res/xml/termux_appwidget_info.xml b/app/src/main/res/xml/termux_appwidget_info.xml new file mode 100644 index 00000000..13941aa7 --- /dev/null +++ b/app/src/main/res/xml/termux_appwidget_info.xml @@ -0,0 +1,14 @@ + + +