//From the desk of Frank P. Westlake; public domain. package jackpal.androidterm.shortcuts; import android.content. Context; import android.content. DialogInterface; import android.content. Intent; import android.content. SharedPreferences; import android.graphics. Typeface; import android.net. Uri; import android.os. Bundle; import android.os. Environment; import android.preference. PreferenceManager; import android.util. Log; import android.view. Gravity; import android.view. View; import android.view. View.OnFocusChangeListener; import android.widget. Button; import android.widget. ImageView; import android.widget. LinearLayout; import android.widget. ScrollView; import android.widget. TextView; import android.widget. EditText; import jackpal.androidterm.R; import jackpal.androidterm.RemoteInterface; import jackpal.androidterm.RunShortcut; import jackpal.androidterm.TermDebug; import jackpal.androidterm.compat.AlertDialogCompat; import jackpal.androidterm.compat.PRNGFixes; import jackpal.androidterm.util.ShortcutEncryption; import java.io. File; import java.security. GeneralSecurityException; public class AddShortcut extends android.app.Activity { private final int OP_MAKE_SHORTCUT= 1; private final Context context= this; private SharedPreferences SP; private int ix= 0; private final int PATH= ix++ , ARGS= ix++ , NAME= ix++; private final EditText et[]= new EditText[5]; private String path; private String name=""; private String iconText[]= {"", null}; ////////////////////////////////////////////////////////////////////// protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); SP=PreferenceManager.getDefaultSharedPreferences(context); String action=getIntent().getAction(); if(action!=null && action.equals("android.intent.action.CREATE_SHORTCUT")) makeShortcut(); else finish(); } ////////////////////////////////////////////////////////////////////// void makeShortcut() { if(path==null) path=""; final AlertDialogCompat.Builder alert = AlertDialogCompat.newInstanceBuilder(context, AlertDialogCompat.THEME_HOLO_DARK); LinearLayout lv=new LinearLayout(context); lv.setOrientation(LinearLayout.VERTICAL); for(int i=0, n=et.length; i<n; i++) {et[i]=new EditText(context); et[i].setSingleLine(true);} if(!path.equals("")) et[0].setText(path); et[PATH].setHint(getString(R.string.addshortcut_command_hint));//"command"); et[NAME].setText(name); et[ARGS].setHint(getString(R.string.addshortcut_example_hint));//"--example=\"a\""); et[ARGS].setOnFocusChangeListener( new OnFocusChangeListener() { public void onFocusChange(View view, boolean focus) { if(!focus) { String s; if( et[NAME].getText().toString().equals("") && !(s=et[ARGS].getText().toString()).equals("") ) et[NAME].setText(s.split("\\s")[0]); } } } ); Button btn_path=new Button(context); btn_path.setText(getString(R.string.addshortcut_button_find_command));//"Find command"); btn_path.setOnClickListener( new View.OnClickListener() { public void onClick(View p1) { String lastPath=SP.getString("lastPath", null); File get= (lastPath==null) ?Environment.getExternalStorageDirectory() :new File(lastPath).getParentFile(); Intent pickerIntent=new Intent(); if(SP.getBoolean("useInternalScriptFinder", false)) { pickerIntent.setClass(getApplicationContext(), jackpal.androidterm.shortcuts.FSNavigator.class) .setData(Uri.fromFile(get)) .putExtra("title", getString(R.string.addshortcut_navigator_title));//"SELECT SHORTCUT TARGET") } else { pickerIntent .putExtra("CONTENT_TYPE", "*/*") .setAction(Intent.ACTION_PICK); } startActivityForResult(pickerIntent, OP_MAKE_SHORTCUT); } } ); lv.addView( layoutTextViewH( getString(R.string.addshortcut_command_window_instructions)//"Command window requires full path, no arguments. For other commands use Arguments window (ex: cd /sdcard)." , null , false ) ); lv.addView(layoutViewViewH(btn_path, et[PATH])); lv.addView(layoutTextViewH(getString(R.string.addshortcut_arguments_label), et[ARGS])); lv.addView(layoutTextViewH(getString(R.string.addshortcut_shortcut_label), et[NAME])); final ImageView img=new ImageView(context); img.setImageResource(jackpal.androidterm.R.drawable.ic_launcher); img.setMaxHeight(100); img.setTag(0xFFFFFFFF); img.setMaxWidth(100); img.setAdjustViewBounds(true); img.setScaleType(ImageView.ScaleType.CENTER_INSIDE); final Button btn_color=new Button(context); btn_color.setText(getString(R.string.addshortcut_button_text_icon));//"Text icon"); btn_color.setOnClickListener( new View.OnClickListener() { public void onClick(View p1) { new ColorValue(context, img, iconText); } } ); lv.addView( layoutTextViewH( getString(R.string.addshortcut_text_icon_instructions)//"Optionally create a text icon:" , null , false ) ); lv.addView(layoutViewViewH(btn_color, img)); final ScrollView sv=new ScrollView(context); sv.setFillViewport(true); sv.addView(lv); alert.setView(sv); alert.setTitle(getString(R.string.addshortcut_title));//"Term Shortcut"); alert.setPositiveButton( android.R.string.yes , new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { buildShortcut( path , et[ARGS].getText().toString() , et[NAME].getText().toString() , iconText[1] , (Integer)img.getTag() ); } } ); alert.setNegativeButton( android.R.string.cancel , new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { finish(); } } ); alert.show(); } ////////////////////////////////////////////////////////////////////// LinearLayout layoutTextViewH(String text, View vw) { return(layoutTextViewH(text, vw, true)); } LinearLayout layoutTextViewH(String text, View vw, boolean attributes) { LinearLayout.LayoutParams lp=new LinearLayout.LayoutParams(LinearLayout.LayoutParams.FILL_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT, 1); TextView tv=new TextView(context); tv.setText(text); if(attributes) tv.setTypeface(Typeface.DEFAULT_BOLD); if(attributes) tv.setGravity(Gravity.RIGHT|Gravity.CENTER_VERTICAL); tv.setPadding(10, tv.getPaddingTop(), 10, tv.getPaddingBottom()); LinearLayout lh=new LinearLayout(context); lh.setOrientation(LinearLayout.HORIZONTAL); lh.addView(tv, lp); if(vw!=null) lh.addView(vw, lp); return(lh); } ////////////////////////////////////////////////////////////////////// LinearLayout layoutViewViewH(View vw1, View vw2) { LinearLayout.LayoutParams lp=new LinearLayout.LayoutParams(LinearLayout.LayoutParams.FILL_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT, 1); LinearLayout lh=new LinearLayout(context); lh.setOrientation(LinearLayout.HORIZONTAL); lh.addView(vw1, lp); if(vw2!=null) lh.addView(vw2, lp); return(lh); } ////////////////////////////////////////////////////////////////////// void buildShortcut( String path , String arguments , String shortcutName , String shortcutText , int shortcutColor ) { // Apply workarounds for SecureRandom bugs in Android < 4.4 PRNGFixes.apply(); ShortcutEncryption.Keys keys=ShortcutEncryption.getKeys(context); if(keys==null) { try { keys=ShortcutEncryption.generateKeys(); } catch (GeneralSecurityException e) { Log.e(TermDebug.LOG_TAG, "Generating shortcut encryption keys failed: " + e.toString()); throw new RuntimeException(e); } ShortcutEncryption.saveKeys(context, keys); } StringBuilder cmd=new StringBuilder(); if(path!=null && !path.equals("")) cmd.append(RemoteInterface.quoteForBash(path)); if(arguments!=null && !arguments.equals("")) cmd.append(" " + arguments); String cmdStr=cmd.toString(); String cmdEnc=null; try { cmdEnc=ShortcutEncryption.encrypt(cmdStr, keys); } catch (GeneralSecurityException e) { Log.e(TermDebug.LOG_TAG, "Shortcut encryption failed: " + e.toString()); throw new RuntimeException(e); } Intent target= new Intent().setClass(context, RunShortcut.class); target.setAction(RunShortcut.ACTION_RUN_SHORTCUT); target.putExtra(RunShortcut.EXTRA_SHORTCUT_COMMAND, cmdEnc); target.putExtra(RunShortcut.EXTRA_WINDOW_HANDLE, shortcutName); target.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); Intent wrapper= new Intent(); wrapper.setAction("com.android.launcher.action.INSTALL_SHORTCUT"); wrapper.putExtra(Intent.EXTRA_SHORTCUT_INTENT, target); if(shortcutName!=null && !shortcutName.equals("")) { wrapper.putExtra(Intent.EXTRA_SHORTCUT_NAME, shortcutName); } if(shortcutText!=null && !shortcutText.equals("")) { wrapper.putExtra( Intent.EXTRA_SHORTCUT_ICON , TextIcon.getTextIcon( shortcutText , shortcutColor , 96 , 96 ) ); } else { wrapper.putExtra( Intent.EXTRA_SHORTCUT_ICON_RESOURCE , Intent.ShortcutIconResource.fromContext(context, jackpal.androidterm.R.drawable.ic_launcher) ); } setResult(RESULT_OK, wrapper); finish(); } ////////////////////////////////////////////////////////////////////// protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); Uri uri= null; path= null; switch(requestCode) { case OP_MAKE_SHORTCUT: if(data!=null && (uri=data.getData())!=null && (path=uri.getPath())!=null) { SP.edit().putString("lastPath", path).commit(); et[PATH].setText(path); name=path.replaceAll(".*/", ""); if(et[NAME].getText().toString().equals("")) et[NAME].setText(name); if(iconText[0]!=null && iconText[0].equals("")) iconText[0]=name; } else finish(); break; } } ////////////////////////////////////////////////////////////////////// }