From d8aeeec60eb586d7bb0cd8519a9cfb6de6234252 Mon Sep 17 00:00:00 2001 From: buddygr Date: Fri, 27 May 2022 12:40:14 +0800 Subject: [PATCH 1/2] =?UTF-8?q?fix:=20=E6=94=AF=E6=8C=81=E5=8A=A8=E6=80=81?= =?UTF-8?q?=E7=94=B3=E8=AF=B7=E5=85=8D=E6=89=93=E6=89=B0=E6=9D=83=E9=99=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../qsl4a/qsl4a/facade/SettingsFacade.java | 50 +++++++++++++++---- 1 file changed, 39 insertions(+), 11 deletions(-) diff --git a/src/main/java/org/qpython/qsl4a/qsl4a/facade/SettingsFacade.java b/src/main/java/org/qpython/qsl4a/qsl4a/facade/SettingsFacade.java index f478780..d89d605 100644 --- a/src/main/java/org/qpython/qsl4a/qsl4a/facade/SettingsFacade.java +++ b/src/main/java/org/qpython/qsl4a/qsl4a/facade/SettingsFacade.java @@ -16,12 +16,15 @@ package org.qpython.qsl4a.qsl4a.facade; +import android.app.NotificationManager; import android.app.Service; import android.content.Context; import android.content.Intent; import android.media.AudioManager; +import android.os.Build; import android.os.PowerManager; +import android.provider.Settings; import android.provider.Settings.SettingNotFoundException; import android.view.WindowManager; @@ -51,6 +54,9 @@ public class SettingsFacade extends RpcReceiver { private final AudioManager mAudio; private final PowerManager mPower; + private final AndroidFacade mAndroidFacade; + private final Context context; + /** * Creates a new SettingsFacade. * @@ -62,8 +68,21 @@ public class SettingsFacade extends RpcReceiver { mService = manager.getService(); mAudio = (AudioManager) mService.getSystemService(Context.AUDIO_SERVICE); mPower = (PowerManager) mService.getSystemService(Context.POWER_SERVICE); + mAndroidFacade = manager.getReceiver(AndroidFacade.class); + context = mAndroidFacade.context; } + private void NotificationPolicyAccessGranted() throws Exception { + NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N + && !notificationManager.isNotificationPolicyAccessGranted()) { + Intent intent = new Intent(Settings.ACTION_NOTIFICATION_POLICY_ACCESS_SETTINGS); + mAndroidFacade.startActivityForResult(intent); + if(!notificationManager.isNotificationPolicyAccessGranted()){ + throw new Exception("Need Permission of NOTIFICATION_POLICY_ACCESS_SETTINGS ."); + } + }} + @Rpc(description = "Sets the screen timeout to this number of seconds.", returns = "The original screen timeout.") public Integer setScreenTimeout(@RpcParameter(name = "value") Integer value) { Integer oldValue = getScreenTimeout(); @@ -108,25 +127,31 @@ public class SettingsFacade extends RpcReceiver { return enabled; } - @Rpc(description = "Checks the ringer silent mode setting.", returns = "True if ringer silent mode is enabled.") - public Boolean checkRingerSilentMode() { - return mAudio.getRingerMode() == AudioManager.RINGER_MODE_SILENT; - } - @Rpc(description = "Toggles ringer silent mode on and off.", returns = "True if ringer silent mode is enabled.") - public Boolean toggleRingerSilentMode(@RpcParameter(name = "enabled") @RpcOptional Boolean enabled) { + public Boolean toggleRingerSilentMode( + @RpcParameter(name = "enabled") @RpcOptional Boolean enabled + ) throws Exception { + NotificationPolicyAccessGranted(); if (enabled == null) { enabled = !checkRingerSilentMode(); } mAudio.setRingerMode(enabled ? AudioManager.RINGER_MODE_SILENT - : AudioManager.RINGER_MODE_NORMAL); + : AudioManager.RINGER_MODE_NORMAL); return enabled; } + @Rpc(description = "Checks the ringer silent mode setting.", returns = "True if ringer silent mode is enabled.") + public Boolean checkRingerSilentMode() { + return mAudio.getRingerMode() == AudioManager.RINGER_MODE_SILENT; + } + @SuppressWarnings("deprecation") -@Rpc(description = "Toggles vibrate mode on and off. If ringer=true then set Ringer setting, else set Notification setting", returns = "True if vibrate mode is enabled.") - public Boolean toggleVibrateMode(@RpcParameter(name = "enabled") @RpcOptional Boolean enabled, - @RpcParameter(name = "ringer") @RpcOptional Boolean ringer) { + @Rpc(description = "Toggles vibrate mode on and off. If ringer=true then set Ringer setting, else set Notification setting", returns = "True if vibrate mode is enabled.") + public Boolean toggleVibrateMode( + @RpcParameter(name = "enabled") @RpcOptional Boolean enabled, + @RpcParameter(name = "ringer") @RpcOptional Boolean ringer + ) throws Exception { + NotificationPolicyAccessGranted(); int atype = ringer ? AudioManager.VIBRATE_TYPE_RINGER : AudioManager.VIBRATE_TYPE_NOTIFICATION; int asetting = enabled ? AudioManager.VIBRATE_SETTING_ON : AudioManager.VIBRATE_SETTING_OFF; mAudio.setVibrateSetting(atype, asetting); @@ -151,7 +176,10 @@ public class SettingsFacade extends RpcReceiver { } @Rpc(description = "Sets the ringer volume.") - public void setRingerVolume(@RpcParameter(name = "volume") Integer volume) { + public void setRingerVolume( + @RpcParameter(name = "volume") Integer volume + ) throws Exception { + NotificationPolicyAccessGranted(); mAudio.setStreamVolume(AudioManager.STREAM_RING, volume, 0); } -- Gitee From 9d857c97c75df59f34ee0a2f9f468e1078fc3a37 Mon Sep 17 00:00:00 2001 From: buddygr Date: Sun, 12 Jun 2022 14:27:47 +0800 Subject: [PATCH 2/2] =?UTF-8?q?feat:=20FutureActivity=E5=8D=87=E7=BA=A7?= =?UTF-8?q?=E4=B8=BA=E6=9C=AA=E6=9D=A5=E5=B0=8F=E7=A8=8B=E5=BA=8F=20feat:?= =?UTF-8?q?=20=E6=96=B0=E5=A2=9E/=E6=9B=B4=E6=96=B0=E5=A4=9A=E4=B8=AASL4A?= =?UTF-8?q?=E5=87=BD=E6=95=B0=EF=BC=9A=20=20=20fullGetProperty,fullGetProp?= =?UTF-8?q?erties,fullSetProperties,=20=20=20fullGetScreenShot,=20=20=20fu?= =?UTF-8?q?llSetListHtml,fullSetList2=20feat:=20FutureActivity=E7=9A=84Tex?= =?UTF-8?q?tView/EditText/Button=E6=96=B0=E5=A2=9Ehtml/textAllCaps?= =?UTF-8?q?=E5=B1=9E=E6=80=A7=20feat:=20FutureActivity=E7=9A=84progressBar?= =?UTF-8?q?=E6=96=B0=E5=A2=9EprogressColor=E5=B1=9E=E6=80=A7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/AndroidManifest.xml | 4 +- .../qsl4a/FutureActivityTaskExecutor.java | 22 +- .../qsl4a/qsl4a/facade/ui/FullScreenTask.java | 186 ++++++++++++-- .../qsl4a/qsl4a/facade/ui/UiFacade.java | 132 +++++++++- .../qsl4a/qsl4a/facade/ui/ViewInflater.java | 234 ++++++++++++++---- .../qpython/qsl4a/qsl4a/util/HtmlUtil.java | 26 ++ 6 files changed, 513 insertions(+), 91 deletions(-) create mode 100644 src/main/java/org/qpython/qsl4a/qsl4a/util/HtmlUtil.java diff --git a/src/main/AndroidManifest.xml b/src/main/AndroidManifest.xml index 4006845..d59ae2c 100644 --- a/src/main/AndroidManifest.xml +++ b/src/main/AndroidManifest.xml @@ -1,4 +1,5 @@ @@ -8,6 +9,7 @@ - + diff --git a/src/main/java/org/qpython/qsl4a/qsl4a/FutureActivityTaskExecutor.java b/src/main/java/org/qpython/qsl4a/qsl4a/FutureActivityTaskExecutor.java index 5634294..24c2f48 100644 --- a/src/main/java/org/qpython/qsl4a/qsl4a/FutureActivityTaskExecutor.java +++ b/src/main/java/org/qpython/qsl4a/qsl4a/FutureActivityTaskExecutor.java @@ -34,6 +34,8 @@ public class FutureActivityTaskExecutor { new ConcurrentHashMap>(); private final AtomicInteger mIdGenerator = new AtomicInteger(0); + private final int intentFlags = Intent.FLAG_ACTIVITY_NEW_DOCUMENT | Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_MULTIPLE_TASK; + public FutureActivityTaskExecutor(Context context) { mContext = context; } @@ -41,17 +43,23 @@ public class FutureActivityTaskExecutor { public void execute(FutureActivityTask task) { int id = mIdGenerator.incrementAndGet(); mTaskMap.put(id, task); - launchHelper(id); - } - - public FutureActivityTask getTask(int id) { - return mTaskMap.remove(id); + Intent helper = new Intent(mContext, FutureActivity.class); + helper.putExtra(Constants.EXTRA_TASK_ID, id); + helper.setFlags(intentFlags); + mContext.startActivity(helper); } - private void launchHelper(int id) { + public void execute(FutureActivityTask task,int flags) { + int id = mIdGenerator.incrementAndGet(); + mTaskMap.put(id, task); Intent helper = new Intent(mContext, FutureActivity.class); - helper.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_MULTIPLE_TASK); helper.putExtra(Constants.EXTRA_TASK_ID, id); + helper.setFlags(flags); mContext.startActivity(helper); } + + public FutureActivityTask getTask(int id) { + return mTaskMap.remove(id); + } + } diff --git a/src/main/java/org/qpython/qsl4a/qsl4a/facade/ui/FullScreenTask.java b/src/main/java/org/qpython/qsl4a/qsl4a/facade/ui/FullScreenTask.java index 1cec678..a49ba9c 100644 --- a/src/main/java/org/qpython/qsl4a/qsl4a/facade/ui/FullScreenTask.java +++ b/src/main/java/org/qpython/qsl4a/qsl4a/facade/ui/FullScreenTask.java @@ -18,7 +18,15 @@ package org.qpython.qsl4a.qsl4a.facade.ui; import android.R; +import android.app.Activity; +import android.app.ActivityManager; +import android.graphics.Bitmap; +import android.graphics.PorterDuff; +import android.graphics.drawable.Drawable; +import android.graphics.drawable.LayerDrawable; +import android.os.Build; import android.os.Handler; +import android.support.annotation.RequiresApi; import android.view.KeyEvent; import android.view.Menu; import android.view.View; @@ -27,13 +35,15 @@ import android.view.ViewGroup.LayoutParams; import android.widget.AdapterView; import android.widget.AdapterView.OnItemClickListener; import android.widget.Button; +import android.widget.EditText; import android.widget.LinearLayout; import android.widget.SeekBar; import android.widget.SeekBar.OnSeekBarChangeListener; -import android.widget.TextView; +import org.json.JSONArray; import org.qpython.qsl4a.qsl4a.facade.EventFacade; import org.qpython.qsl4a.qsl4a.future.FutureActivityTask; +import org.xmlpull.v1.XmlPullParser; import java.io.StringReader; import java.util.HashMap; @@ -41,9 +51,6 @@ import java.util.List; import java.util.Map; import java.util.concurrent.CountDownLatch; -import org.json.JSONArray; -import org.xmlpull.v1.XmlPullParser; - public class FullScreenTask extends FutureActivityTask implements OnClickListener, OnItemClickListener, OnSeekBarChangeListener { private EventFacade mEventFacade; @@ -55,20 +62,27 @@ public class FullScreenTask extends FutureActivityTask implements OnClic protected Handler mHandler = null; private List mOverrideKeys; protected String mTitle; + protected int mTheme; - public FullScreenTask(String layout, String title) { + public FullScreenTask(String layout, String title, Integer theme) { super(); mLayout = layout; if (title != null) { mTitle = title; } else { - mTitle = "SL4a"; + mTitle = ""; + } + if (theme != null) { + mTheme = theme; + } else { + mTheme = 0; } } @Override public void onCreate() { // super.onCreate(); + final Activity activity = getActivity(); if (mHandler == null) { mHandler = new Handler(); } @@ -77,15 +91,20 @@ public class FullScreenTask extends FutureActivityTask implements OnClic if (mView == null) { StringReader sr = new StringReader(mLayout); XmlPullParser xml = ViewInflater.getXml(sr); - mView = mInflater.inflate(getActivity(), xml); + mView = mInflater.inflate(activity, xml); } } catch (Exception e) { - mInflater.getErrors().add(e.toString()); - mView = defaultView(); + String E = e.toString(); + mInflater.getErrors().add(E); + mView = defaultView(E); mInflater.setIdList(R.id.class); } - getActivity().setContentView(mView); - getActivity().setTitle(mTitle); + //activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LOCKED); + activity.setTheme(mTheme); + activity.setContentView(mView); + activity.setTitle(mTitle); + if (!mTitle.equals("")) + activity.setTaskDescription(new ActivityManager.TaskDescription(mTitle)); mInflater.setClickListener(mView, this, this, this); mShowLatch.countDown(); } @@ -97,15 +116,16 @@ public class FullScreenTask extends FutureActivityTask implements OnClic } /** default view in case of errors */ - protected View defaultView() { - LinearLayout result = new LinearLayout(getActivity()); + protected View defaultView(String Error) { + final Activity activity = getActivity(); + LinearLayout result = new LinearLayout(activity); result.setOrientation(LinearLayout.VERTICAL); - TextView text = new TextView(getActivity()); - text.setText("Sample Layout"); - result.addView(text, LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT); - Button b = new Button(getActivity()); - b.setText("OK"); - result.addView(b, LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT); + EditText text = new EditText(activity); + text.setText("Error Message :\n" + Error); + result.addView(text, LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT); + Button OK = new Button(activity); + OK.setText("OK"); + result.addView(OK, LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT); return result; } @@ -148,6 +168,18 @@ public class FullScreenTask extends FutureActivityTask implements OnClic return result; } + public String getViewPropery(String idName,String attr) { + View v = getViewByName(idName); + switch (attr) { + case "id": + return idName; + case "type": + return v.getClass().getSimpleName(); + default: + return mInflater.getProperty(v,attr); + } + } + public String setViewProperty(String idName, String property, String value) { View v = getViewByName(idName); mInflater.getErrors().clear(); @@ -188,6 +220,46 @@ public class FullScreenTask extends FutureActivityTask implements OnClic return mInflater.getErrors().get(0); } + public String setListHtml(String id, JSONArray items) { + View v = getViewByName(id); + mInflater.getErrors().clear(); + if (v != null) { + SetListHtml p = new SetListHtml(v, items); + mHandler.post(p); + try { + p.mLatch.await(); + } catch (InterruptedException e) { + mInflater.getErrors().add(e.toString()); + } + } else { + return "View " + id + " not found."; + } + if (mInflater.getErrors().size() == 0) { + return "OK"; + } + return mInflater.getErrors().get(0); + } + + public String setList2(String id, JSONArray items, JSONArray intRes) { + View v = getViewByName(id); + mInflater.getErrors().clear(); + if (v != null) { + SetList2 p = new SetList2(v, items, intRes); + mHandler.post(p); + try { + p.mLatch.await(); + } catch (InterruptedException e) { + mInflater.getErrors().add(e.toString()); + } + } else { + return "View " + id + " not found."; + } + if (mInflater.getErrors().size() == 0) { + return "OK"; + } + return mInflater.getErrors().get(0); + } + @Override public void onClick(View view) { mEventFacade.postEvent("click", mInflater.getViewInfo(view)); @@ -250,6 +322,46 @@ public class FullScreenTask extends FutureActivityTask implements OnClic } } + private class SetListHtml implements Runnable { + View mView; + JSONArray mItems; + CountDownLatch mLatch = new CountDownLatch(1); + + SetListHtml(View view, JSONArray items) { + mView = view; + mItems = items; + mLatch.countDown(); + } + + @RequiresApi(api = Build.VERSION_CODES.N) + @Override + public void run() { + mInflater.setListAdapterHtml(mView, mItems); + mView.invalidate(); + } + } + + private class SetList2 implements Runnable { + View mView; + JSONArray mItems; + JSONArray mIntRes; + + CountDownLatch mLatch = new CountDownLatch(1); + + SetList2(View view, JSONArray intRes, JSONArray items) { + mView = view; + mItems = items; + mIntRes = intRes; + mLatch.countDown(); + } + + @Override + public void run() { + mInflater.setListAdapter2(mView, mIntRes, mItems); + mView.invalidate(); + } + } + private class SetLayout implements Runnable { String mLayout; CountDownLatch mLatch = new CountDownLatch(1); @@ -281,16 +393,28 @@ public class FullScreenTask extends FutureActivityTask implements OnClic } } + private class SetTheme implements Runnable { + int mSetTheme; + CountDownLatch mLatch = new CountDownLatch(1); + + SetTheme(int theme) { mSetTheme = theme;} + + @Override + public void run() { + mTheme = mSetTheme; + getActivity().setTheme(mSetTheme); + mLatch.countDown(); + } + } + @Override public boolean onKeyDown(int keyCode, KeyEvent event) { Map data = new HashMap(); data.put("key", String.valueOf(keyCode)); data.put("action", String.valueOf(event.getAction())); mEventFacade.postEvent("key", data); - boolean overrideKey = - (keyCode == KeyEvent.KEYCODE_BACK) - || (mOverrideKeys == null ? false : mOverrideKeys.contains(keyCode)); - return overrideKey; + return (keyCode == KeyEvent.KEYCODE_BACK) + || (mOverrideKeys != null && mOverrideKeys.contains(keyCode)); } @Override @@ -330,6 +454,16 @@ public class FullScreenTask extends FutureActivityTask implements OnClic } } + public void setTheme(int theme) { + SetTheme p = new SetTheme(theme); + mHandler.post(p); + try { + p.mLatch.await(); + } catch (InterruptedException e) { + mInflater.getErrors().add(e.toString()); + } + } + @Override public void onProgressChanged(SeekBar aview, int progress, boolean fromUser) { Map data = mInflater.getViewInfo(aview); @@ -350,4 +484,10 @@ public class FullScreenTask extends FutureActivityTask implements OnClic } + public Bitmap getScreenShot() { + View v = getActivity().getWindow().getDecorView(); + v.setDrawingCacheEnabled(true); + return v.getDrawingCache(); + } + } diff --git a/src/main/java/org/qpython/qsl4a/qsl4a/facade/ui/UiFacade.java b/src/main/java/org/qpython/qsl4a/qsl4a/facade/ui/UiFacade.java index f25207f..d4050df 100644 --- a/src/main/java/org/qpython/qsl4a/qsl4a/facade/ui/UiFacade.java +++ b/src/main/java/org/qpython/qsl4a/qsl4a/facade/ui/UiFacade.java @@ -18,6 +18,8 @@ package org.qpython.qsl4a.qsl4a.facade.ui; import android.app.ProgressDialog; import android.app.Service; +import android.graphics.Bitmap; +import android.os.Environment; import android.util.AndroidRuntimeException; import android.view.ContextMenu; import android.view.ContextMenu.ContextMenuInfo; @@ -26,22 +28,23 @@ import android.view.MenuItem; import android.view.View; import org.qpython.qsl4a.QSL4APP; -import org.qpython.qsl4a.qsl4a.BaseApplication; -import org.qpython.qsl4a.qsl4a.FileUtils; import org.qpython.qsl4a.qsl4a.FutureActivityTaskExecutor; import org.qpython.qsl4a.qsl4a.facade.EventFacade; import org.qpython.qsl4a.qsl4a.facade.FacadeManager; import org.qpython.qsl4a.qsl4a.interpreter.html.HtmlActivityTask; -import org.qpython.qsl4a.qsl4a.interpreter.html.HtmlInterpreter; import org.qpython.qsl4a.qsl4a.jsonrpc.RpcReceiver; import org.qpython.qsl4a.qsl4a.rpc.Rpc; import org.qpython.qsl4a.qsl4a.rpc.RpcDefault; import org.qpython.qsl4a.qsl4a.rpc.RpcOptional; import org.qpython.qsl4a.qsl4a.rpc.RpcParameter; -import java.io.IOException; +import java.io.File; +import java.io.FileOutputStream; +import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Collections; +import java.util.Date; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; @@ -131,6 +134,8 @@ public class UiFacade extends RpcReceiver { private final EventFacade mEventFacade; private List mOverrideKeys = Collections.synchronizedList(new ArrayList()); + private final String sdcard; + public UiFacade(FacadeManager manager) { super(manager); mService = manager.getService(); @@ -139,6 +144,7 @@ public class UiFacade extends RpcReceiver { mOptionsMenuItems = new CopyOnWriteArrayList(); mEventFacade = manager.getReceiver(EventFacade.class); mMenuUpdated = new AtomicBoolean(false); + sdcard = Environment.getExternalStorageDirectory().toString(); } /** @@ -343,6 +349,15 @@ public class UiFacade extends RpcReceiver { } } + @Rpc(description = "Set progress dialog message .") + public void dialogSetProgressMessage(@RpcParameter(name = "message") String message) { + if (mDialogTask != null && mDialogTask instanceof ProgressDialogTask) { + ((ProgressDialog) mDialogTask.getDialog()).setMessage(message); + } else { + throw new RuntimeException("No valid dialog to set message ."); + } + } + @Rpc(description = "Set alert dialog positive button text.") public void dialogSetPositiveButtonText(@RpcParameter(name = "text") String text) { if (mDialogTask != null && mDialogTask instanceof AlertDialogTask) { @@ -446,7 +461,7 @@ public class UiFacade extends RpcReceiver { * See wiki page for more * detail. */ - @Rpc(description = "Display a WebView with the given URL.") + /*@Rpc(description = "Display a WebView with the given URL.") public void webViewShow( @RpcParameter(name = "url") String url, @RpcParameter(name = "wait", description = "block until the user exits the WebView") @RpcOptional Boolean wait) @@ -464,7 +479,7 @@ public class UiFacade extends RpcReceiver { throw new RuntimeException(e); } } - } + }*/ /** * Context menus are used primarily with {@link #webViewShow} @@ -553,7 +568,8 @@ public class UiFacade extends RpcReceiver { @Rpc(description = "Show Full Screen.") public List fullShow( @RpcParameter(name = "layout", description = "String containing View layout") String layout, - @RpcParameter(name = "title", description = "Activity Title") @RpcOptional String title) + @RpcParameter(name = "title", description = "Activity Title") @RpcOptional String title, + @RpcParameter(name = "theme", description = "Activity Theme") @RpcOptional Integer theme) throws InterruptedException { if (mFullScreenTask != null) { // fullDismiss(); @@ -561,8 +577,11 @@ public class UiFacade extends RpcReceiver { if (title != null) { mFullScreenTask.setTitle(title); } + if (theme != null) { + mFullScreenTask.setTheme(theme); + } } else { - mFullScreenTask = new FullScreenTask(layout, title); + mFullScreenTask = new FullScreenTask(layout, title, theme); mFullScreenTask.setEventFacade(mEventFacade); mFullScreenTask.setUiFacade(this); mFullScreenTask.setOverrideKeys(mOverrideKeys); @@ -597,7 +616,37 @@ public class UiFacade extends RpcReceiver { return mFullScreenTask.getViewDetail(id); } - @Rpc(description = "Set fullscreen widget property") + @Rpc(description = "Get a fullscreen property for a specific widget") + public String fullGetProperty( + @RpcParameter(name = "id", description = "id of layout widget") String id, + @RpcParameter(name = "property", description = "property of layout widget") String property) + throws JSONException { + if (mFullScreenTask == null) { + throw new RuntimeException("No screen displayed."); + } + return mFullScreenTask.getViewPropery(id,property); + } + + @Rpc(description = "Get a fullscreen property for many specific widgets") + public JSONArray fullGetProperties( + @RpcParameter(name = "ids", description = "ids of layout widgets") JSONArray ids, + @RpcParameter(name = "property", description = "property of layout widgets") String property) + throws JSONException { + if (mFullScreenTask == null) { + throw new RuntimeException("No screen displayed."); + } + List Ids = new ArrayList(); + for (int i = 0; i < ids.length(); i++) { + Ids.add(ids.get(i).toString()); + } + JSONArray rst = new JSONArray(); + for(String id:Ids) { + rst.put(mFullScreenTask.getViewPropery(id,property)); + } + return rst; + } + + @Rpc(description = "Set a fullscreen widget's a property") public String fullSetProperty( @RpcParameter(name = "id", description = "id of layout widget") String id, @RpcParameter(name = "property", description = "name of property to set") String property, @@ -608,7 +657,29 @@ public class UiFacade extends RpcReceiver { return mFullScreenTask.setViewProperty(id, property, value); } - @Rpc(description = "Attach a list to a fullscreen widget") + @Rpc(description = "Set many fullscreen widgets' a property") + public String fullSetProperties( + @RpcParameter(name = "ids", description = "ids of layout widgets") JSONArray ids, + @RpcParameter(name = "property", description = "name of property to set") String property, + @RpcParameter(name = "value", description = "value to set property to") String value) + throws JSONException { + if (mFullScreenTask == null) { + throw new RuntimeException("No screen displayed."); + } + List Ids = new ArrayList(); + for (int i = 0; i < ids.length(); i++) { + Ids.add(ids.get(i).toString()); + } + String rst; + for(String id:Ids) { + rst = mFullScreenTask.setViewProperty(id, property, value); + if (!rst.equals("OK")) + return rst; + } + return "OK"; + } + + @Rpc(description = "Attach a text list to a fullscreen widget") public String fullSetList( @RpcParameter(name = "id", description = "id of layout widget") String id, @RpcParameter(name = "list", description = "List to set") JSONArray items) { @@ -618,6 +689,27 @@ public class UiFacade extends RpcReceiver { return mFullScreenTask.setList(id, items); } + @Rpc(description = "Attach a html list to a fullscreen widget") + public String fullSetListHtml( + @RpcParameter(name = "id", description = "id of layout widget") String id, + @RpcParameter(name = "list", description = "List to set") JSONArray items) { + if (mFullScreenTask == null) { + throw new RuntimeException("No screen displayed."); + } + return mFullScreenTask.setListHtml(id, items); + } + + @Rpc(description = "Attach a 2-line list to a fullscreen widget") + public String fullSetList2( + @RpcParameter(name = "id", description = "id of layout widget") String id, + @RpcParameter(name = "list", description = "List to set") JSONArray items, + @RpcParameter(name = "intRes", description = "integers of list resource") JSONArray intRes) { + if (mFullScreenTask == null) { + throw new RuntimeException("No screen displayed."); + } + return mFullScreenTask.setList2(id, items, intRes); + } + @Rpc(description = "Set the Full Screen Activity Title") public void fullSetTitle( @RpcParameter(name = "title", description = "Activity Title") String title) { @@ -693,4 +785,24 @@ public class UiFacade extends RpcReceiver { }; } } + + @Rpc(description = "Get the Full Screen Activity ScreenShot to path .") + public String fullGetScreenShot( + @RpcParameter(name = "path") @RpcOptional String path) throws Exception { + if (mFullScreenTask == null) { + throw new RuntimeException("No screen displayed."); + } + if (path == null) { + path = sdcard + "/Pictures/Screenshots/"; /*存放截屏的文件夹*/ + File _path = new File(path); + if (!_path.exists()) { + _path.mkdirs(); + } + path += new SimpleDateFormat("yyyyMMdd-HHmmss").format(new Date()) + ".jpg";//图片命名 + } + Bitmap bmp = mFullScreenTask.getScreenShot(); + bmp.compress(Bitmap.CompressFormat.JPEG,100,new FileOutputStream(path)); + return path; + } + } \ No newline at end of file diff --git a/src/main/java/org/qpython/qsl4a/qsl4a/facade/ui/ViewInflater.java b/src/main/java/org/qpython/qsl4a/qsl4a/facade/ui/ViewInflater.java index 60f1599..d0aa0df 100644 --- a/src/main/java/org/qpython/qsl4a/qsl4a/facade/ui/ViewInflater.java +++ b/src/main/java/org/qpython/qsl4a/qsl4a/facade/ui/ViewInflater.java @@ -17,15 +17,23 @@ package org.qpython.qsl4a.qsl4a.facade.ui; +import android.annotation.SuppressLint; import android.app.Activity; import android.content.Context; import android.graphics.Bitmap; import android.graphics.BitmapFactory; +import android.graphics.PorterDuff; import android.graphics.Typeface; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; +import android.graphics.drawable.LayerDrawable; import android.net.Uri; +import android.os.Build; +import android.support.annotation.RequiresApi; +import android.text.Html; import android.text.InputType; +import android.text.SpannableString; +import android.text.Spanned; import android.text.method.DigitsKeyListener; import android.util.DisplayMetrics; import android.view.Gravity; @@ -39,12 +47,18 @@ import android.widget.ArrayAdapter; import android.widget.ListAdapter; import android.widget.RelativeLayout; import android.widget.SeekBar; +import android.widget.SimpleAdapter; import android.widget.Spinner; import android.widget.SpinnerAdapter; import android.widget.TableLayout; import android.widget.TextView; +import org.json.JSONArray; import org.qpython.qsl4a.qsl4a.LogUtil; +import org.qpython.qsl4a.qsl4a.util.HtmlUtil; +import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlPullParserException; +import org.xmlpull.v1.XmlPullParserFactory; import java.io.IOException; import java.io.InputStream; @@ -59,14 +73,10 @@ import java.util.List; import java.util.Map; import java.util.Map.Entry; -import org.json.JSONArray; -import org.xmlpull.v1.XmlPullParser; -import org.xmlpull.v1.XmlPullParserException; -import org.xmlpull.v1.XmlPullParserFactory; - public class ViewInflater { private static XmlPullParserFactory mFactory; public static final String ANDROID = "http://schemas.android.com/apk/res/android"; + public static final String QPYTHON = "http://www.qpython.org"; public static final int BASESEQ = 0x7f0f0000; private int mNextSeq = BASESEQ; private final Map mIdList = new HashMap(); @@ -76,6 +86,7 @@ public class ViewInflater { private static final Map mInputTypes = new HashMap(); public static final Map mColorNames = new HashMap(); public static final Map mRelative = new HashMap(); + static { mColorNames.put("aliceblue", "#f0f8ff"); mColorNames.put("antiquewhite", "#faebd7"); @@ -330,7 +341,7 @@ public class ViewInflater { while ((event = xml.next()) != XmlPullParser.END_DOCUMENT) { switch (event) { case XmlPullParser.START_TAG: - if (view == null || view instanceof ViewGroup) { + if (/*view == null ||*/ view instanceof ViewGroup) { inflateView(context, xml, (ViewGroup) view); } else { skipTag(xml); // Not really a view, probably, skip it. @@ -363,6 +374,8 @@ public class ViewInflater { String attr = xml.getAttributeName(i); if (ANDROID.equals(ns)) { setProperty(view, root, attr, xml.getAttributeValue(i)); + } else if (QPYTHON.equals(ns)) { + setProperty(view, root, attr, xml.getAttributeValue(i)); } } if (root != null) { @@ -378,7 +391,7 @@ public class ViewInflater { return 0; } if (value.equals("match_parent")) { - return LayoutParams.FILL_PARENT; + return LayoutParams.MATCH_PARENT; } if (value.equals("wrap_content")) { return LayoutParams.WRAP_CONTENT; @@ -467,10 +480,10 @@ public class ViewInflater { String lookfor = root.getClass().getName() + "$LayoutParams"; addln(lookfor); Class clazz = Class.forName(lookfor).asSubclass(LayoutParams.class); - if (clazz != null) { + //if (clazz != null) { Constructor ct = clazz.getConstructor(int.class, int.class); result = ct.newInstance(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT); - } + //} } catch (Exception e) { result = null; } @@ -489,6 +502,7 @@ public class ViewInflater { } } + @SuppressLint("WrongConstant") private void setProperty(View view, ViewGroup root, String attr, String value) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException { addln(attr + ":" + value); @@ -520,7 +534,7 @@ public class ViewInflater { } else if (attr.equals("textHighlightColor")) { setInteger(view, "HighlightColor", getColor(value)); } else if (attr.equals("textColorHint")) { - setInteger(view, "LinkTextColor", getColor(value)); + setInteger(view, "HintTextColor", getColor(value)); } else if (attr.equals("textStyle")) { TextView textview = (TextView) view; int style = getInteger(Typeface.class, value); @@ -536,7 +550,37 @@ public class ViewInflater { textview.setTypeface(Typeface.create(value, style)); } else if (attr.equals("src")) { setImage(view, value); - } else { + } else if (attr.equals("textAllCaps")) { + TextView textview = (TextView) view; + textview.setAllCaps(Boolean.parseBoolean(value)); + } else if (attr.startsWith("progress")) { + attr = attr.substring(8); + SeekBar seekBar = (SeekBar) view; + if (attr.equals("")){ + int progress; + progress = Integer.valueOf(value); + if (seekBar.getMax() viewclass = Class.forName(name).asSubclass(View.class); - if (viewclass != null) { + //if (viewclass != null) { Constructor ct = viewclass.getConstructor(Context.class); result = ct.newInstance(context); - } + //} } catch (Exception e) { } return result; @@ -923,7 +977,7 @@ public class ViewInflater { } } - private String getProperty(View v, String attr) { + public String getProperty(View v, String attr) { String name = PCase(attr); Method m = tryMethod(v, "get" + name); if (m == null) { @@ -936,9 +990,11 @@ public class ViewInflater { if (o != null) { result = o.toString(); } - } catch (Exception e) { - result = null; + } catch (Exception ignored) { } + } else if (attr.equals("html")){ + TextView tv = (TextView) v; + result = Html.toHtml(new SpannableString(tv.getText())); } return result; } @@ -1002,18 +1058,49 @@ public class ViewInflater { list.add(items.get(i).toString()); } ArrayAdapter adapter; + Method m; if (view instanceof Spinner) { adapter = - new ArrayAdapter(mContext, android.R.layout.simple_spinner_item, + new ArrayAdapter<>(mContext, android.R.layout.simple_spinner_item, android.R.id.text1, list); + adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); + m = view.getClass().getMethod("setAdapter",SpinnerAdapter.class); } else { adapter = - new ArrayAdapter(mContext, android.R.layout.simple_list_item_1, + new ArrayAdapter<>(mContext, android.R.layout.simple_list_item_1, android.R.id.text1, list); + //adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); + m = view.getClass().getMethod("setAdapter", ListAdapter.class); + } + m.invoke(view, adapter); + } catch (Exception e) { + mErrors.add("failed to load list " + e.getMessage()); + } + } + + @RequiresApi(api = Build.VERSION_CODES.N) + public void setListAdapterHtml(View view, JSONArray items) { + List list = new ArrayList(); + try { + for (int i = 0; i < items.length(); i++) { + list.add(items.get(i).toString()); } - adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); - Method m = tryMethod(view, "setAdapter", SpinnerAdapter.class); - if (m == null) { + ArrayAdapter adapter; + Method m; + Spanned[] listHtml = new Spanned[list.size()]; + for (int i=0;i(mContext, android.R.layout.simple_spinner_item, + android.R.id.text1, listHtml); + adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); + m = view.getClass().getMethod("setAdapter",SpinnerAdapter.class); + } else { + adapter = + new ArrayAdapter<>(mContext, android.R.layout.simple_list_item_1, + android.R.id.text1, listHtml); + //adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); m = view.getClass().getMethod("setAdapter", ListAdapter.class); } m.invoke(view, adapter); @@ -1022,6 +1109,53 @@ public class ViewInflater { } } + public void setListAdapter2(View view, JSONArray items, JSONArray intRes) { + try{ + Method m; + if (view instanceof Spinner) { + m = view.getClass().getMethod("setAdapter", SpinnerAdapter.class); + } else { + m = view.getClass().getMethod("setAdapter", ListAdapter.class); + } + List integers = new ArrayList(); + for (int i = 0; i < intRes.length(); i++) { + integers.add(intRes.getInt(i)); + } + int l=intRes.length(); + if (view instanceof Spinner || l==2) { + List list = new ArrayList(); + ArrayAdapter adapter; + for (int i = 0; i < items.length(); i++) + list.add(items.get(i).toString()); + adapter = new ArrayAdapter(mContext, integers.get(0), integers.get(1), list); + if (view instanceof Spinner) { + if (l==3) adapter.setDropDownViewResource(integers.get(2)); + else if (l==2) adapter.setDropDownViewResource(integers.get(0)); + } + m.invoke(view, adapter); + } else if (l==3) { + Map map; + List> list = new ArrayList<>(); + int j,k; + k=items.length(); + for (int i = 0; i < k; i+=2) { + map =new HashMap<>(); + map.put("1",items.get(i).toString()); + j=i+1; + if(j { + Drawable drawable = null; + try { + drawable = Drawable.createFromStream(new URL(source).openStream(), null); + drawable.setBounds(0, 0, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight()); + } catch (IOException e) { + e.printStackTrace(); + } + return drawable; + }; + + public static Spanned textToHtml(String text){ + return Html.fromHtml(text,imageGetter,null); + } +} -- Gitee