这是indexloc提供的服务,不要输入任何密码
Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 16 additions & 2 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
<uses-permission android:name="android.permission.WRITE_SETTINGS"
tools:ignore="ProtectedPermissions" />
<uses-permission android:name="android.permission.USE_FINGERPRINT" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

<!-- Some of the used permissions imply uses-feature, so we need to make it optional.
See http://developer.android.com/guide/topics/manifest/uses-feature-element.html#permissions -->
Expand All @@ -43,14 +44,21 @@
<permission android:name="com.termux.sharedfiles.READ" android:protectionLevel="signature" />

<application
android:allowBackup="true"
android:allowBackup="false"
android:fullBackupContent="false"
android:icon="@mipmap/ic_launcher"
android:roundIcon="@mipmap/ic_launcher_round"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@android:style/Theme.Material.Light" >
<receiver android:name="com.termux.api.TermuxApiReceiver"/>
<activity android:name="com.termux.api.DialogActivity" android:theme="@style/DialogTheme" android:noHistory="true" android:excludeFromRecents="true" android:exported="false"/>
<receiver android:name="com.termux.api.TermuxApiReceiver"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="com.termux.app.OPENED"/>
</intent-filter>
</receiver>
<activity android:name=".FingerprintAPI$FingerprintActivity" android:theme="@android:style/Theme.NoDisplay"
android:noHistory="true"
android:excludeFromRecents="true"
Expand All @@ -64,6 +72,12 @@
android:theme="@android:style/Theme.Translucent.NoTitleBar"
android:excludeFromRecents="true"
android:exported="false"/>
<activity android:name=".util.TermuxApiVerifyActivity"
android:theme="@android:style/Theme.Material.Light.Dialog"
android:noHistory="true"
android:excludeFromRecents="true"
android:exported="false"/>

<service android:name="com.termux.api.SpeechToTextAPI$SpeechToTextService"/>
<service android:name="com.termux.api.TextToSpeechAPI$TextToSpeechService" />
<service android:name=".SensorAPI$SensorReaderService"/>
Expand Down
42 changes: 4 additions & 38 deletions app/src/main/java/com/termux/api/NotificationAPI.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,25 +6,18 @@
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Build;
import android.provider.Settings;
import android.text.TextUtils;

import com.termux.api.util.ResultReturner;
import com.termux.api.util.TermuxApiLogger;
import com.termux.api.util.TermuxIntentHelper;

import java.io.PrintWriter;
import java.util.Arrays;
import java.util.UUID;

public class NotificationAPI {

public static final String TERMUX_SERVICE = "com.termux.app.TermuxService";
public static final String ACTION_EXECUTE = "com.termux.service_execute";
public static final String EXTRA_ARGUMENTS = "com.termux.execute.arguments";
public static final String BIN_SH = "/data/data/com.termux/files/usr/bin/sh";
private static final String EXTRA_EXECUTE_IN_BACKGROUND = "com.termux.execute.background";
private static final String CHANNEL_ID = "termux-notification";
private static final String CHANNEL_TITLE = "Termux API notification channel";

Expand Down Expand Up @@ -107,49 +100,22 @@ static void onReceiveShowNotification(TermuxApiReceiver apiReceiver, final Conte
notification.setAutoCancel(true);

if (actionExtra != null) {
String[] arguments = new String[]{"-c", actionExtra};
Uri executeUri = new Uri.Builder().scheme("com.termux.file")
.path(BIN_SH)
.appendQueryParameter("arguments", Arrays.toString(arguments))
.build();
Intent executeIntent = new Intent(ACTION_EXECUTE, executeUri);
executeIntent.setClassName("com.termux", TERMUX_SERVICE);
executeIntent.putExtra(EXTRA_EXECUTE_IN_BACKGROUND, true);
executeIntent.putExtra(EXTRA_ARGUMENTS, arguments);
PendingIntent pi = PendingIntent.getService(context, 0, executeIntent, 0);
PendingIntent pi = TermuxIntentHelper.createPendingIntent(context, actionExtra);
notification.setContentIntent(pi);
}

for (int button = 1; button <= 3; button++) {
String buttonText = intent.getStringExtra("button_text_" + button);
String buttonAction = intent.getStringExtra("button_action_" + button);
if (buttonText != null && buttonAction != null) {
String[] arguments = new String[]{"-c", buttonAction};
Uri executeUri = new Uri.Builder().scheme("com.termux.file")
.path(BIN_SH)
.appendQueryParameter("arguments", Arrays.toString(arguments))
.build();
Intent executeIntent = new Intent(ACTION_EXECUTE, executeUri);
executeIntent.setClassName("com.termux", TERMUX_SERVICE);
executeIntent.putExtra(EXTRA_EXECUTE_IN_BACKGROUND, true);
executeIntent.putExtra(EXTRA_ARGUMENTS, arguments);
PendingIntent pi = PendingIntent.getService(context, 0, executeIntent, 0);
PendingIntent pi = TermuxIntentHelper.createPendingIntent(context, buttonAction);
notification.addAction(new Notification.Action(android.R.drawable.ic_input_add, buttonText, pi));
}
}

String onDeleteActionExtra = intent.getStringExtra("on_delete_action");
if (onDeleteActionExtra != null) {
String[] arguments = new String[]{"-c", onDeleteActionExtra};
Uri executeUri = new Uri.Builder().scheme("com.termux.file")
.path(BIN_SH)
.appendQueryParameter("arguments", Arrays.toString(arguments))
.build();
Intent executeIntent = new Intent(ACTION_EXECUTE, executeUri);
executeIntent.setClassName("com.termux", TERMUX_SERVICE);
executeIntent.putExtra(EXTRA_EXECUTE_IN_BACKGROUND, true);
executeIntent.putExtra(EXTRA_ARGUMENTS, arguments);
PendingIntent pi = PendingIntent.getService(context, 0, executeIntent, 0);
PendingIntent pi = TermuxIntentHelper.createPendingIntent(context, onDeleteActionExtra);
notification.setDeleteIntent(pi);
}

Expand Down
11 changes: 9 additions & 2 deletions app/src/main/java/com/termux/api/TermuxApiReceiver.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,19 @@

import com.termux.api.util.TermuxApiLogger;
import com.termux.api.util.TermuxApiPermissionActivity;
import com.termux.api.util.TermuxApiVerifyActivity;

public class TermuxApiReceiver extends BroadcastReceiver {
private static final String TERMUX_OPENED = "com.termux.app.OPENED";

@Override
public void onReceive(Context context, Intent intent) {
public void onReceive(final Context context, Intent intent) {
// validate user has installed termux-api package when Termux first opened
if (TERMUX_OPENED.equals(intent.getAction())) {
TermuxApiVerifyActivity.checkAndNotifyToolStatus(context);
return;
}

String apiMethod = intent.getStringExtra("api_method");
if (apiMethod == null) {
TermuxApiLogger.error("Missing 'api_method' extra");
Expand Down Expand Up @@ -176,5 +184,4 @@ public void onReceive(Context context, Intent intent) {
TermuxApiLogger.error("Unrecognized 'api_method' extra: '" + apiMethod + "'");
}
}

}
247 changes: 247 additions & 0 deletions app/src/main/java/com/termux/api/util/TermuxApiVerifyActivity.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,247 @@
package com.termux.api.util;

import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.app.PendingIntent;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.view.View;
import android.view.Window;
import android.widget.CheckBox;
import android.widget.Toast;

import com.termux.api.R;

import java.io.File;

/**
* Verifies installation of termux-api package for user and provides notification
* dialog if it isn't as well as help link to the Termux Wiki
*/
public class TermuxApiVerifyActivity extends Activity {
private static final String TERMUX_API_WIKI_URL = "https://wiki.termux.com/wiki/Termux:API";
private static final String EXTRA_NOTIFY_TYPE = "notify_type";


private static final int EXTRA_NOTIFY_NOT_INSTALLED = R.layout.dialog_missing_tools;
private static final int EXTRA_NOTIFY_UPDATE = R.layout.dialog_tools_update;

private static final int DIALOG_DELAY = 2500;


protected Dialog dialog;


public static void checkAndNotifyToolStatus(final Context context) {
boolean shouldNotifyUser = false;

final Intent notifyIntent = new Intent(context, TermuxApiVerifyActivity.class);
notifyIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

if (!TermuxApiHelper.hasToolsInstalled()) {
notifyIntent.putExtra(EXTRA_NOTIFY_TYPE, EXTRA_NOTIFY_NOT_INSTALLED);
shouldNotifyUser = true;
} else if (TermuxApiHelper.checkIfVersionChanged(context)) {
notifyIntent.putExtra(EXTRA_NOTIFY_TYPE, EXTRA_NOTIFY_UPDATE);
shouldNotifyUser = TermuxApiHelper.canRemindUser(context);
}

if (shouldNotifyUser) {
new Handler(Looper.getMainLooper()).postDelayed(new Runnable() {
@Override
public void run() {
context.startActivity(notifyIntent);
}
}, DIALOG_DELAY);
}
}


@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setFinishOnTouchOutside(false);
showDialog();
}

protected void showDialog() {
int dialogType = getIntent().getIntExtra(EXTRA_NOTIFY_TYPE, 0);
View dialogView = View.inflate(this, dialogType, null);
requestWindowFeature(Window.FEATURE_NO_TITLE);

dialog = getDialog(dialogView);
dialog.show();
}

/**
* Installs termux-api package
* @param view
*/
public void installToolsButtonClicked(View view) {
dismiss();

Toast.makeText(this, "Installing termux-api", Toast.LENGTH_SHORT).show();

// install termux-api and use our notification api to display success
String command = "pkg install termux-api && termux-notification --content 'termux-api package installed successfully!'";
TermuxApiHelper.execTermuxCommand(this, command);
TermuxApiHelper.saveVersion(this);
}

/**
* Updates Termux packages
* @param view
*/
public void updateButtonClicked(View view) {
dismiss();

Toast.makeText(this, "Updated packages", Toast.LENGTH_SHORT).show();

// update packages and use our notification api to display success
String command = "yes | pkg update && termux-notification --content 'packages updated successfully!'";
TermuxApiHelper.execTermuxCommand(this, command);
TermuxApiHelper.saveVersion(this);
}

/**
* Launches TermuxAPI Wiki page
* @param view
*/
public void learnMoreButtonClicked(View view) {
dismiss();

Intent urlIntent = new Intent(Intent.ACTION_VIEW);
urlIntent.setData(Uri.parse(TERMUX_API_WIKI_URL));
startActivity(urlIntent);
}

/**
* Toggle preference to remind user
* @param view
*/
public void remindMeCheckBoxClicked(View view) {
CheckBox checkBox = (CheckBox)view;
// if box is NOT checked, we CAN remind the user
TermuxApiHelper.setCanRemindUser(this, !checkBox.isChecked());
}

protected Dialog getDialog(View dialogView) {
Dialog dialog = new AlertDialog.Builder(this)
.setTitle(getString(R.string.version, TermuxApiHelper.getInstalledVersion(this)))
.setView(dialogView)
.setPositiveButton("Okay", null)
.setOnDismissListener(new DialogInterface.OnDismissListener() {
@Override
public void onDismiss(DialogInterface dialogInterface) {
finish();
}
})
.create();
dialog.setCanceledOnTouchOutside(false);
return dialog;
}

protected void dismiss() {
if (dialog != null) {
dialog.dismiss();
}
}


/**
* Helper class to manage installation
*/
static final class TermuxApiHelper {
private static final String PREFERENCES = "termux_api_prefs";
private static final String KEY_API_VERSION = "api_version";
private static final String KEY_REMINDER = "reminder";

/**
* Check if installed version doesn't match our previously stored version
* @param context
* @return
*/
static boolean checkIfVersionChanged(Context context) {
SharedPreferences preferences = context.getSharedPreferences(PREFERENCES, Context.MODE_PRIVATE);
final String installedApiVersion = getInstalledVersion(context);
return !preferences.getString(KEY_API_VERSION, "").equals(installedApiVersion);
}

/**
* Checks to see if we can remind user
* @param context
* @return
*/
static boolean canRemindUser(Context context) {
SharedPreferences preferences = context.getSharedPreferences(PREFERENCES, Context.MODE_PRIVATE);
return preferences.getBoolean(KEY_REMINDER, true);
}

/**
* Returns version number of our TermuxAPI
* @param context
* @return
*/
static String getInstalledVersion(Context context) {
String version = "Unknown";
try {
PackageInfo packageInfo = context.getPackageManager().getPackageInfo(context.getPackageName(), 0);
version = packageInfo.versionName;
} catch (PackageManager.NameNotFoundException e) {
TermuxApiLogger.error("Failed to obtain TermuxAPIVersion", e);
}
return version;
}

/**
* Executes specified command through Termux using a PendingIntent
* @param context
* @param command
*/
static void execTermuxCommand(Context context, String command) {
PendingIntent pi = TermuxIntentHelper.createPendingIntent(context, command);
try {
pi.send();
} catch (PendingIntent.CanceledException e) {
TermuxApiLogger.error("execTermuxCommand error", e);
}
}

/**
* Checks to see if 'termux-api' pkg is installed
* @return
*/
@SuppressLint("SdCardPath")
static boolean hasToolsInstalled() {
return new File("/data/data/com.termux/files/usr/libexec/termux-api").exists();
}

/**
* Saves installed version to preferences
* @param context
*/
static void saveVersion(Context context) {
SharedPreferences preferences = context.getSharedPreferences(PREFERENCES, Context.MODE_PRIVATE);
SharedPreferences.Editor editor = preferences.edit();
editor.putString(KEY_API_VERSION, getInstalledVersion(context));
editor.apply();
}

static void setCanRemindUser(Context context, boolean canRemind) {
SharedPreferences preferences = context.getSharedPreferences(PREFERENCES, Context.MODE_PRIVATE);
SharedPreferences.Editor editor = preferences.edit();
editor.putBoolean(KEY_REMINDER, canRemind);
editor.apply();
}
}
}
Loading