├── .github └── FUNDING.yml ├── .gitignore ├── LICENSE ├── README.md ├── build.gradle ├── doc ├── cn │ └── APIs.rst └── en │ └── APIs.rst ├── proguard-rules.pro ├── src └── main │ ├── AndroidManifest.xml │ ├── java │ └── org │ │ └── qpython │ │ └── qsl4a │ │ ├── QPyScriptService.java │ │ ├── QSL4APP.java │ │ ├── QSL4AScript.java │ │ ├── codec │ │ ├── Base64Codec.java │ │ ├── BinaryDecoder.java │ │ ├── BinaryEncoder.java │ │ ├── CharEncoding.java │ │ ├── Decoder.java │ │ ├── DecoderException.java │ │ ├── Encoder.java │ │ ├── EncoderException.java │ │ ├── StreamGobbler.java │ │ └── StringUtils.java │ │ └── qsl4a │ │ ├── Analytics.java │ │ ├── AndroidProxy.java │ │ ├── BaseApplication.java │ │ ├── Constants.java │ │ ├── Exec.java │ │ ├── FeaturedInterpreters.java │ │ ├── FileUtils.java │ │ ├── ForegroundService.java │ │ ├── FutureActivityTaskExecutor.java │ │ ├── IntentBuilders.java │ │ ├── IoUtils.java │ │ ├── LogUtil.java │ │ ├── MainThread.java │ │ ├── NotificationIdFactory.java │ │ ├── Process.java │ │ ├── ScriptLauncher.java │ │ ├── ScriptProcess.java │ │ ├── ScriptStorageAdapter.java │ │ ├── SimpleServer.java │ │ ├── SingleThreadExecutor.java │ │ ├── StringUtils.java │ │ ├── Version.java │ │ ├── activity │ │ └── FutureActivity.java │ │ ├── bluetooth │ │ └── BluetoothDiscoveryHelper.java │ │ ├── event │ │ └── Event.java │ │ ├── exception │ │ └── Sl4aException.java │ │ ├── facade │ │ ├── ActivityResultFacade.java │ │ ├── AndroidFacade.java │ │ ├── ApplicationManagerFacade.java │ │ ├── BatteryManagerFacade.java │ │ ├── BluetoothFacade.java │ │ ├── CameraFacade.java │ │ ├── CommonIntentsFacade.java │ │ ├── ContactsFacade.java │ │ ├── EventFacade.java │ │ ├── EventServer.java │ │ ├── EyesFreeFacade.java │ │ ├── FacadeConfiguration.java │ │ ├── FacadeManager.java │ │ ├── FacadeManagerFactory.java │ │ ├── JpegProvider.java │ │ ├── LocationFacade.java │ │ ├── MediaPlayerFacade.java │ │ ├── MediaRecorderFacade.java │ │ ├── MjpegServer.java │ │ ├── PhoneFacade.java │ │ ├── PreferencesFacade.java │ │ ├── QPyInterfaceFacade.java │ │ ├── SensorManagerFacade.java │ │ ├── SettingsFacade.java │ │ ├── SignalStrengthFacade.java │ │ ├── SmsFacade.java │ │ ├── SpeechRecognitionFacade.java │ │ ├── TextToSpeechFacade.java │ │ ├── ToneGeneratorFacade.java │ │ ├── USBHostSerialFacade.java │ │ ├── WakeLockFacade.java │ │ ├── WebCamFacade.java │ │ ├── WifiFacade.java │ │ └── ui │ │ │ ├── AlertDialogTask.java │ │ │ ├── DatePickerDialogTask.java │ │ │ ├── DialogTask.java │ │ │ ├── FullScreenTask.java │ │ │ ├── NFCBeamTask.java │ │ │ ├── ProgressDialogTask.java │ │ │ ├── SeekBarDialogTask.java │ │ │ ├── TimePickerDialogTask.java │ │ │ ├── UiFacade.java │ │ │ └── ViewInflater.java │ │ ├── future │ │ ├── FutureActivityTask.java │ │ └── FutureResult.java │ │ ├── interpreter │ │ ├── ExternalClassLoader.java │ │ ├── InProcessInterpreter.java │ │ ├── Interpreter.java │ │ ├── InterpreterConfiguration.java │ │ ├── InterpreterConstants.java │ │ ├── InterpreterDescriptor.java │ │ ├── InterpreterProcess.java │ │ ├── InterpreterPropertyNames.java │ │ ├── InterpreterUtils.java │ │ ├── MyInterpreter.java │ │ ├── html │ │ │ ├── HtmlActivityTask.java │ │ │ └── HtmlInterpreter.java │ │ └── shell │ │ │ └── ShellInterpreter.java │ │ ├── jsonrpc │ │ ├── JsonBuilder.java │ │ ├── JsonRpcResult.java │ │ ├── JsonRpcServer.java │ │ ├── RpcReceiver.java │ │ ├── RpcReceiverManager.java │ │ └── RpcReceiverManagerFactory.java │ │ ├── language │ │ ├── BeanShellLanguage.java │ │ ├── HtmlLanguage.java │ │ ├── JavaScriptLanguage.java │ │ ├── Language.java │ │ ├── LuaLanguage.java │ │ ├── PerlLanguage.java │ │ ├── PhpLanguage.java │ │ ├── PythonLanguage.java │ │ ├── RubyLanguage.java │ │ ├── ShellLanguage.java │ │ ├── SleepLanguage.java │ │ ├── SquirrelLanguage.java │ │ ├── SupportedLanguages.java │ │ └── TclLanguage.java │ │ ├── rpc │ │ ├── Converter.java │ │ ├── MethodDescriptor.java │ │ ├── ParameterDescriptor.java │ │ ├── Rpc.java │ │ ├── RpcDefault.java │ │ ├── RpcDeprecated.java │ │ ├── RpcError.java │ │ ├── RpcMinSdk.java │ │ ├── RpcName.java │ │ ├── RpcOptional.java │ │ ├── RpcParameter.java │ │ ├── RpcStartEvent.java │ │ └── RpcStopEvent.java │ │ ├── trigger │ │ ├── EventGenerationControllingObserver.java │ │ ├── ScriptTrigger.java │ │ ├── Trigger.java │ │ └── TriggerRepository.java │ │ └── util │ │ ├── SPFUtils.java │ │ └── VisibleForTesting.java │ └── res │ ├── drawable-xxhdpi │ ├── img_home_logo.png │ └── img_home_logo_3.png │ ├── drawable │ └── toolbar_button_bg.xml │ ├── layout │ ├── activity_run_splash.xml │ └── widget_run_control.xml │ └── values │ ├── colors.xml │ ├── strings.xml │ └── styles.xml └── tests └── AndroidFacade-Clipboard.md /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | patreon: riverfor 4 | custom: ["https://paypal.me/qpyriver"] 5 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | build 4 | __MACOSX 5 | .idea 6 | keystore 7 | .DS_Store 8 | local.properties 9 | *.apk 10 | qbaselib.iml 11 | .* 12 | !/.gitignore 13 | gradle-wrapper.properties 14 | Android.mk 15 | qpython/src/main/jni/python/libpython2.7.b 16 | qpysdk/src/main/obj 17 | values-fr 18 | values-tr 19 | build.gradle.new 20 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # About 2 | QPysl4a is forked from https://www.github.com/damonkohler/sl4a/, and it provides the Android Layer APIs for script engine. 3 | 4 | It is not a standalone project, it will be included by QPython / QPython3 as a submodule. 5 | 6 | # APIs Documentation 7 | If you are looking for a solution to drive Android with Python, then maybe QPysl4a is exactly what you need. With the help of QPysl4a, you could call many Android APIs with Python code. 8 | 9 | Here is what we have provided: [QPysl4a APIs](doc/en/APIs.rst), [Chinese version](doc/cn/APIs.rst) 10 | 11 | 12 | ## More information 13 | Please visit [QPython Project Readme](https://github.com/qpython-android/qpython/blob/master/README.md) 14 | -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.library' 2 | 3 | android { 4 | compileSdkVersion rootProject.ext.compileSdkVersion 5 | buildToolsVersion rootProject.ext.buildToolsVersion 6 | 7 | defaultConfig { 8 | minSdkVersion rootProject.ext.minSdkVersion 9 | targetSdkVersion rootProject.ext.targetSdkVersion 10 | versionCode 1 11 | versionName "1.0" 12 | } 13 | buildTypes { 14 | release { 15 | minifyEnabled false 16 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 17 | } 18 | } 19 | 20 | // defaultPublishConfig 'release' 21 | // publishNonDefault true 22 | // productFlavors { 23 | // library { 24 | // /* This strange empty flavour is actually needed 25 | // for the below to be successful 26 | // debugCompile project(path: ':common', configuration: "libraryDebug") 27 | // releaseCompile project(path: ':common', configuration: "libraryRelease") 28 | // */ 29 | // } 30 | // } 31 | 32 | dataBinding { 33 | enabled = true 34 | } 35 | 36 | lintOptions { 37 | abortOnError false 38 | } 39 | } 40 | 41 | dependencies { 42 | api rootProject.ext.libSupportDesign 43 | //api rootProject.ext.libSupportV7 44 | api rootProject.ext.libGoogleGuava 45 | compile project(path: ':qbaselib') 46 | } 47 | 48 | -------------------------------------------------------------------------------- /proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in C:\Users\Jay\AppData\Local\Android\Sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include mPath and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /src/main/java/org/qpython/qsl4a/QSL4APP.java: -------------------------------------------------------------------------------- 1 | package org.qpython.qsl4a; 2 | 3 | import android.app.Application; 4 | 5 | import com.quseit.base.MyApp; 6 | 7 | import org.qpython.qsl4a.qsl4a.FutureActivityTaskExecutor; 8 | import org.qpython.qsl4a.qsl4a.LogUtil; 9 | import org.qpython.qsl4a.qsl4a.interpreter.InterpreterConfiguration; 10 | import org.qpython.qsl4a.qsl4a.interpreter.InterpreterConstants; 11 | import org.qpython.qsl4a.qsl4a.trigger.TriggerRepository; 12 | 13 | import java.util.Map; 14 | import java.util.concurrent.CountDownLatch; 15 | 16 | 17 | public class QSL4APP extends MyApp implements InterpreterConfiguration.ConfigurationObserver { 18 | 19 | private final CountDownLatch mLatch = new CountDownLatch(1); 20 | private final FutureActivityTaskExecutor mTaskExecutor = new FutureActivityTaskExecutor(this); 21 | 22 | 23 | /*@Override 24 | public Class getHomeActivityClass() { 25 | }*/ 26 | // 27 | // @Override 28 | // public Intent getMainApplicationIntent() { 29 | // return null; 30 | // //return new Intent(Intent.ACTION_VIEW, Uri.parse(getString(R.string.app_url))); 31 | // } 32 | protected InterpreterConfiguration mConfiguration; 33 | Map movieDirs = null; 34 | private volatile boolean receivedConfigUpdate = false; 35 | private TriggerRepository mTriggerRepository; 36 | 37 | protected QSL4APP() { 38 | super(); 39 | } 40 | 41 | 42 | @Override 43 | public void onCreate() { 44 | super.onCreate(); 45 | } 46 | 47 | public void initConfiguration() { 48 | mConfiguration = new InterpreterConfiguration(this); 49 | mConfiguration.registerObserver(this); 50 | mConfiguration.startDiscovering(InterpreterConstants.MIME + QSL4AScript.getFileExtension(this)); 51 | } 52 | 53 | public FutureActivityTaskExecutor getTaskExecutor() { 54 | return mTaskExecutor; 55 | } 56 | 57 | 58 | public InterpreterConfiguration getInterpreterConfiguration() { 59 | return mConfiguration; 60 | } 61 | 62 | public TriggerRepository getTriggerRepository() { 63 | return mTriggerRepository; 64 | } 65 | 66 | 67 | @Override 68 | public void onConfigurationChanged() { 69 | receivedConfigUpdate = true; 70 | mLatch.countDown(); 71 | } 72 | 73 | public boolean readyToStart() { 74 | try { 75 | mLatch.await(); 76 | } catch (InterruptedException e) { 77 | LogUtil.e(e); 78 | } 79 | return receivedConfigUpdate; 80 | } 81 | 82 | 83 | } 84 | -------------------------------------------------------------------------------- /src/main/java/org/qpython/qsl4a/QSL4AScript.java: -------------------------------------------------------------------------------- 1 | package org.qpython.qsl4a; 2 | 3 | import android.content.Context; 4 | 5 | public class QSL4AScript { 6 | 7 | // public final static int ID = R.raw.pymain; 8 | 9 | public static String sFileName; 10 | 11 | public static String getFileName(Context context) { 12 | // if (sFileName == null) { 13 | // Resources resources = context.getResources(); 14 | // String name = resources.getText(ID).toString(); 15 | // sFileName = name.substring(name.lastIndexOf('/') + 1, name.length()); 16 | // } 17 | sFileName = "main.py"; 18 | return sFileName; 19 | } 20 | 21 | public static String getFileExtension(Context context) { 22 | if (sFileName == null) { 23 | getFileName(context); 24 | } 25 | int dotIndex = sFileName.lastIndexOf('.'); 26 | if (dotIndex == -1) { 27 | return null; 28 | } 29 | return sFileName.substring(dotIndex); 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/org/qpython/qsl4a/codec/BinaryDecoder.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package org.qpython.qsl4a.codec; 19 | 20 | /** 21 | * Defines common decoding methods for byte array decoders. 22 | * 23 | * @author Apache Software Foundation 24 | * @version $Id: BinaryDecoder.java 651573 2008-04-25 11:11:21Z niallp $ 25 | */ 26 | public interface BinaryDecoder extends Decoder { 27 | 28 | /** 29 | * Decodes a byte array and returns the results as a byte array. 30 | * 31 | * @param pArray A byte array which has been encoded with the 32 | * appropriate encoder 33 | * 34 | * @return a byte array that contains decoded content 35 | * 36 | * @throws DecoderException A decoder exception is thrown 37 | * if a Decoder encounters a failure condition during 38 | * the decode process. 39 | */ 40 | byte[] decode(byte[] pArray) throws DecoderException; 41 | } 42 | 43 | -------------------------------------------------------------------------------- /src/main/java/org/qpython/qsl4a/codec/BinaryEncoder.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package org.qpython.qsl4a.codec; 19 | 20 | /** 21 | * Defines common encoding methods for byte array encoders. 22 | * 23 | * @author Apache Software Foundation 24 | * @version $Id: BinaryEncoder.java 651573 2008-04-25 11:11:21Z niallp $ 25 | */ 26 | public interface BinaryEncoder extends Encoder { 27 | 28 | /** 29 | * Encodes a byte array and return the encoded data 30 | * as a byte array. 31 | * 32 | * @param pArray Data to be encoded 33 | * 34 | * @return A byte array containing the encoded data 35 | * 36 | * @throws EncoderException thrown if the Encoder 37 | * encounters a failure condition during the 38 | * encoding process. 39 | */ 40 | byte[] encode(byte[] pArray) throws EncoderException; 41 | } 42 | 43 | -------------------------------------------------------------------------------- /src/main/java/org/qpython/qsl4a/codec/Decoder.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package org.qpython.qsl4a.codec; 19 | 20 | /** 21 | *

Provides the highest level of abstraction for Decoders. 22 | * This is the sister interface of {@link Encoder}. All 23 | * Decoders implement this common generic interface.

24 | * 25 | *

Allows a user to pass a generic Object to any Decoder 26 | * implementation in the codec package.

27 | * 28 | *

One of the two interfaces at the center of the codec package.

29 | * 30 | * @author Apache Software Foundation 31 | * @version $Id: Decoder.java 797690 2009-07-24 23:28:35Z ggregory $ 32 | */ 33 | public interface Decoder { 34 | 35 | /** 36 | * Decodes an "encoded" Object and returns a "decoded" 37 | * Object. Note that the implementation of this 38 | * interface will try to cast the Object parameter 39 | * to the specific type expected by a particular Decoder 40 | * implementation. If a {@link ClassCastException} occurs 41 | * this decode method will throw a DecoderException. 42 | * 43 | * @param pObject an object to "decode" 44 | * 45 | * @return a 'decoded" object 46 | * 47 | * @throws DecoderException a decoder exception can 48 | * be thrown for any number of reasons. Some good 49 | * candidates are that the parameter passed to this 50 | * method is null, a param cannot be cast to the 51 | * appropriate type for a specific encoder. 52 | */ 53 | Object decode(Object pObject) throws DecoderException; 54 | } 55 | 56 | -------------------------------------------------------------------------------- /src/main/java/org/qpython/qsl4a/codec/DecoderException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package org.qpython.qsl4a.codec; 19 | 20 | /** 21 | * Thrown when a Decoder has encountered a failure condition during a decode. 22 | * 23 | * @author Apache Software Foundation 24 | * @version $Id: DecoderException.java 797804 2009-07-25 17:27:04Z ggregory $ 25 | */ 26 | public class DecoderException extends Exception { 27 | 28 | /** 29 | * Declares the Serial Version Uid. 30 | * 31 | * @see Always Declare Serial Version Uid 32 | */ 33 | private static final long serialVersionUID = 1L; 34 | 35 | /** 36 | * Constructs a new exception with null as its detail message. The cause is not initialized, and may 37 | * subsequently be initialized by a call to {@link #initCause}. 38 | * 39 | * @since 1.4 40 | */ 41 | public DecoderException() { 42 | super(); 43 | } 44 | 45 | /** 46 | * Constructs a new exception with the specified detail message. The cause is not initialized, and may subsequently 47 | * be initialized by a call to {@link #initCause}. 48 | * 49 | * @param message 50 | * The detail message which is saved for later retrieval by the {@link #getMessage()} method. 51 | */ 52 | public DecoderException(String message) { 53 | super(message); 54 | } 55 | 56 | /** 57 | * Constructsa new exception with the specified detail message and cause. 58 | * 59 | *

60 | * Note that the detail message associated with cause is not automatically incorporated into this 61 | * exception's detail message. 62 | *

63 | * 64 | * @param message 65 | * The detail message which is saved for later retrieval by the {@link #getMessage()} method. 66 | * @param cause 67 | * The cause which is saved for later retrieval by the {@link #getCause()} method. A null 68 | * value is permitted, and indicates that the cause is nonexistent or unknown. 69 | * @since 1.4 70 | */ 71 | public DecoderException(String message, Throwable cause) { 72 | super(message, cause); 73 | } 74 | 75 | /** 76 | * Constructs a new exception with the specified cause and a detail message of (cause==null ? 77 | * null : cause.toString()) (which typically contains the class and detail message of cause). 78 | * This constructor is useful for exceptions that are little more than wrappers for other throwables. 79 | * 80 | * @param cause 81 | * The cause which is saved for later retrieval by the {@link #getCause()} method. A null 82 | * value is permitted, and indicates that the cause is nonexistent or unknown. 83 | * @since 1.4 84 | */ 85 | public DecoderException(Throwable cause) { 86 | super(cause); 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /src/main/java/org/qpython/qsl4a/codec/Encoder.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package org.qpython.qsl4a.codec; 19 | 20 | /** 21 | *

Provides the highest level of abstraction for Encoders. 22 | * This is the sister interface of {@link Decoder}. Every implementation of 23 | * Encoder provides this common generic interface whic allows a user to pass a 24 | * generic Object to any Encoder implementation in the codec package.

25 | * 26 | * @author Apache Software Foundation 27 | * @version $Id: Encoder.java 634915 2008-03-08 09:30:25Z bayard $ 28 | */ 29 | public interface Encoder { 30 | 31 | /** 32 | * Encodes an "Object" and returns the encoded content 33 | * as an Object. The Objects here may just be byte[] 34 | * or Strings depending on the implementation used. 35 | * 36 | * @param pObject An object ot encode 37 | * 38 | * @return An "encoded" Object 39 | * 40 | * @throws EncoderException an encoder exception is 41 | * thrown if the encoder experiences a failure 42 | * condition during the encoding process. 43 | */ 44 | Object encode(Object pObject) throws EncoderException; 45 | } 46 | 47 | -------------------------------------------------------------------------------- /src/main/java/org/qpython/qsl4a/codec/EncoderException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package org.qpython.qsl4a.codec; 19 | 20 | /** 21 | * Thrown when there is a failure condition during the encoding process. This exception is thrown when an Encoder 22 | * encounters a encoding specific exception such as invalid data, inability to calculate a checksum, characters outside 23 | * of the expected range. 24 | * 25 | * @author Apache Software Foundation 26 | * @version $Id: EncoderException.java 797804 2009-07-25 17:27:04Z ggregory $ 27 | */ 28 | public class EncoderException extends Exception { 29 | 30 | /** 31 | * Declares the Serial Version Uid. 32 | * 33 | * @see Always Declare Serial Version Uid 34 | */ 35 | private static final long serialVersionUID = 1L; 36 | 37 | /** 38 | * Constructs a new exception with null as its detail message. The cause is not initialized, and may 39 | * subsequently be initialized by a call to {@link #initCause}. 40 | * 41 | * @since 1.4 42 | */ 43 | public EncoderException() { 44 | super(); 45 | } 46 | 47 | /** 48 | * Constructs a new exception with the specified detail message. The cause is not initialized, and may subsequently 49 | * be initialized by a call to {@link #initCause}. 50 | * 51 | * @param message 52 | * a useful message relating to the encoder specific error. 53 | */ 54 | public EncoderException(String message) { 55 | super(message); 56 | } 57 | 58 | /** 59 | * Constructs a new exception with the specified detail message and cause. 60 | * 61 | *

62 | * Note that the detail message associated with cause is not automatically incorporated into this 63 | * exception's detail message. 64 | *

65 | * 66 | * @param message 67 | * The detail message which is saved for later retrieval by the {@link #getMessage()} method. 68 | * @param cause 69 | * The cause which is saved for later retrieval by the {@link #getCause()} method. A null 70 | * value is permitted, and indicates that the cause is nonexistent or unknown. 71 | * @since 1.4 72 | */ 73 | public EncoderException(String message, Throwable cause) { 74 | super(message, cause); 75 | } 76 | 77 | /** 78 | * Constructs a new exception with the specified cause and a detail message of (cause==null ? 79 | * null : cause.toString()) (which typically contains the class and detail message of cause). 80 | * This constructor is useful for exceptions that are little more than wrappers for other throwables. 81 | * 82 | * @param cause 83 | * The cause which is saved for later retrieval by the {@link #getCause()} method. A null 84 | * value is permitted, and indicates that the cause is nonexistent or unknown. 85 | * @since 1.4 86 | */ 87 | public EncoderException(Throwable cause) { 88 | super(cause); 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /src/main/java/org/qpython/qsl4a/qsl4a/Analytics.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2009 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 | * use this file except in compliance with the License. You may obtain a copy of 6 | * the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations under 14 | * the License. 15 | */ 16 | 17 | package org.qpython.qsl4a.qsl4a; 18 | 19 | import android.app.Activity; 20 | import android.content.Context; 21 | import android.content.SharedPreferences; 22 | import android.preference.PreferenceManager; 23 | 24 | 25 | import java.util.concurrent.ExecutorService; 26 | import java.util.concurrent.Executors; 27 | 28 | public class Analytics { 29 | private static SharedPreferences mPrefs; 30 | private static String mSl4aVersion; 31 | private static ExecutorService mWorkPool; 32 | private static volatile boolean mStarted = false; 33 | 34 | private Analytics() { 35 | // Utility class. 36 | } 37 | 38 | // TODO(Alexey): Add Javadoc. "Also, it would be cool to wrap up the Analytics API into a facade." 39 | @SuppressWarnings("deprecation") 40 | public static synchronized void start(Context context, String analyticsAccountId) { 41 | if (context == null || analyticsAccountId == null) { 42 | return; 43 | } 44 | mSl4aVersion = Version.getVersion(context); 45 | mPrefs = PreferenceManager.getDefaultSharedPreferences(context); 46 | mWorkPool = Executors.newSingleThreadExecutor(); 47 | mStarted = true; 48 | } 49 | 50 | private static class PageNameBuilder { 51 | private final StringBuilder mmName = new StringBuilder(); 52 | 53 | void add(String pathPart) { 54 | mmName.append("/"); 55 | mmName.append(pathPart); 56 | } 57 | 58 | String build() { 59 | return mmName.toString(); 60 | } 61 | } 62 | 63 | public static void track(final String... nameParts) { 64 | if (mStarted && mPrefs.getBoolean("usagetracking", false)) { 65 | mWorkPool.submit(new Runnable() { 66 | public void run() { 67 | PageNameBuilder builder = new PageNameBuilder(); 68 | builder.add(mSl4aVersion); 69 | for (String part : nameParts) { 70 | builder.add(part); 71 | } 72 | String name = builder.build(); 73 | } 74 | }); 75 | } 76 | } 77 | 78 | public static void trackActivity(Activity activity) { 79 | String name = activity.getClass().getSimpleName(); 80 | track(name); 81 | } 82 | 83 | @SuppressWarnings("deprecation") 84 | public static synchronized void stop() { 85 | if (mStarted) { 86 | mStarted = false; 87 | mWorkPool.shutdownNow(); 88 | } 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /src/main/java/org/qpython/qsl4a/qsl4a/AndroidProxy.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2009 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 | * use this file except in compliance with the License. You may obtain a copy of 6 | * the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations under 14 | * the License. 15 | */ 16 | 17 | package org.qpython.qsl4a.qsl4a; 18 | 19 | import android.app.Service; 20 | import android.content.Intent; 21 | 22 | import org.qpython.qsl4a.qsl4a.facade.FacadeConfiguration; 23 | import org.qpython.qsl4a.qsl4a.facade.FacadeManagerFactory; 24 | import org.qpython.qsl4a.qsl4a.jsonrpc.JsonRpcServer; 25 | import org.qpython.qsl4a.qsl4a.jsonrpc.RpcReceiverManagerFactory; 26 | 27 | import java.net.InetSocketAddress; 28 | import java.util.UUID; 29 | 30 | public class AndroidProxy { 31 | 32 | private InetSocketAddress mAddress; 33 | private final JsonRpcServer mJsonRpcServer; 34 | private final UUID mSecret; 35 | private final RpcReceiverManagerFactory mFacadeManagerFactory; 36 | 37 | /** 38 | * 39 | * @param service 40 | * Android service (required to build facades). 41 | * @param intent 42 | * the intent that launched the proxy/script. 43 | * @param requiresHandshake 44 | * indicates whether RPC security protocol should be enabled. 45 | */ 46 | public AndroidProxy(Service service, Intent intent, boolean requiresHandshake) { 47 | if (requiresHandshake) { 48 | mSecret = UUID.randomUUID(); 49 | } else { 50 | mSecret = null; 51 | } 52 | mFacadeManagerFactory = 53 | new FacadeManagerFactory(FacadeConfiguration.getSdkLevel(), service, intent, 54 | FacadeConfiguration.getFacadeClasses()); 55 | mJsonRpcServer = new JsonRpcServer(mFacadeManagerFactory, getSecret()); 56 | } 57 | 58 | public InetSocketAddress getAddress() { 59 | return mAddress; 60 | } 61 | 62 | public InetSocketAddress startLocal() { 63 | return startLocal(0); 64 | } 65 | 66 | public InetSocketAddress startLocal(int port) { 67 | mAddress = mJsonRpcServer.startLocal(port); 68 | return mAddress; 69 | } 70 | 71 | public InetSocketAddress startPublic() { 72 | return startPublic(0); 73 | } 74 | 75 | public InetSocketAddress startPublic(int port) { 76 | mAddress = mJsonRpcServer.startPublic(port); 77 | return mAddress; 78 | } 79 | 80 | public void shutdown() { 81 | if (mJsonRpcServer!=null) { 82 | mJsonRpcServer.shutdown(); 83 | } 84 | } 85 | 86 | public String getSecret() { 87 | if (mSecret == null) { 88 | return null; 89 | } 90 | return mSecret.toString(); 91 | } 92 | 93 | public RpcReceiverManagerFactory getRpcReceiverManagerFactory() { 94 | return mFacadeManagerFactory; 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /src/main/java/org/qpython/qsl4a/qsl4a/BaseApplication.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2009 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 | * use this file except in compliance with the License. You may obtain a copy of 6 | * the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations under 14 | * the License. 15 | */ 16 | 17 | package org.qpython.qsl4a.qsl4a; 18 | 19 | import android.app.Application; 20 | 21 | import org.qpython.qsl4a.qsl4a.interpreter.InterpreterConfiguration; 22 | import org.qpython.qsl4a.qsl4a.trigger.TriggerRepository; 23 | 24 | public class BaseApplication extends Application { 25 | 26 | private final FutureActivityTaskExecutor mTaskExecutor = new FutureActivityTaskExecutor(this); 27 | private TriggerRepository mTriggerRepository; 28 | 29 | protected InterpreterConfiguration mConfiguration; 30 | 31 | public FutureActivityTaskExecutor getTaskExecutor() { 32 | return mTaskExecutor; 33 | } 34 | 35 | @Override 36 | public void onCreate() { 37 | super.onCreate(); 38 | mConfiguration = new InterpreterConfiguration(this); 39 | mConfiguration.startDiscovering(); 40 | mTriggerRepository = new TriggerRepository(this); 41 | } 42 | 43 | public InterpreterConfiguration getInterpreterConfiguration() { 44 | return mConfiguration; 45 | } 46 | 47 | public TriggerRepository getTriggerRepository() { 48 | return mTriggerRepository; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/main/java/org/qpython/qsl4a/qsl4a/Exec.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2007 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.qpython.qsl4a.qsl4a; 18 | 19 | import java.io.FileDescriptor; 20 | 21 | /** 22 | * Tools for executing commands. 23 | */ 24 | public class Exec { 25 | /** 26 | * @param cmd 27 | * The command to execute 28 | * @param arg0 29 | * The first argument to the command, may be null 30 | * @param arg1 31 | * the second argument to the command, may be null 32 | * @return the file descriptor of the started process. 33 | * 34 | */ 35 | public static FileDescriptor createSubprocess(String command, String[] arguments, 36 | String[] environmentVariables, String workingDirectory) { 37 | return createSubprocess(command, arguments, environmentVariables, workingDirectory, null); 38 | } 39 | 40 | /** 41 | * @param cmd 42 | * The command to execute 43 | * @param arguments 44 | * Array of arguments, may be null 45 | * @param environmentVariables 46 | * Array of environment variables, may be null 47 | * @param processId 48 | * A one-element array to which the process ID of the started process will be written. 49 | * @return the file descriptor of the opened process's psuedo-terminal. 50 | * 51 | */ 52 | public static native FileDescriptor createSubprocess(String command, String[] arguments, 53 | String[] environmentVariables, String workingDirectory, int[] processId); 54 | 55 | public static native void setPtyWindowSize(FileDescriptor fd, int row, int col, int xpixel, 56 | int ypixel); 57 | 58 | /** 59 | * Causes the calling thread to wait for the process associated with the receiver to finish 60 | * executing. 61 | * 62 | * @return The exit value of the Process being waited on 63 | * 64 | */ 65 | public static native int waitFor(int processId); 66 | 67 | static { 68 | System.loadLibrary("com_googlecode_android_scripting_Exec"); 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /src/main/java/org/qpython/qsl4a/qsl4a/FeaturedInterpreters.java: -------------------------------------------------------------------------------- 1 | // Copyright 2010 Google Inc. All Rights Reserved. 2 | 3 | package org.qpython.qsl4a.qsl4a; 4 | 5 | import android.content.Context; 6 | 7 | import java.net.MalformedURLException; 8 | import java.net.URL; 9 | import java.util.ArrayList; 10 | import java.util.Collections; 11 | import java.util.HashMap; 12 | import java.util.List; 13 | import java.util.Map; 14 | 15 | public class FeaturedInterpreters { 16 | private static final Map mNameMap = 17 | new HashMap(); 18 | private static final Map mExtensionMap = 19 | new HashMap(); 20 | 21 | static { 22 | try { 23 | FeaturedInterpreter interpreters[] = 24 | { 25 | new FeaturedInterpreter("BeanShell 2.0b4", ".bsh", 26 | "http://android-scripting.googlecode.com/files/beanshell_for_android_r2.apk"), 27 | new FeaturedInterpreter("JRuby", ".rb", 28 | "https://github.com/downloads/ruboto/sl4a_jruby_interpreter/JRubyForAndroid_r2dev.apk"), 29 | new FeaturedInterpreter("Lua 5.1.4", ".lua", 30 | "http://android-scripting.googlecode.com/files/lua_for_android_r1.apk"), 31 | new FeaturedInterpreter("Perl 5.10.1", ".pl", 32 | "http://android-scripting.googlecode.com/files/perl_for_android_r1.apk"), 33 | new FeaturedInterpreter("Python 2.6.2", ".py", 34 | "http://python-for-android.googlecode.com/files/PythonForAndroid_r5.apk"), 35 | new FeaturedInterpreter("Rhino 1.7R2", ".js", 36 | "http://android-scripting.googlecode.com/files/rhino_for_android_r2.apk"), 37 | new FeaturedInterpreter("PHP 5.3.3", ".php", 38 | "http://php-for-android.googlecode.com/files/phpforandroid_r1.apk") }; 39 | for (FeaturedInterpreter interpreter : interpreters) { 40 | mNameMap.put(interpreter.mmName, interpreter); 41 | mExtensionMap.put(interpreter.mmExtension, interpreter); 42 | } 43 | } catch (MalformedURLException e) { 44 | LogUtil.e(e); 45 | } 46 | } 47 | 48 | public static List getList() { 49 | ArrayList list = new ArrayList(mNameMap.keySet()); 50 | Collections.sort(list); 51 | return list; 52 | } 53 | 54 | public static URL getUrlForName(String name) { 55 | if (!mNameMap.containsKey(name)) { 56 | return null; 57 | } 58 | return mNameMap.get(name).mmUrl; 59 | } 60 | 61 | public static String getInterpreterNameForScript(String fileName) { 62 | String extension = getExtension(fileName); 63 | if (extension == null || !mExtensionMap.containsKey(extension)) { 64 | return null; 65 | } 66 | return mExtensionMap.get(extension).mmName; 67 | } 68 | 69 | public static boolean isSupported(String fileName) { 70 | String extension = getExtension(fileName); 71 | return (extension != null) && (mExtensionMap.containsKey(extension)); 72 | } 73 | 74 | public static int getInterpreterIcon(Context context, String key) { 75 | String packageName = context.getPackageName(); 76 | String name = "_icon"; 77 | if (key.contains(".")) { 78 | name = key.substring(key.lastIndexOf('.') + 1) + name; 79 | } else { 80 | name = key + name; 81 | } 82 | return context.getResources().getIdentifier(name, "drawable", packageName); 83 | } 84 | 85 | private static String getExtension(String fileName) { 86 | int dotIndex = fileName.lastIndexOf('.'); 87 | if (dotIndex == -1) { 88 | return null; 89 | } 90 | return fileName.substring(dotIndex); 91 | } 92 | 93 | private static class FeaturedInterpreter { 94 | private final String mmName; 95 | private final String mmExtension; 96 | private final URL mmUrl; 97 | 98 | private FeaturedInterpreter(String name, String extension, String url) 99 | throws MalformedURLException { 100 | mmName = name; 101 | mmExtension = extension; 102 | mmUrl = new URL(url); 103 | } 104 | } 105 | 106 | } 107 | -------------------------------------------------------------------------------- /src/main/java/org/qpython/qsl4a/qsl4a/ForegroundService.java: -------------------------------------------------------------------------------- 1 | package org.qpython.qsl4a.qsl4a; 2 | 3 | import android.app.Notification; 4 | import android.app.NotificationManager; 5 | import android.app.Service; 6 | 7 | import java.lang.reflect.Method; 8 | 9 | public abstract class ForegroundService extends Service { 10 | private static final Class[] mStartForegroundSignature = 11 | new Class[] { int.class, Notification.class }; 12 | private static final Class[] mStopForegroundSignature = new Class[] { boolean.class }; 13 | 14 | private final int mNotificationId; 15 | 16 | private NotificationManager mNotificationManager; 17 | private Method mStartForeground; 18 | private Method mStopForeground; 19 | private Object[] mStartForegroundArgs = new Object[2]; 20 | private Object[] mStopForegroundArgs = new Object[1]; 21 | 22 | public ForegroundService(int id) { 23 | mNotificationId = id; 24 | } 25 | 26 | protected abstract Notification createNotification(); 27 | 28 | /** 29 | * This is a wrapper around the new startForeground method, using the older APIs if it is not 30 | * available. 31 | */ 32 | private void startForegroundCompat(Notification notification) { 33 | // If we have the new startForeground API, then use it. 34 | if (mStartForeground != null) { 35 | mStartForegroundArgs[0] = Integer.valueOf(mNotificationId); 36 | mStartForegroundArgs[1] = notification; 37 | try { 38 | mStartForeground.invoke(this, mStartForegroundArgs); 39 | } catch (Exception e) { 40 | LogUtil.e(e); 41 | } 42 | return; 43 | } 44 | 45 | // Fall back on the old API. 46 | startForegroundCompat(notification); 47 | if (notification != null) { 48 | mNotificationManager.notify(mNotificationId, notification); 49 | } 50 | } 51 | 52 | 53 | 54 | /** 55 | * This is a wrapper around the new stopForeground method, using the older APIs if it is not 56 | * available. 57 | */ 58 | private void stopForegroundCompat() { 59 | // If we have the new stopForeground API, then use it. 60 | if (mStopForeground != null) { 61 | mStopForegroundArgs[0] = Boolean.TRUE; 62 | try { 63 | mStopForeground.invoke(this, mStopForegroundArgs); 64 | } catch (Exception e) { 65 | LogUtil.e(e); 66 | } 67 | return; 68 | } 69 | 70 | // Fall back on the old API. Note to cancel BEFORE changing the 71 | // foreground state, since we could be killed at that point. 72 | mNotificationManager.cancel(mNotificationId); 73 | stopForeground(true); 74 | 75 | } 76 | 77 | @Override 78 | public void onCreate() { 79 | mNotificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE); 80 | try { 81 | mStartForeground = getClass().getMethod("startForeground", mStartForegroundSignature); 82 | mStopForeground = getClass().getMethod("stopForeground", mStopForegroundSignature); 83 | } catch (NoSuchMethodException e) { 84 | // Running on an older platform. 85 | mStartForeground = mStopForeground = null; 86 | } 87 | startForegroundCompat(createNotification()); 88 | } 89 | 90 | @Override 91 | public void onDestroy() { 92 | // Make sure our notification is gone. 93 | stopForegroundCompat(); 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /src/main/java/org/qpython/qsl4a/qsl4a/FutureActivityTaskExecutor.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2010 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 | * use this file except in compliance with the License. You may obtain a copy of 6 | * the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations under 14 | * the License. 15 | */ 16 | 17 | package org.qpython.qsl4a.qsl4a; 18 | 19 | import android.content.Context; 20 | import android.content.Intent; 21 | 22 | 23 | import org.qpython.qsl4a.qsl4a.activity.FutureActivity; 24 | import org.qpython.qsl4a.qsl4a.future.FutureActivityTask; 25 | 26 | import java.util.Map; 27 | import java.util.concurrent.ConcurrentHashMap; 28 | import java.util.concurrent.atomic.AtomicInteger; 29 | 30 | public class FutureActivityTaskExecutor { 31 | 32 | private final Context mContext; 33 | private final Map> mTaskMap = 34 | new ConcurrentHashMap>(); 35 | private final AtomicInteger mIdGenerator = new AtomicInteger(0); 36 | 37 | public FutureActivityTaskExecutor(Context context) { 38 | mContext = context; 39 | } 40 | 41 | public void execute(FutureActivityTask task) { 42 | int id = mIdGenerator.incrementAndGet(); 43 | mTaskMap.put(id, task); 44 | launchHelper(id); 45 | } 46 | 47 | public FutureActivityTask getTask(int id) { 48 | return mTaskMap.remove(id); 49 | } 50 | 51 | private void launchHelper(int id) { 52 | Intent helper = new Intent(mContext, FutureActivity.class); 53 | helper.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_MULTIPLE_TASK); 54 | helper.putExtra(Constants.EXTRA_TASK_ID, id); 55 | mContext.startActivity(helper); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/main/java/org/qpython/qsl4a/qsl4a/IoUtils.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2010 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 | * use this file except in compliance with the License. You may obtain a copy of 6 | * the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations under 14 | * the License. 15 | */ 16 | 17 | package org.qpython.qsl4a.qsl4a; 18 | 19 | import java.io.BufferedInputStream; 20 | import java.io.BufferedOutputStream; 21 | import java.io.IOException; 22 | import java.io.InputStream; 23 | import java.io.OutputStream; 24 | 25 | public class IoUtils { 26 | private static final int BUFFER_SIZE = 1024 * 8; 27 | 28 | private IoUtils() { 29 | // Utility class. 30 | } 31 | 32 | public static int copy(InputStream input, OutputStream output) throws Exception, IOException { 33 | byte[] buffer = new byte[BUFFER_SIZE]; 34 | 35 | BufferedInputStream in = new BufferedInputStream(input, BUFFER_SIZE); 36 | BufferedOutputStream out = new BufferedOutputStream(output, BUFFER_SIZE); 37 | int count = 0, n = 0; 38 | try { 39 | while ((n = in.read(buffer, 0, BUFFER_SIZE)) != -1) { 40 | out.write(buffer, 0, n); 41 | count += n; 42 | } 43 | out.flush(); 44 | } finally { 45 | try { 46 | out.close(); 47 | } catch (IOException e) { 48 | LogUtil.e(e.getMessage(), e); 49 | } 50 | try { 51 | in.close(); 52 | } catch (IOException e) { 53 | LogUtil.e(e.getMessage(), e); 54 | } 55 | } 56 | return count; 57 | } 58 | 59 | } 60 | -------------------------------------------------------------------------------- /src/main/java/org/qpython/qsl4a/qsl4a/MainThread.java: -------------------------------------------------------------------------------- 1 | // Copyright 2010 Google Inc. All Rights Reserved. 2 | 3 | package org.qpython.qsl4a.qsl4a; 4 | 5 | import android.content.Context; 6 | import android.os.Handler; 7 | 8 | 9 | import org.qpython.qsl4a.qsl4a.future.FutureResult; 10 | 11 | import java.util.concurrent.Callable; 12 | 13 | public class MainThread { 14 | 15 | private MainThread() { 16 | // Utility class. 17 | } 18 | 19 | /** 20 | * Executed in the main thread, returns the result of an execution. Anything that runs here should 21 | * finish quickly to avoid hanging the UI thread. 22 | */ 23 | public static T run(Context context, final Callable task) { 24 | final FutureResult result = new FutureResult(); 25 | Handler handler = new Handler(context.getMainLooper()); 26 | handler.post(new Runnable() { 27 | @Override 28 | public void run() { 29 | try { 30 | result.set(task.call()); 31 | } catch (Exception e) { 32 | LogUtil.e(e); 33 | result.set(null); 34 | } 35 | } 36 | }); 37 | try { 38 | return result.get(); 39 | } catch (InterruptedException e) { 40 | LogUtil.e(e); 41 | } 42 | return null; 43 | } 44 | 45 | public static void run(Context context, final Runnable task) { 46 | Handler handler = new Handler(context.getMainLooper()); 47 | handler.post(new Runnable() { 48 | @Override 49 | public void run() { 50 | task.run(); 51 | } 52 | }); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/main/java/org/qpython/qsl4a/qsl4a/NotificationIdFactory.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2010 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 | * use this file except in compliance with the License. You may obtain a copy of 6 | * the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations under 14 | * the License. 15 | */ 16 | 17 | package org.qpython.qsl4a.qsl4a; 18 | 19 | import java.util.concurrent.atomic.AtomicInteger; 20 | 21 | /** 22 | * Creates unique ids to identify the notifications created by the android scripting service and the 23 | * trigger service. 24 | * 25 | * @author Felix Arends (felix.arends@gmail.com) 26 | * 27 | */ 28 | public final class NotificationIdFactory { 29 | private static final AtomicInteger mNextId = new AtomicInteger(0); 30 | 31 | public static int create() { 32 | return mNextId.incrementAndGet(); 33 | } 34 | 35 | private NotificationIdFactory() { 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/main/java/org/qpython/qsl4a/qsl4a/ScriptLauncher.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2009 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 | * use this file except in compliance with the License. You may obtain a copy of 6 | * the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations under 14 | * the License. 15 | */ 16 | 17 | package org.qpython.qsl4a.qsl4a; 18 | 19 | import android.app.Service; 20 | import android.content.Context; 21 | import android.content.Intent; 22 | 23 | 24 | import java.io.File; 25 | 26 | import org.qpython.qsl4a.QSL4APP; 27 | import org.qpython.qsl4a.qsl4a.facade.FacadeConfiguration; 28 | import org.qpython.qsl4a.qsl4a.facade.FacadeManager; 29 | import org.qpython.qsl4a.qsl4a.interpreter.Interpreter; 30 | import org.qpython.qsl4a.qsl4a.interpreter.InterpreterConfiguration; 31 | import org.qpython.qsl4a.qsl4a.interpreter.InterpreterProcess; 32 | import org.qpython.qsl4a.qsl4a.interpreter.html.HtmlActivityTask; 33 | import org.qpython.qsl4a.qsl4a.interpreter.html.HtmlInterpreter; 34 | 35 | public class ScriptLauncher { 36 | 37 | private ScriptLauncher() { 38 | // Utility class. 39 | } 40 | 41 | public static HtmlActivityTask launchHtmlScript(File script, Service service, Intent intent, 42 | InterpreterConfiguration config) { 43 | if (!script.exists()) { 44 | throw new RuntimeException("No such script to launch."); 45 | } 46 | HtmlInterpreter interpreter = 47 | (HtmlInterpreter) config.getInterpreterByName(HtmlInterpreter.HTML); 48 | if (interpreter == null) { 49 | throw new RuntimeException("HtmlInterpreter is not available."); 50 | } 51 | final FacadeManager manager = 52 | new FacadeManager(FacadeConfiguration.getSdkLevel(), service, intent, 53 | FacadeConfiguration.getFacadeClasses()); 54 | FutureActivityTaskExecutor executor = 55 | ((QSL4APP) service.getApplication()).getTaskExecutor(); 56 | final HtmlActivityTask task = 57 | new HtmlActivityTask(manager, interpreter.getAndroidJsSource(), 58 | interpreter.getJsonSource(),interpreter.getTemplateSource(), script.getAbsolutePath(), true); 59 | executor.execute(task); 60 | return task; 61 | } 62 | 63 | public static InterpreterProcess launchInterpreter(Context context, final AndroidProxy proxy, Intent intent, 64 | InterpreterConfiguration config, Runnable shutdownHook) { 65 | Interpreter interpreter; 66 | String interpreterName; 67 | interpreterName = intent.getStringExtra(Constants.EXTRA_INTERPRETER_NAME); 68 | interpreter = config.getInterpreterByName(interpreterName); 69 | InterpreterProcess process = new InterpreterProcess(interpreter, proxy); 70 | if (shutdownHook == null) { 71 | process.start(context,new Runnable() { 72 | @Override 73 | public void run() { 74 | proxy.shutdown(); 75 | } 76 | }); 77 | } else { 78 | process.start(context,shutdownHook); 79 | } 80 | return process; 81 | } 82 | 83 | public static ScriptProcess launchScript(Context context,File script, InterpreterConfiguration configuration, 84 | final AndroidProxy proxy, Runnable shutdownHook) { 85 | if (!script.exists()) { 86 | throw new RuntimeException("No such script to launch."); 87 | } 88 | ScriptProcess process = new ScriptProcess(script, configuration, proxy); 89 | if (shutdownHook == null) { 90 | process.start(context,new Runnable() { 91 | @Override 92 | public void run() { 93 | proxy.shutdown(); 94 | } 95 | }); 96 | } else { 97 | process.start(context,shutdownHook); 98 | } 99 | return process; 100 | } 101 | } -------------------------------------------------------------------------------- /src/main/java/org/qpython/qsl4a/qsl4a/ScriptProcess.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2010 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 | * use this file except in compliance with the License. You may obtain a copy of 6 | * the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations under 14 | * the License. 15 | */ 16 | 17 | package org.qpython.qsl4a.qsl4a; 18 | 19 | import org.qpython.qsl4a.qsl4a.interpreter.Interpreter; 20 | import org.qpython.qsl4a.qsl4a.interpreter.InterpreterConfiguration; 21 | import org.qpython.qsl4a.qsl4a.interpreter.InterpreterProcess; 22 | 23 | import java.io.File; 24 | 25 | public class ScriptProcess extends InterpreterProcess { 26 | 27 | private final File mScript; 28 | 29 | public ScriptProcess(File script, InterpreterConfiguration configuration, AndroidProxy proxy) { 30 | super(configuration.getInterpreterForScript(script.getName()), proxy); 31 | mScript = script; 32 | String scriptName = script.getName(); 33 | setName(scriptName); 34 | Interpreter interpreter = configuration.getInterpreterForScript(scriptName); 35 | setCommand(String.format(interpreter.getScriptCommand(), script.getAbsolutePath())); 36 | } 37 | 38 | public String getPath() { 39 | return mScript.getPath(); 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /src/main/java/org/qpython/qsl4a/qsl4a/ScriptStorageAdapter.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2009 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 | * use this file except in compliance with the License. You may obtain a copy of 6 | * the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations under 14 | * the License. 15 | */ 16 | 17 | package org.qpython.qsl4a.qsl4a; 18 | 19 | import android.content.Context; 20 | 21 | import com.quseit.util.FileUtils; 22 | 23 | import org.qpython.qsl4a.qsl4a.interpreter.Interpreter; 24 | import org.qpython.qsl4a.qsl4a.interpreter.InterpreterConfiguration; 25 | import org.qpython.qsl4a.qsl4a.interpreter.InterpreterConstants; 26 | 27 | import java.io.BufferedWriter; 28 | import java.io.File; 29 | import java.io.FileWriter; 30 | import java.io.IOException; 31 | import java.util.ArrayList; 32 | import java.util.Arrays; 33 | import java.util.Collections; 34 | import java.util.Comparator; 35 | import java.util.Iterator; 36 | import java.util.LinkedList; 37 | import java.util.List; 38 | 39 | /** 40 | * Manages storage and retrieval of scripts on the file system. 41 | * 42 | * @author Damon Kohler (damonkohler@gmail.com) 43 | */ 44 | public class ScriptStorageAdapter { 45 | 46 | private ScriptStorageAdapter() { 47 | // Utility class. 48 | } 49 | 50 | /** 51 | * Writes data to the script by name and overwrites any existing data. 52 | */ 53 | public static void writeScript(Context context, File script, String data) { 54 | if (script.getParent() == null) { 55 | script = new File(FileUtils.getScriptsRootPath(context), script.getPath()); 56 | } 57 | try { 58 | FileWriter stream = new FileWriter(script, false /* overwrite */); 59 | BufferedWriter out = new BufferedWriter(stream); 60 | out.write(data); 61 | out.close(); 62 | } catch (IOException e) { 63 | LogUtil.e("Failed to write script.", e); 64 | } 65 | } 66 | 67 | /** 68 | * Returns a list of all available script {@link File}s. 69 | */ 70 | public static List listAllScripts(Context context,File dir) { 71 | if (dir == null) { 72 | dir = new File(FileUtils.getScriptsRootPath(context)); 73 | } 74 | if (dir.exists()) { 75 | List scripts = Arrays.asList(dir.listFiles()); 76 | Collections.sort(scripts, new Comparator() { 77 | @Override 78 | public int compare(File file1, File file2) { 79 | if (file1.isDirectory() && !file2.isDirectory()) { 80 | return -1; 81 | } else if (!file1.isDirectory() && file2.isDirectory()) { 82 | return 1; 83 | } 84 | return file1.compareTo(file2); 85 | } 86 | }); 87 | return scripts; 88 | } 89 | return new ArrayList(); 90 | } 91 | 92 | /** 93 | * Returns a list of script {@link File}s from the given folder for which there is an interpreter 94 | * installed. 95 | */ 96 | public static List listExecutableScripts(Context context,File directory, InterpreterConfiguration config) { 97 | // NOTE(damonkohler): Creating a LinkedList here is necessary in order to be able to filter it 98 | // later. 99 | List scripts = new LinkedList<>(listAllScripts(context,directory)); 100 | // Filter out any files that don't have interpreters installed. 101 | for (Iterator it = scripts.iterator(); it.hasNext();) { 102 | File script = it.next(); 103 | if (script.isDirectory()) { 104 | continue; 105 | } 106 | Interpreter interpreter = config.getInterpreterForScript(script.getName()); 107 | if (interpreter == null || !interpreter.isInstalled()) { 108 | it.remove(); 109 | } 110 | } 111 | return scripts; 112 | } 113 | 114 | /** 115 | * Returns a list of all (including subfolders) script {@link File}s for which there is an 116 | * interpreter installed. 117 | */ 118 | public static List listExecutableScriptsRecursively(Context context,File directory, 119 | InterpreterConfiguration config) { 120 | // NOTE(damonkohler): Creating a LinkedList here is necessary in order to be able to filter it 121 | // later. 122 | List scripts = new LinkedList(); 123 | List files = listAllScripts(context,directory); 124 | 125 | // Filter out any files that don't have interpreters installed. 126 | for (Iterator it = files.iterator(); it.hasNext();) { 127 | File file = it.next(); 128 | if (file.isDirectory()) { 129 | scripts.addAll(listExecutableScriptsRecursively(context,file, config)); 130 | } 131 | Interpreter interpreter = config.getInterpreterForScript(file.getName()); 132 | if (interpreter != null && interpreter.isInstalled()) { 133 | scripts.add(file); 134 | } 135 | } 136 | Collections.sort(scripts); 137 | return scripts; 138 | } 139 | } -------------------------------------------------------------------------------- /src/main/java/org/qpython/qsl4a/qsl4a/SingleThreadExecutor.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2010 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 | * use this file except in compliance with the License. You may obtain a copy of 6 | * the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations under 14 | * the License. 15 | */ 16 | 17 | package org.qpython.qsl4a.qsl4a; 18 | 19 | import java.util.concurrent.LinkedBlockingQueue; 20 | import java.util.concurrent.ThreadPoolExecutor; 21 | import java.util.concurrent.TimeUnit; 22 | 23 | public class SingleThreadExecutor extends ThreadPoolExecutor { 24 | 25 | public SingleThreadExecutor() { 26 | super(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue()); 27 | } 28 | 29 | @Override 30 | protected void afterExecute(Runnable r, Throwable t) { 31 | if (t != null) { 32 | throw new RuntimeException(t); 33 | } 34 | } 35 | } -------------------------------------------------------------------------------- /src/main/java/org/qpython/qsl4a/qsl4a/StringUtils.java: -------------------------------------------------------------------------------- 1 | package org.qpython.qsl4a.qsl4a; 2 | 3 | import java.util.Collection; 4 | import java.util.Iterator; 5 | 6 | public class StringUtils { 7 | 8 | private StringUtils() { 9 | // Utility class. 10 | } 11 | public static String addSlashes(String txt) 12 | { 13 | if (null != txt) 14 | { 15 | txt = txt.replace("\\", "\\\\") ; 16 | txt = txt.replace("\'", "\\\'") ; 17 | //txt = txt.replace(" ", "\\ ") ; 18 | 19 | } 20 | 21 | return txt ; 22 | } 23 | 24 | public static String join(Collection collection, String delimiter) { 25 | StringBuffer buffer = new StringBuffer(); 26 | Iterator iter = collection.iterator(); 27 | while (iter.hasNext()) { 28 | buffer.append(iter.next()); 29 | if (iter.hasNext()) { 30 | buffer.append(delimiter); 31 | } 32 | } 33 | return buffer.toString(); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/org/qpython/qsl4a/qsl4a/Version.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2009 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 | * use this file except in compliance with the License. You may obtain a copy of 6 | * the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations under 14 | * the License. 15 | */ 16 | 17 | package org.qpython.qsl4a.qsl4a; 18 | 19 | import android.content.Context; 20 | import android.content.pm.PackageInfo; 21 | import android.content.pm.PackageManager; 22 | 23 | public class Version { 24 | 25 | private Version() { 26 | // Utility class. 27 | } 28 | 29 | public static String getVersion(Context context) { 30 | try { 31 | PackageInfo info = context.getPackageManager().getPackageInfo(context.getPackageName(), 0); 32 | return info.versionName; 33 | } catch (PackageManager.NameNotFoundException e) { 34 | LogUtil.e("Package name not found", e); 35 | } 36 | return "?"; 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/org/qpython/qsl4a/qsl4a/activity/FutureActivity.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2010 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 | * use this file except in compliance with the License. You may obtain a copy of 6 | * the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations under 14 | * the License. 15 | */ 16 | 17 | package org.qpython.qsl4a.qsl4a.activity; 18 | 19 | import android.app.Activity; 20 | import android.app.Service; 21 | import android.content.Intent; 22 | import android.content.pm.ResolveInfo; 23 | import android.os.Bundle; 24 | //import android.support.v7.app.AppCompatActivity; 25 | import android.view.ContextMenu; 26 | import android.view.ContextMenu.ContextMenuInfo; 27 | import android.view.KeyEvent; 28 | import android.view.Menu; 29 | import android.view.View; 30 | 31 | import org.qpython.qsl4a.QSL4APP; 32 | import org.qpython.qsl4a.qsl4a.Constants; 33 | import org.qpython.qsl4a.qsl4a.FutureActivityTaskExecutor; 34 | import org.qpython.qsl4a.qsl4a.LogUtil; 35 | import org.qpython.qsl4a.qsl4a.future.FutureActivityTask; 36 | 37 | /** 38 | * This {@link Activity} is launched by {@link }s in order to perform operations that a 39 | * {@link Service} is unable to do. For example: start another activity for result, show dialogs, 40 | * etc. 41 | * 42 | * @author Damon Kohler (damonkohler@gmail.com) 43 | */ 44 | public class FutureActivity extends Activity { 45 | private FutureActivityTask mTask; 46 | 47 | private int count = 0; 48 | 49 | @Override 50 | protected void onCreate(Bundle savedInstanceState) { 51 | super.onCreate(savedInstanceState); 52 | LogUtil.v("FutureActivity created."); 53 | int id = getIntent().getIntExtra(Constants.EXTRA_TASK_ID, 0); 54 | if (id == 0) { 55 | throw new RuntimeException("FutureActivityTask ID is not specified."); 56 | } 57 | // River Modify 58 | FutureActivityTaskExecutor taskQueue = ((QSL4APP) getApplication()).getTaskExecutor(); 59 | mTask = taskQueue.getTask(id); 60 | if (mTask == null) { // TODO: (Robbie) This is now less of a kludge. Would still like to know 61 | // what is happening. 62 | LogUtil.w("FutureActivity has no task!"); 63 | try { 64 | Intent intent = new Intent(Intent.ACTION_MAIN); // Should default to main of current app. 65 | intent.addCategory(Intent.CATEGORY_LAUNCHER); 66 | String packageName = getPackageName(); 67 | for (ResolveInfo resolve : getPackageManager().queryIntentActivities(intent, 0)) { 68 | LogUtil.d("resolve.activityInfo.name:"+resolve.activityInfo.name); 69 | if (resolve.activityInfo.packageName.equals(packageName)) { 70 | intent.setClassName(packageName, resolve.activityInfo.name); 71 | break; 72 | } 73 | } 74 | startActivity(intent); 75 | } catch (Exception e) { 76 | LogUtil.e("Can't find main activity."); 77 | } 78 | } else { 79 | mTask.setActivity(this); 80 | mTask.onCreate(); 81 | } 82 | } 83 | 84 | @Override 85 | protected void onStart() { 86 | super.onStart(); 87 | if (mTask != null) { 88 | mTask.onStart(); 89 | } 90 | } 91 | 92 | @Override 93 | protected void onResume() { 94 | super.onResume(); 95 | if (mTask != null) { 96 | mTask.onResume(); 97 | } 98 | } 99 | 100 | @Override 101 | protected void onPause() { 102 | super.onPause(); 103 | if (mTask != null) { 104 | mTask.onPause(); 105 | } 106 | } 107 | 108 | @Override 109 | protected void onStop() { 110 | super.onStop(); 111 | if (mTask != null) { 112 | mTask.onStop(); 113 | } 114 | } 115 | 116 | @Override 117 | protected void onDestroy() { 118 | super.onDestroy(); 119 | if (mTask != null) { 120 | mTask.onDestroy(); 121 | } 122 | } 123 | 124 | @Override 125 | public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) { 126 | if (mTask != null) { 127 | mTask.onCreateContextMenu(menu, v, menuInfo); 128 | } 129 | } 130 | 131 | @Override 132 | public boolean onPrepareOptionsMenu(Menu menu) { 133 | super.onPrepareOptionsMenu(menu); 134 | if (mTask == null) { 135 | return false; 136 | } else { 137 | return mTask.onPrepareOptionsMenu(menu); 138 | } 139 | } 140 | 141 | @Override 142 | public void onActivityResult(int requestCode, int resultCode, Intent data) { 143 | if (mTask != null) { 144 | mTask.onActivityResult(requestCode, resultCode, data); 145 | } 146 | } 147 | 148 | @Override 149 | protected void onNewIntent(Intent intent) { 150 | super.onNewIntent(intent); 151 | if (mTask != null) { 152 | mTask.onNewIntent(intent); 153 | } 154 | } 155 | @Override 156 | public boolean onKeyDown(int keyCode, KeyEvent event) { 157 | if (mTask != null) { 158 | return mTask.onKeyDown(keyCode, event); 159 | } 160 | return false; 161 | } 162 | } 163 | -------------------------------------------------------------------------------- /src/main/java/org/qpython/qsl4a/qsl4a/bluetooth/BluetoothDiscoveryHelper.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2010 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 | * use this file except in compliance with the License. You may obtain a copy of 6 | * the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations under 14 | * the License. 15 | */ 16 | 17 | package org.qpython.qsl4a.qsl4a.bluetooth; 18 | 19 | import android.bluetooth.BluetoothAdapter; 20 | import android.bluetooth.BluetoothDevice; 21 | import android.content.BroadcastReceiver; 22 | import android.content.Context; 23 | import android.content.Intent; 24 | import android.content.IntentFilter; 25 | 26 | import java.util.Set; 27 | 28 | public class BluetoothDiscoveryHelper { 29 | 30 | public static interface BluetoothDiscoveryListener { 31 | public void addBondedDevice(String name, String address); 32 | 33 | public void addDevice(String name, String address); 34 | 35 | public void scanDone(); 36 | } 37 | 38 | private final Context mContext; 39 | private final BluetoothDiscoveryListener mListener; 40 | private final BroadcastReceiver mReceiver; 41 | 42 | public BluetoothDiscoveryHelper(Context context, BluetoothDiscoveryListener listener) { 43 | mContext = context; 44 | mListener = listener; 45 | mReceiver = new BluetoothReceiver(); 46 | } 47 | 48 | private class BluetoothReceiver extends BroadcastReceiver { 49 | @Override 50 | public void onReceive(Context context, Intent intent) { 51 | final String action = intent.getAction(); 52 | 53 | if (BluetoothDevice.ACTION_FOUND.equals(action)) { 54 | // Get the BluetoothDevice object from the Intent. 55 | BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); 56 | // If it's already paired, skip it, because it's been listed already. 57 | if (device.getBondState() != BluetoothDevice.BOND_BONDED) { 58 | mListener.addDevice(device.getName(), device.getAddress()); 59 | } 60 | } else if (BluetoothAdapter.ACTION_DISCOVERY_FINISHED.equals(action)) { 61 | mListener.scanDone(); 62 | } 63 | } 64 | } 65 | 66 | public void startDiscovery() { 67 | BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); 68 | 69 | if (bluetoothAdapter.isDiscovering()) { 70 | bluetoothAdapter.cancelDiscovery(); 71 | } 72 | 73 | Set pairedDevices = bluetoothAdapter.getBondedDevices(); 74 | for (BluetoothDevice device : pairedDevices) { 75 | mListener.addBondedDevice(device.getName(), device.getAddress()); 76 | } 77 | 78 | final IntentFilter deviceFoundFilter = new IntentFilter(BluetoothDevice.ACTION_FOUND); 79 | mContext.registerReceiver(mReceiver, deviceFoundFilter); 80 | 81 | final IntentFilter discoveryFinishedFilter = 82 | new IntentFilter(BluetoothAdapter.ACTION_DISCOVERY_FINISHED); 83 | mContext.registerReceiver(mReceiver, discoveryFinishedFilter); 84 | 85 | if (!bluetoothAdapter.isEnabled()) { 86 | bluetoothAdapter.enable(); 87 | } 88 | 89 | bluetoothAdapter.startDiscovery(); 90 | } 91 | 92 | public void cancel() { 93 | mContext.unregisterReceiver(mReceiver); 94 | mListener.scanDone(); 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /src/main/java/org/qpython/qsl4a/qsl4a/event/Event.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2010 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 | * use this file except in compliance with the License. You may obtain a copy of 6 | * the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations under 14 | * the License. 15 | */ 16 | 17 | package org.qpython.qsl4a.qsl4a.event; 18 | 19 | import com.google.common.base.Preconditions; 20 | 21 | public class Event { 22 | 23 | private String mName; 24 | private Object mData; 25 | private double mCreationTime; 26 | 27 | public Event(String name, Object data) { 28 | Preconditions.checkNotNull(name); 29 | setName(name); 30 | setData(data); 31 | mCreationTime = System.currentTimeMillis() * 1000; 32 | } 33 | 34 | public void setName(String name) { 35 | mName = name; 36 | } 37 | 38 | public String getName() { 39 | return mName; 40 | } 41 | 42 | public void setData(Object data) { 43 | mData = data; 44 | } 45 | 46 | public Object getData() { 47 | return mData; 48 | } 49 | 50 | public double getCreationTime() { 51 | return mCreationTime; 52 | } 53 | 54 | public boolean nameEquals(String name) { 55 | return mName.equals(name); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/main/java/org/qpython/qsl4a/qsl4a/exception/Sl4aException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2009 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 | * use this file except in compliance with the License. You may obtain a copy of 6 | * the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations under 14 | * the License. 15 | */ 16 | 17 | package org.qpython.qsl4a.qsl4a.exception; 18 | 19 | @SuppressWarnings("serial") 20 | public class Sl4aException extends Exception { 21 | 22 | public Sl4aException(Exception e) { 23 | super(e); 24 | } 25 | 26 | public Sl4aException(String message) { 27 | super(message); 28 | } 29 | 30 | public Sl4aException(String message, Exception e) { 31 | super(message, e); 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/org/qpython/qsl4a/qsl4a/facade/ApplicationManagerFacade.java: -------------------------------------------------------------------------------- 1 | package org.qpython.qsl4a.qsl4a.facade; 2 | 3 | import android.app.ActivityManager; 4 | import android.app.Service; 5 | import android.content.Context; 6 | import android.content.Intent; 7 | import android.content.pm.PackageManager; 8 | import android.content.pm.ResolveInfo; 9 | 10 | 11 | import org.qpython.qsl4a.qsl4a.jsonrpc.RpcReceiver; 12 | import org.qpython.qsl4a.qsl4a.rpc.Rpc; 13 | import org.qpython.qsl4a.qsl4a.rpc.RpcParameter; 14 | 15 | import java.util.ArrayList; 16 | import java.util.Arrays; 17 | import java.util.HashMap; 18 | import java.util.HashSet; 19 | import java.util.List; 20 | import java.util.Map; 21 | import java.util.Set; 22 | 23 | /** 24 | * Facade for managing Applications. 25 | * 26 | */ 27 | public class ApplicationManagerFacade extends RpcReceiver { 28 | 29 | private final AndroidFacade mAndroidFacade; 30 | private final ActivityManager mActivityManager; 31 | private final PackageManager mPackageManager; 32 | 33 | public ApplicationManagerFacade(FacadeManager manager) { 34 | super(manager); 35 | Service service = manager.getService(); 36 | mAndroidFacade = manager.getReceiver(AndroidFacade.class); 37 | mActivityManager = (ActivityManager) service.getSystemService(Context.ACTIVITY_SERVICE); 38 | mPackageManager = service.getPackageManager(); 39 | } 40 | 41 | @Rpc(description = "Returns a list of all launchable application class names.") 42 | public Map getLaunchableApplications() { 43 | Intent intent = new Intent(Intent.ACTION_MAIN); 44 | intent.addCategory(Intent.CATEGORY_LAUNCHER); 45 | List resolveInfos = mPackageManager.queryIntentActivities(intent, 0); 46 | Map applications = new HashMap(); 47 | for (ResolveInfo info : resolveInfos) { 48 | applications.put(info.loadLabel(mPackageManager).toString(), info.activityInfo.name); 49 | } 50 | return applications; 51 | } 52 | 53 | @Rpc(description = "Start activity with the given class name.") 54 | public void launch(@RpcParameter(name = "className") String className) { 55 | Intent intent = new Intent(Intent.ACTION_MAIN); 56 | String packageName = className.substring(0, className.lastIndexOf(".")); 57 | intent.setClassName(packageName, className); 58 | mAndroidFacade.startActivity(intent); 59 | } 60 | 61 | @Rpc(description = "Returns a list of packages running activities or services.", returns = "List of packages running activities.") 62 | public List getRunningPackages() { 63 | Set runningPackages = new HashSet(); 64 | List appProcesses = 65 | mActivityManager.getRunningAppProcesses(); 66 | for (ActivityManager.RunningAppProcessInfo info : appProcesses) { 67 | runningPackages.addAll(Arrays.asList(info.pkgList)); 68 | } 69 | List serviceProcesses = 70 | mActivityManager.getRunningServices(Integer.MAX_VALUE); 71 | for (ActivityManager.RunningServiceInfo info : serviceProcesses) { 72 | runningPackages.add(info.service.getPackageName()); 73 | } 74 | return new ArrayList(runningPackages); 75 | } 76 | 77 | @SuppressWarnings("deprecation") 78 | @Rpc(description = "Force stops a package.") 79 | public void forceStopPackage( 80 | @RpcParameter(name = "packageName", description = "name of package") String packageName) { 81 | mActivityManager.restartPackage(packageName); 82 | } 83 | 84 | @Override 85 | public void shutdown() { 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /src/main/java/org/qpython/qsl4a/qsl4a/facade/CommonIntentsFacade.java: -------------------------------------------------------------------------------- 1 | package org.qpython.qsl4a.qsl4a.facade; 2 | 3 | import android.app.SearchManager; 4 | import android.content.Intent; 5 | import android.net.Uri; 6 | import android.provider.Contacts.People; 7 | 8 | 9 | import org.qpython.qsl4a.qsl4a.jsonrpc.RpcReceiver; 10 | import org.qpython.qsl4a.qsl4a.rpc.Rpc; 11 | import org.qpython.qsl4a.qsl4a.rpc.RpcOptional; 12 | import org.qpython.qsl4a.qsl4a.rpc.RpcParameter; 13 | 14 | import java.io.File; 15 | 16 | import org.json.JSONException; 17 | import org.json.JSONObject; 18 | 19 | /** 20 | * A selection of commonly used intents.
21 | *
22 | * These can be used to trigger some common tasks. 23 | * 24 | */ 25 | @SuppressWarnings("deprecation") 26 | public class CommonIntentsFacade extends RpcReceiver { 27 | 28 | private final AndroidFacade mAndroidFacade; 29 | 30 | public CommonIntentsFacade(FacadeManager manager) { 31 | super(manager); 32 | mAndroidFacade = manager.getReceiver(AndroidFacade.class); 33 | } 34 | 35 | @Override 36 | public void shutdown() { 37 | } 38 | 39 | @Rpc(description = "Display content to be picked by URI (e.g. contacts)", returns = "A map of result values.") 40 | public Intent pick(@RpcParameter(name = "uri") String uri) throws JSONException { 41 | return mAndroidFacade.startActivityForResult(Intent.ACTION_PICK, uri, null, null, null, null); 42 | } 43 | 44 | @Rpc(description = "Starts the barcode scanner.", returns = "A Map representation of the result Intent.") 45 | public Intent scanBarcode() throws JSONException { 46 | return mAndroidFacade.startActivityForResult("com.google.zxing.client.android.SCAN", null, 47 | null, null, null, null); 48 | } 49 | 50 | private void view(Uri uri, String type) { 51 | 52 | Intent intent = new Intent(); 53 | intent.setClassName(this.mAndroidFacade.getmService().getApplicationContext(),"org.qpython.qpy.main.QWebViewActivity"); 54 | intent.putExtra("com.quseit.common.extra.CONTENT_URL1", "main"); 55 | intent.putExtra("com.quseit.common.extra.CONTENT_URL2", "QPyWebApp"); 56 | //intent.putExtra("com.quseit.common.extra.CONTENT_URL6", "drawer"); 57 | intent.setDataAndType(uri, type); 58 | mAndroidFacade.startActivity(intent); 59 | } 60 | 61 | @Rpc(description = "Start activity with view action by URI (i.e. browser, contacts, etc.).") 62 | public void view( 63 | @RpcParameter(name = "uri") String uri, 64 | @RpcParameter(name = "type", description = "MIME type/subtype of the URI") @RpcOptional String type, 65 | @RpcParameter(name = "extras", description = "a Map of extras to add to the Intent") @RpcOptional JSONObject extras) 66 | throws Exception { 67 | mAndroidFacade.startActivity(Intent.ACTION_VIEW, uri, type, extras, true, null, null); 68 | } 69 | 70 | @Rpc(description = "Opens a map search for query (e.g. pizza, 123 My Street).") 71 | public void viewMap(@RpcParameter(name = "query, e.g. pizza, 123 My Street") String query) 72 | throws Exception { 73 | view("geo:0,0?q=" + query, null, null); 74 | } 75 | 76 | @Rpc(description = "Opens the list of contacts.") 77 | public void viewContacts() throws JSONException { 78 | view(People.CONTENT_URI, null); 79 | } 80 | 81 | @Rpc(description = "Opens the browser to display a local HTML file.") 82 | public void viewHtml( 83 | @RpcParameter(name = "path", description = "the path to the HTML file") String path) 84 | throws JSONException { 85 | File file = new File(path); 86 | view(Uri.fromFile(file), "text/html"); 87 | } 88 | 89 | @Rpc(description = "Starts a search for the given query.") 90 | public void search(@RpcParameter(name = "query") String query) { 91 | Intent intent = new Intent(Intent.ACTION_SEARCH); 92 | intent.putExtra(SearchManager.QUERY, query); 93 | mAndroidFacade.startActivity(intent); 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /src/main/java/org/qpython/qsl4a/qsl4a/facade/EventServer.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2001 Naranjo Manuel Francisco 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 | * use this file except in compliance with the License. You may obtain a copy of 6 | * the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations under 14 | * the License. 15 | */ 16 | package org.qpython.qsl4a.qsl4a.facade; 17 | 18 | import org.qpython.qsl4a.qsl4a.LogUtil; 19 | import org.qpython.qsl4a.qsl4a.SimpleServer; 20 | import org.qpython.qsl4a.qsl4a.event.Event; 21 | import org.qpython.qsl4a.qsl4a.jsonrpc.JsonBuilder; 22 | 23 | import java.io.IOException; 24 | import java.io.PrintWriter; 25 | import java.net.InetSocketAddress; 26 | import java.net.Socket; 27 | import java.util.Vector; 28 | import java.util.concurrent.CountDownLatch; 29 | 30 | import org.json.JSONException; 31 | 32 | /** 33 | * An Event Forwarding server that forwards events from the rpc queue in realtime to listener 34 | * clients. 35 | * 36 | * @author Manuel Naranjo (manuel@aircable.net) 37 | * @see com.googlecode.android_scripting.SimpleServer 38 | */ 39 | public class EventServer extends SimpleServer implements EventFacade.EventObserver { 40 | private static final Vector mListeners = new Vector(); 41 | private InetSocketAddress address = null; 42 | 43 | public EventServer() { 44 | this(0); 45 | } 46 | 47 | public EventServer(int port) { 48 | address = startAllInterfaces(port); 49 | } 50 | 51 | public InetSocketAddress getAddress() { 52 | return address; 53 | } 54 | 55 | @Override 56 | public void shutdown() { 57 | onEventReceived(new Event("sl4a", "{\"shutdown\": \"event-server\"}")); 58 | for (Listener listener : mListeners) { 59 | mListeners.remove(listener); 60 | listener.lock.countDown(); 61 | } 62 | super.shutdown(); 63 | } 64 | 65 | @Override 66 | protected void handleConnection(Socket socket) throws IOException { 67 | Listener l = new Listener(socket); 68 | LogUtil.v("Adding EventServer listener " + socket.getPort()); 69 | mListeners.add(l); 70 | // we are running in the socket accept thread 71 | // wait until the event dispatcher gets us the events 72 | // or we die, what ever happens first 73 | try { 74 | l.lock.await(); 75 | } catch (InterruptedException e) { 76 | e.printStackTrace(); 77 | } 78 | try { 79 | l.sock.close(); 80 | } catch (IOException e) { 81 | e.printStackTrace(); 82 | } 83 | LogUtil.v("Ending EventServer listener " + socket.getPort()); 84 | } 85 | 86 | @Override 87 | public void onEventReceived(Event event) { 88 | Object result = null; 89 | try { 90 | result = JsonBuilder.build(event); 91 | } catch (JSONException e) { 92 | return; 93 | } 94 | 95 | LogUtil.v("EventServer dispatching " + result); 96 | 97 | for (Listener listener : mListeners) { 98 | if (!listener.out.checkError()) { 99 | listener.out.write(result + "\n"); 100 | listener.out.flush(); 101 | } else { 102 | // let the socket accept thread we're done 103 | mListeners.remove(listener); 104 | listener.lock.countDown(); 105 | } 106 | } 107 | } 108 | 109 | private class Listener { 110 | private Socket sock; 111 | private PrintWriter out; 112 | private CountDownLatch lock = new CountDownLatch(1); 113 | 114 | public Listener(Socket l) throws IOException { 115 | sock = l; 116 | out = new PrintWriter(l.getOutputStream(), true); 117 | } 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /src/main/java/org/qpython/qsl4a/qsl4a/facade/EyesFreeFacade.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2009 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 | * use this file except in compliance with the License. You may obtain a copy of 6 | * the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations under 14 | * the License. 15 | */ 16 | 17 | package org.qpython.qsl4a.qsl4a.facade; 18 | 19 | import android.app.Service; 20 | import android.content.Intent; 21 | import android.content.pm.PackageManager; 22 | import android.content.pm.ResolveInfo; 23 | 24 | 25 | import org.qpython.qsl4a.qsl4a.jsonrpc.RpcReceiver; 26 | import org.qpython.qsl4a.qsl4a.rpc.Rpc; 27 | import org.qpython.qsl4a.qsl4a.rpc.RpcParameter; 28 | 29 | import java.util.List; 30 | 31 | /** 32 | * Provides Text To Speech services for API 3 or less. 33 | */ 34 | 35 | public class EyesFreeFacade extends RpcReceiver { 36 | 37 | private final Service mService; 38 | private final PackageManager mPackageManager; 39 | 40 | public EyesFreeFacade(FacadeManager manager) { 41 | super(manager); 42 | mService = manager.getService(); 43 | mPackageManager = mService.getPackageManager(); 44 | } 45 | 46 | @Rpc(description = "Speaks the provided message via TTS.") 47 | public void ttsSpeak(@RpcParameter(name = "message") String message) { 48 | Intent intent = new Intent("com.google.tts.makeBagel"); 49 | intent.putExtra("message", message); 50 | intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 51 | List infos = mPackageManager.queryIntentActivities(intent, 0); 52 | if (infos.size() > 0) { 53 | mService.startActivity(intent); 54 | } else { 55 | throw new RuntimeException("Eyes-Free is not installed."); 56 | } 57 | } 58 | 59 | @Override 60 | public void shutdown() { 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/main/java/org/qpython/qsl4a/qsl4a/facade/FacadeManager.java: -------------------------------------------------------------------------------- 1 | package org.qpython.qsl4a.qsl4a.facade; 2 | 3 | import android.app.Service; 4 | import android.content.Intent; 5 | 6 | import org.qpython.qsl4a.qsl4a.LogUtil; 7 | import org.qpython.qsl4a.qsl4a.exception.Sl4aException; 8 | import org.qpython.qsl4a.qsl4a.jsonrpc.RpcReceiver; 9 | import org.qpython.qsl4a.qsl4a.jsonrpc.RpcReceiverManager; 10 | import org.qpython.qsl4a.qsl4a.rpc.RpcDeprecated; 11 | import org.qpython.qsl4a.qsl4a.rpc.RpcMinSdk; 12 | 13 | 14 | import java.lang.reflect.InvocationTargetException; 15 | import java.lang.reflect.Method; 16 | import java.util.Collection; 17 | 18 | public class FacadeManager extends RpcReceiverManager { 19 | 20 | private final Service mService; 21 | private final Intent mIntent; 22 | private int mSdkLevel; 23 | 24 | public FacadeManager(int sdkLevel, Service service, Intent intent, 25 | Collection> classList) { 26 | super(classList); 27 | mSdkLevel = sdkLevel; 28 | mService = service; 29 | mIntent = intent; 30 | } 31 | 32 | public int getSdkLevel() { 33 | return mSdkLevel; 34 | } 35 | 36 | public Service getService() { 37 | return mService; 38 | } 39 | 40 | public Intent getIntent() { 41 | return mIntent; 42 | } 43 | 44 | @Override 45 | public Object invoke(Class clazz, Method method, Object[] args) 46 | throws Exception { 47 | try { 48 | if (method.isAnnotationPresent(RpcDeprecated.class)) { 49 | String replacedBy = method.getAnnotation(RpcDeprecated.class).value(); 50 | String title = method.getName() + " is deprecated"; 51 | LogUtil.notify(mService, title, title, String.format("Please use %s instead.", replacedBy)); 52 | } else if (method.isAnnotationPresent(RpcMinSdk.class)) { 53 | int requiredSdkLevel = method.getAnnotation(RpcMinSdk.class).value(); 54 | if (mSdkLevel < requiredSdkLevel) { 55 | throw new Sl4aException(String.format("%s requires API level %d, current level is %d", 56 | method.getName(), requiredSdkLevel, mSdkLevel)); 57 | } 58 | } 59 | return super.invoke(clazz, method, args); 60 | } catch (InvocationTargetException e) { 61 | if (e.getCause() instanceof SecurityException) { 62 | LogUtil.notify(mService, "RPC invoke failed...", mService.getPackageName(), e.getCause() 63 | .getMessage()); 64 | } 65 | throw e; 66 | } 67 | } 68 | 69 | public AndroidFacade.Resources getAndroidFacadeResources() { 70 | return new AndroidFacade.Resources() { 71 | @Override 72 | public int getLogo48() { 73 | // TODO(Alexey): As an alternative, ask application for resource ids. 74 | String packageName = mService.getApplication().getPackageName(); 75 | return mService.getResources().getIdentifier("script_logo_48", "drawable", packageName); 76 | } 77 | }; 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /src/main/java/org/qpython/qsl4a/qsl4a/facade/FacadeManagerFactory.java: -------------------------------------------------------------------------------- 1 | package org.qpython.qsl4a.qsl4a.facade; 2 | 3 | import android.app.Service; 4 | import android.content.Intent; 5 | 6 | 7 | import org.qpython.qsl4a.qsl4a.jsonrpc.RpcReceiver; 8 | import org.qpython.qsl4a.qsl4a.jsonrpc.RpcReceiverManager; 9 | import org.qpython.qsl4a.qsl4a.jsonrpc.RpcReceiverManagerFactory; 10 | 11 | import java.util.ArrayList; 12 | import java.util.Collection; 13 | import java.util.List; 14 | 15 | public class FacadeManagerFactory implements RpcReceiverManagerFactory { 16 | 17 | private final int mSdkLevel; 18 | private final Service mService; 19 | private final Intent mIntent; 20 | private final Collection> mClassList; 21 | private final List mFacadeManagers; 22 | 23 | public FacadeManagerFactory(int sdkLevel, Service service, Intent intent, 24 | Collection> classList) { 25 | mSdkLevel = sdkLevel; 26 | mService = service; 27 | mIntent = intent; 28 | mClassList = classList; 29 | mFacadeManagers = new ArrayList(); 30 | } 31 | 32 | public FacadeManager create() { 33 | FacadeManager facadeManager = new FacadeManager(mSdkLevel, mService, mIntent, mClassList); 34 | mFacadeManagers.add(facadeManager); 35 | return facadeManager; 36 | } 37 | 38 | @Override 39 | public List getRpcReceiverManagers() { 40 | return mFacadeManagers; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/main/java/org/qpython/qsl4a/qsl4a/facade/JpegProvider.java: -------------------------------------------------------------------------------- 1 | package org.qpython.qsl4a.qsl4a.facade; 2 | 3 | interface JpegProvider { 4 | public byte[] getJpeg(); 5 | } -------------------------------------------------------------------------------- /src/main/java/org/qpython/qsl4a/qsl4a/facade/MjpegServer.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2010 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 | * use this file except in compliance with the License. You may obtain a copy of 6 | * the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations under 14 | * the License. 15 | */ 16 | 17 | package org.qpython.qsl4a.qsl4a.facade; 18 | 19 | import java.io.OutputStream; 20 | import java.net.Socket; 21 | 22 | import org.qpython.qsl4a.qsl4a.SimpleServer; 23 | 24 | class MjpegServer extends SimpleServer { 25 | 26 | private final JpegProvider mProvider; 27 | 28 | public MjpegServer(JpegProvider provider) { 29 | mProvider = provider; 30 | } 31 | 32 | @Override 33 | protected void handleConnection(Socket socket) throws Exception { 34 | byte[] data = mProvider.getJpeg(); 35 | if (data == null) { 36 | return; 37 | } 38 | OutputStream outputStream = socket.getOutputStream(); 39 | outputStream.write(( 40 | "HTTP/1.0 200 OK\r\n" + 41 | "Server: SL4A\r\n" + 42 | "Connection: close\r\n" + 43 | "Max-Age: 0\r\n" + 44 | "Expires: 0\r\n" + 45 | "Cache-Control: no-cache, private\r\n" + 46 | "Pragma: no-cache\r\n" + 47 | "Content-Type: multipart/x-mixed-replace; boundary=--BoundaryString\r\n\r\n").getBytes()); 48 | while (true) { 49 | data = mProvider.getJpeg(); 50 | if (data == null) { 51 | return; 52 | } 53 | outputStream.write("--BoundaryString\r\n".getBytes()); 54 | outputStream.write("Content-type: image/jpg\r\n".getBytes()); 55 | outputStream.write(("Content-Length: " + data.length + "\r\n\r\n").getBytes()); 56 | outputStream.write(data); 57 | outputStream.write("\r\n\r\n".getBytes()); 58 | outputStream.flush(); 59 | } 60 | } 61 | } -------------------------------------------------------------------------------- /src/main/java/org/qpython/qsl4a/qsl4a/facade/PreferencesFacade.java: -------------------------------------------------------------------------------- 1 | package org.qpython.qsl4a.qsl4a.facade; 2 | 3 | import android.app.Service; 4 | import android.content.SharedPreferences; 5 | import android.content.SharedPreferences.Editor; 6 | import android.preference.PreferenceManager; 7 | 8 | import org.qpython.qsl4a.qsl4a.jsonrpc.RpcReceiver; 9 | import org.qpython.qsl4a.qsl4a.rpc.Rpc; 10 | import org.qpython.qsl4a.qsl4a.rpc.RpcOptional; 11 | import org.qpython.qsl4a.qsl4a.rpc.RpcParameter; 12 | 13 | import java.io.IOException; 14 | import java.util.Map; 15 | 16 | /** 17 | * This facade allows access to the Preferences interface. 18 | * 19 | *
20 | * Notes:
21 | * filename - Filename indicates which preference file to refer to. If no filename is 22 | * supplied (the default) then the SharedPreferences uses is the default for the SL4A application.
23 | * prefPutValue - uses "MODE_PRIVATE" when writing to preferences. Save values to the default 24 | * shared preferences is explicitly disallowed.
25 | *
26 | * See Preferences and 28 | * Shared 29 | * Preferences in the android documentation on how preferences work. 30 | * 31 | * @author Robbie Matthews (rjmatthews62@gmail.com) 32 | */ 33 | 34 | public class PreferencesFacade extends RpcReceiver { 35 | 36 | private Service mService; 37 | 38 | public PreferencesFacade(FacadeManager manager) { 39 | super(manager); 40 | mService = manager.getService(); 41 | } 42 | 43 | @Rpc(description = "Read a value from shared preferences") 44 | public Object prefGetValue( 45 | @RpcParameter(name = "key") String key, 46 | @RpcParameter(name = "filename", description = "Desired preferences file. If not defined, uses the default Shared Preferences.") @RpcOptional String filename) { 47 | SharedPreferences p = getPref(filename); 48 | return p.getAll().get(key); 49 | } 50 | 51 | @Rpc(description = "Write a value to shared preferences") 52 | public void prefPutValue( 53 | @RpcParameter(name = "key") String key, 54 | @RpcParameter(name = "value") Object value, 55 | @RpcParameter(name = "filename", description = "Desired preferences file. If not defined, uses the default Shared Preferences.") @RpcOptional String filename) 56 | throws IOException { 57 | if (filename == null || filename.equals("")) { 58 | throw new IOException("Can't write to default preferences."); 59 | } 60 | SharedPreferences p = getPref(filename); 61 | Editor e = p.edit(); 62 | if (value instanceof Boolean) { 63 | e.putBoolean(key, (Boolean) value); 64 | } else if (value instanceof Long) { 65 | e.putLong(key, (Long) value); 66 | } else if (value instanceof Integer) { 67 | e.putLong(key, (Integer) value); 68 | } else if (value instanceof Float) { 69 | e.putFloat(key, (Float) value); 70 | } else if (value instanceof Double) { // TODO: Not sure if this is a good idea 71 | e.putFloat(key, ((Double) value).floatValue()); 72 | } else { 73 | e.putString(key, value.toString()); 74 | } 75 | e.commit(); 76 | } 77 | 78 | @Rpc(description = "Get list of Shared Preference Values", returns = "Map of key,value") 79 | public Map prefGetAll( 80 | @RpcParameter(name = "filename", description = "Desired preferences file. If not defined, uses the default Shared Preferences.") @RpcOptional String filename) { 81 | return getPref(filename).getAll(); 82 | } 83 | 84 | private SharedPreferences getPref(String filename) { 85 | if (filename == null || filename.equals("")) { 86 | return PreferenceManager.getDefaultSharedPreferences(mService); 87 | } 88 | return mService.getSharedPreferences(filename, 0); 89 | 90 | } 91 | 92 | @Override 93 | public void shutdown() { 94 | 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /src/main/java/org/qpython/qsl4a/qsl4a/facade/SignalStrengthFacade.java: -------------------------------------------------------------------------------- 1 | package org.qpython.qsl4a.qsl4a.facade; 2 | 3 | import android.app.Service; 4 | import android.content.Context; 5 | import android.os.Bundle; 6 | import android.telephony.PhoneStateListener; 7 | import android.telephony.SignalStrength; 8 | import android.telephony.TelephonyManager; 9 | 10 | import org.qpython.qsl4a.qsl4a.MainThread; 11 | import org.qpython.qsl4a.qsl4a.jsonrpc.RpcReceiver; 12 | import org.qpython.qsl4a.qsl4a.rpc.Rpc; 13 | import org.qpython.qsl4a.qsl4a.rpc.RpcMinSdk; 14 | import org.qpython.qsl4a.qsl4a.rpc.RpcStartEvent; 15 | import org.qpython.qsl4a.qsl4a.rpc.RpcStopEvent; 16 | 17 | import java.util.concurrent.Callable; 18 | 19 | /** 20 | * Exposes SignalStrength functionality. 21 | * 22 | * @author Joerg Zieren (joerg.zieren@gmail.com) 23 | */ 24 | @RpcMinSdk(7) 25 | public class SignalStrengthFacade extends RpcReceiver { 26 | private final Service mService; 27 | private final TelephonyManager mTelephonyManager; 28 | private final EventFacade mEventFacade; 29 | private final PhoneStateListener mPhoneStateListener; 30 | private Bundle mSignalStrengths; 31 | 32 | public SignalStrengthFacade(FacadeManager manager) { 33 | super(manager); 34 | mService = manager.getService(); 35 | mEventFacade = manager.getReceiver(EventFacade.class); 36 | mTelephonyManager = 37 | (TelephonyManager) manager.getService().getSystemService(Context.TELEPHONY_SERVICE); 38 | mPhoneStateListener = MainThread.run(mService, new Callable() { 39 | @Override 40 | public PhoneStateListener call() throws Exception { 41 | return new PhoneStateListener() { 42 | @Override 43 | public void onSignalStrengthsChanged(SignalStrength signalStrength) { 44 | mSignalStrengths = new Bundle(); 45 | mSignalStrengths.putInt("gsm_signal_strength", signalStrength.getGsmSignalStrength()); 46 | mSignalStrengths.putInt("gsm_bit_error_rate", signalStrength.getGsmBitErrorRate()); 47 | mSignalStrengths.putInt("cdma_dbm", signalStrength.getCdmaDbm()); 48 | mSignalStrengths.putInt("cdma_ecio", signalStrength.getCdmaEcio()); 49 | mSignalStrengths.putInt("evdo_dbm", signalStrength.getEvdoDbm()); 50 | mSignalStrengths.putInt("evdo_ecio", signalStrength.getEvdoEcio()); 51 | mEventFacade.postEvent("signal_strengths", mSignalStrengths.clone()); 52 | } 53 | }; 54 | } 55 | }); 56 | } 57 | 58 | @Rpc(description = "Starts tracking signal strengths.") 59 | @RpcStartEvent("signal_strengths") 60 | public void startTrackingSignalStrengths() { 61 | mTelephonyManager.listen(mPhoneStateListener, PhoneStateListener.LISTEN_SIGNAL_STRENGTHS); 62 | } 63 | 64 | @Rpc(description = "Returns the current signal strengths.", returns = "A map of \"gsm_signal_strength\"") 65 | public Bundle readSignalStrengths() { 66 | return mSignalStrengths; 67 | } 68 | 69 | @Rpc(description = "Stops tracking signal strength.") 70 | @RpcStopEvent("signal_strengths") 71 | public void stopTrackingSignalStrengths() { 72 | mTelephonyManager.listen(mPhoneStateListener, PhoneStateListener.LISTEN_NONE); 73 | } 74 | 75 | @Override 76 | public void shutdown() { 77 | stopTrackingSignalStrengths(); 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /src/main/java/org/qpython/qsl4a/qsl4a/facade/SpeechRecognitionFacade.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2009 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 | * use this file except in compliance with the License. You may obtain a copy of 6 | * the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations under 14 | * the License. 15 | */ 16 | 17 | package org.qpython.qsl4a.qsl4a.facade; 18 | 19 | import android.content.Intent; 20 | import android.speech.RecognizerIntent; 21 | 22 | 23 | import org.qpython.qsl4a.qsl4a.jsonrpc.RpcReceiver; 24 | import org.qpython.qsl4a.qsl4a.rpc.Rpc; 25 | import org.qpython.qsl4a.qsl4a.rpc.RpcOptional; 26 | import org.qpython.qsl4a.qsl4a.rpc.RpcParameter; 27 | 28 | import java.util.ArrayList; 29 | 30 | /** 31 | * A facade containing RPC implementations related to the speech-to-text functionality of Android. 32 | * 33 | * @author Felix Arends (felix.arends@gmail.com) 34 | * 35 | */ 36 | public class SpeechRecognitionFacade extends RpcReceiver { 37 | private final AndroidFacade mAndroidFacade; 38 | 39 | /** 40 | * @param activityLauncher 41 | * a helper object that launches activities in a blocking manner 42 | */ 43 | public SpeechRecognitionFacade(FacadeManager manager) { 44 | super(manager); 45 | mAndroidFacade = manager.getReceiver(AndroidFacade.class); 46 | } 47 | 48 | @Rpc(description = "Recognizes user's speech and returns the most likely result.", returns = "An empty string in case the speech cannot be recongnized.") 49 | public String recognizeSpeech( 50 | @RpcParameter(name = "prompt", description = "text prompt to show to the user when asking them to speak") @RpcOptional final String prompt, 51 | @RpcParameter(name = "language", description = "language override to inform the recognizer that it should expect speech in a language different than the one set in the java.util.Locale.getDefault()") @RpcOptional final String language, 52 | @RpcParameter(name = "languageModel", description = "informs the recognizer which speech model to prefer (see android.speech.RecognizeIntent)") @RpcOptional final String languageModel) { 53 | final Intent recognitionIntent = 54 | new Intent(android.speech.RecognizerIntent.ACTION_RECOGNIZE_SPEECH); 55 | 56 | // Setup intent parameters (if provided). 57 | if (language != null) { 58 | recognitionIntent.putExtra(RecognizerIntent.EXTRA_LANGUAGE, ""); 59 | } 60 | if (languageModel != null) { 61 | recognitionIntent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL, ""); 62 | } 63 | if (prompt != null) { 64 | recognitionIntent.putExtra(RecognizerIntent.EXTRA_PROMPT, ""); 65 | } 66 | 67 | // Run the activity an retrieve the result. 68 | final Intent data = mAndroidFacade.startActivityForResult(recognitionIntent); 69 | 70 | if (data.hasExtra(android.speech.RecognizerIntent.EXTRA_RESULTS)) { 71 | // The result consists of an array-list containing one entry for each 72 | // possible result. The most likely result is the first entry. 73 | ArrayList results = 74 | data.getStringArrayListExtra(android.speech.RecognizerIntent.EXTRA_RESULTS); 75 | return results.get(0); 76 | } 77 | 78 | return ""; 79 | } 80 | 81 | @Override 82 | public void shutdown() { 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /src/main/java/org/qpython/qsl4a/qsl4a/facade/TextToSpeechFacade.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2009 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 | * use this file except in compliance with the License. You may obtain a copy of 6 | * the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations under 14 | * the License. 15 | */ 16 | 17 | package org.qpython.qsl4a.qsl4a.facade; 18 | 19 | import android.os.SystemClock; 20 | import android.speech.tts.TextToSpeech; 21 | import android.speech.tts.TextToSpeech.OnInitListener; 22 | 23 | 24 | import org.qpython.qsl4a.qsl4a.jsonrpc.RpcReceiver; 25 | import org.qpython.qsl4a.qsl4a.rpc.Rpc; 26 | import org.qpython.qsl4a.qsl4a.rpc.RpcMinSdk; 27 | import org.qpython.qsl4a.qsl4a.rpc.RpcParameter; 28 | 29 | import java.util.concurrent.CountDownLatch; 30 | 31 | /** 32 | * Provides Text To Speech services for API 4 or more. 33 | */ 34 | 35 | @RpcMinSdk(4) 36 | public class TextToSpeechFacade extends RpcReceiver { 37 | 38 | private final TextToSpeech mTts; 39 | private final CountDownLatch mOnInitLock; 40 | 41 | public TextToSpeechFacade(FacadeManager manager) { 42 | super(manager); 43 | mOnInitLock = new CountDownLatch(1); 44 | mTts = new TextToSpeech(manager.getService(), new OnInitListener() { 45 | @Override 46 | public void onInit(int arg0) { 47 | mOnInitLock.countDown(); 48 | } 49 | }); 50 | } 51 | 52 | @Override 53 | public void shutdown() { 54 | while (mTts.isSpeaking()) { 55 | SystemClock.sleep(100); 56 | } 57 | mTts.shutdown(); 58 | } 59 | 60 | @Rpc(description = "Speaks the provided message via TTS.") 61 | public void ttsSpeak(@RpcParameter(name = "message") String message) throws InterruptedException { 62 | mOnInitLock.await(); 63 | if (message != null) { 64 | mTts.speak(message, TextToSpeech.QUEUE_ADD, null); 65 | } 66 | } 67 | 68 | @Rpc(description = "Returns True if speech is currently in progress.") 69 | public Boolean ttsIsSpeaking() throws InterruptedException { 70 | mOnInitLock.await(); 71 | return mTts.isSpeaking(); 72 | } 73 | 74 | } 75 | -------------------------------------------------------------------------------- /src/main/java/org/qpython/qsl4a/qsl4a/facade/ToneGeneratorFacade.java: -------------------------------------------------------------------------------- 1 | package org.qpython.qsl4a.qsl4a.facade; 2 | 3 | import android.media.AudioManager; 4 | import android.media.ToneGenerator; 5 | 6 | import org.qpython.qsl4a.qsl4a.jsonrpc.RpcReceiver; 7 | import org.qpython.qsl4a.qsl4a.rpc.Rpc; 8 | import org.qpython.qsl4a.qsl4a.rpc.RpcDefault; 9 | import org.qpython.qsl4a.qsl4a.rpc.RpcParameter; 10 | 11 | 12 | /** 13 | * Generate DTMF tones. 14 | * 15 | */ 16 | public class ToneGeneratorFacade extends RpcReceiver { 17 | 18 | private final ToneGenerator mToneGenerator; 19 | 20 | public ToneGeneratorFacade(FacadeManager manager) { 21 | super(manager); 22 | mToneGenerator = new ToneGenerator(AudioManager.STREAM_MUSIC, 100); 23 | } 24 | 25 | @Rpc(description = "Generate DTMF tones for the given phone number.") 26 | public void generateDtmfTones( 27 | @RpcParameter(name = "phoneNumber") String phoneNumber, 28 | @RpcParameter(name = "toneDuration", description = "duration of each tone in milliseconds") @RpcDefault("100") Integer toneDuration) 29 | throws InterruptedException { 30 | try { 31 | for (int i = 0; i < phoneNumber.length(); i++) { 32 | switch (phoneNumber.charAt(i)) { 33 | case '0': 34 | mToneGenerator.startTone(ToneGenerator.TONE_DTMF_0); 35 | Thread.sleep(toneDuration); 36 | break; 37 | case '1': 38 | mToneGenerator.startTone(ToneGenerator.TONE_DTMF_1); 39 | Thread.sleep(toneDuration); 40 | break; 41 | case '2': 42 | mToneGenerator.startTone(ToneGenerator.TONE_DTMF_2); 43 | Thread.sleep(toneDuration); 44 | break; 45 | case '3': 46 | mToneGenerator.startTone(ToneGenerator.TONE_DTMF_3); 47 | Thread.sleep(toneDuration); 48 | break; 49 | case '4': 50 | mToneGenerator.startTone(ToneGenerator.TONE_DTMF_4); 51 | Thread.sleep(toneDuration); 52 | break; 53 | case '5': 54 | mToneGenerator.startTone(ToneGenerator.TONE_DTMF_5); 55 | Thread.sleep(toneDuration); 56 | break; 57 | case '6': 58 | mToneGenerator.startTone(ToneGenerator.TONE_DTMF_6); 59 | Thread.sleep(toneDuration); 60 | break; 61 | case '7': 62 | mToneGenerator.startTone(ToneGenerator.TONE_DTMF_7); 63 | Thread.sleep(toneDuration); 64 | break; 65 | case '8': 66 | mToneGenerator.startTone(ToneGenerator.TONE_DTMF_8); 67 | Thread.sleep(toneDuration); 68 | break; 69 | case '9': 70 | mToneGenerator.startTone(ToneGenerator.TONE_DTMF_9); 71 | Thread.sleep(toneDuration); 72 | break; 73 | case '*': 74 | mToneGenerator.startTone(ToneGenerator.TONE_DTMF_S); 75 | Thread.sleep(toneDuration); 76 | break; 77 | case '#': 78 | mToneGenerator.startTone(ToneGenerator.TONE_DTMF_P); 79 | Thread.sleep(toneDuration); 80 | break; 81 | default: 82 | throw new RuntimeException("Cannot generate tone for '" + phoneNumber.charAt(i) + "'"); 83 | } 84 | } 85 | } finally { 86 | mToneGenerator.stopTone(); 87 | } 88 | } 89 | 90 | @Override 91 | public void shutdown() { 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /src/main/java/org/qpython/qsl4a/qsl4a/facade/WakeLockFacade.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2010 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 | * use this file except in compliance with the License. You may obtain a copy of 6 | * the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations under 14 | * the License. 15 | */ 16 | 17 | package org.qpython.qsl4a.qsl4a.facade; 18 | 19 | import android.annotation.SuppressLint; 20 | import android.app.Service; 21 | import android.content.Context; 22 | import android.os.PowerManager; 23 | import android.os.PowerManager.WakeLock; 24 | 25 | 26 | import org.qpython.qsl4a.qsl4a.jsonrpc.RpcReceiver; 27 | import org.qpython.qsl4a.qsl4a.rpc.Rpc; 28 | 29 | import java.util.HashMap; 30 | import java.util.Map; 31 | import java.util.Map.Entry; 32 | 33 | /** 34 | * A facade exposing some of the functionality of the PowerManager, in particular wake locks. 35 | * 36 | * @author Felix Arends (felixarends@gmail.com) 37 | * @author Damon Kohler (damonkohler@gmail.com) 38 | */ 39 | public class WakeLockFacade extends RpcReceiver { 40 | 41 | private final static String WAKE_LOCK_TAG = 42 | "com.googlecode.android_scripting.facade.PowerManagerFacade"; 43 | 44 | private enum WakeLockType { 45 | FULL, PARTIAL, BRIGHT, DIM 46 | } 47 | 48 | private class WakeLockManager { 49 | private final PowerManager mmPowerManager; 50 | private final Map mmLocks = new HashMap(); 51 | 52 | @SuppressWarnings("deprecation") 53 | public WakeLockManager(Service service) { 54 | mmPowerManager = (PowerManager) service.getSystemService(Context.POWER_SERVICE); 55 | addWakeLock(WakeLockType.PARTIAL, PowerManager.PARTIAL_WAKE_LOCK); 56 | addWakeLock(WakeLockType.FULL, PowerManager.FULL_WAKE_LOCK | PowerManager.ON_AFTER_RELEASE); 57 | addWakeLock(WakeLockType.BRIGHT, PowerManager.SCREEN_BRIGHT_WAKE_LOCK 58 | | PowerManager.ON_AFTER_RELEASE); 59 | addWakeLock(WakeLockType.DIM, PowerManager.SCREEN_DIM_WAKE_LOCK 60 | | PowerManager.ON_AFTER_RELEASE); 61 | } 62 | 63 | private void addWakeLock(WakeLockType type, int flags) { 64 | WakeLock full = mmPowerManager.newWakeLock(flags, WAKE_LOCK_TAG); 65 | full.setReferenceCounted(false); 66 | mmLocks.put(type, full); 67 | } 68 | 69 | @SuppressLint("Wakelock") 70 | public void acquire(WakeLockType type) { 71 | mmLocks.get(type).acquire(); 72 | for (Entry entry : mmLocks.entrySet()) { 73 | if (entry.getKey() != type) { 74 | entry.getValue().release(); 75 | } 76 | } 77 | } 78 | 79 | public void release() { 80 | for (Entry entry : mmLocks.entrySet()) { 81 | entry.getValue().release(); 82 | } 83 | } 84 | } 85 | 86 | private final WakeLockManager mManager; 87 | 88 | public WakeLockFacade(FacadeManager manager) { 89 | super(manager); 90 | mManager = new WakeLockManager(manager.getService()); 91 | } 92 | 93 | @Rpc(description = "Acquires a full wake lock (CPU on, screen bright, keyboard bright).") 94 | public void wakeLockAcquireFull() { 95 | mManager.acquire(WakeLockType.FULL); 96 | } 97 | 98 | @Rpc(description = "Acquires a partial wake lock (CPU on).") 99 | public void wakeLockAcquirePartial() { 100 | mManager.acquire(WakeLockType.PARTIAL); 101 | } 102 | 103 | @Rpc(description = "Acquires a bright wake lock (CPU on, screen bright).") 104 | public void wakeLockAcquireBright() { 105 | mManager.acquire(WakeLockType.BRIGHT); 106 | } 107 | 108 | @Rpc(description = "Acquires a dim wake lock (CPU on, screen dim).") 109 | public void wakeLockAcquireDim() { 110 | mManager.acquire(WakeLockType.DIM); 111 | } 112 | 113 | @Rpc(description = "Releases the wake lock.") 114 | public void wakeLockRelease() { 115 | mManager.release(); 116 | } 117 | 118 | @Override 119 | public void shutdown() { 120 | wakeLockRelease(); 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /src/main/java/org/qpython/qsl4a/qsl4a/facade/WifiFacade.java: -------------------------------------------------------------------------------- 1 | package org.qpython.qsl4a.qsl4a.facade; 2 | 3 | import android.app.Service; 4 | import android.content.Context; 5 | import android.net.wifi.ScanResult; 6 | import android.net.wifi.WifiInfo; 7 | import android.net.wifi.WifiManager; 8 | import android.net.wifi.WifiManager.WifiLock; 9 | 10 | 11 | import org.qpython.qsl4a.qsl4a.jsonrpc.RpcReceiver; 12 | import org.qpython.qsl4a.qsl4a.rpc.Rpc; 13 | import org.qpython.qsl4a.qsl4a.rpc.RpcOptional; 14 | import org.qpython.qsl4a.qsl4a.rpc.RpcParameter; 15 | 16 | import java.util.List; 17 | 18 | /** 19 | * Wifi functions. 20 | * 21 | */ 22 | public class WifiFacade extends RpcReceiver { 23 | 24 | private final Service mService; 25 | private final WifiManager mWifi; 26 | private WifiLock mLock; 27 | 28 | public WifiFacade(FacadeManager manager) { 29 | super(manager); 30 | mService = manager.getService(); 31 | mWifi = (WifiManager) mService.getApplicationContext().getSystemService(Context.WIFI_SERVICE); 32 | mLock = null; 33 | } 34 | 35 | private void makeLock(int wifiMode) { 36 | if (mLock == null) { 37 | mLock = mWifi.createWifiLock(wifiMode, "sl4a"); 38 | mLock.acquire(); 39 | } 40 | } 41 | 42 | @Rpc(description = "Returns the list of access points found during the most recent Wifi scan.") 43 | public List wifiGetScanResults() { 44 | return mWifi.getScanResults(); 45 | } 46 | 47 | @Rpc(description = "Acquires a full Wifi lock.") 48 | public void wifiLockAcquireFull() { 49 | makeLock(WifiManager.WIFI_MODE_FULL); 50 | } 51 | 52 | @Rpc(description = "Acquires a scan only Wifi lock.") 53 | public void wifiLockAcquireScanOnly() { 54 | makeLock(WifiManager.WIFI_MODE_SCAN_ONLY); 55 | } 56 | 57 | @Rpc(description = "Releases a previously acquired Wifi lock.") 58 | public void wifiLockRelease() { 59 | if (mLock != null) { 60 | mLock.release(); 61 | mLock = null; 62 | } 63 | } 64 | 65 | @Rpc(description = "Starts a scan for Wifi access points.", returns = "True if the scan was initiated successfully.") 66 | public Boolean wifiStartScan() { 67 | return mWifi.startScan(); 68 | } 69 | 70 | @Rpc(description = "Checks Wifi state.", returns = "True if Wifi is enabled.") 71 | public Boolean checkWifiState() { 72 | return mWifi.getWifiState() == WifiManager.WIFI_STATE_ENABLED; 73 | } 74 | 75 | @Rpc(description = "Toggle Wifi on and off.", returns = "True if Wifi is enabled.") 76 | public Boolean toggleWifiState(@RpcParameter(name = "enabled") @RpcOptional Boolean enabled) { 77 | if (enabled == null) { 78 | enabled = !checkWifiState(); 79 | } 80 | mWifi.setWifiEnabled(enabled); 81 | return enabled; 82 | } 83 | 84 | @Rpc(description = "Disconnects from the currently active access point.", returns = "True if the operation succeeded.") 85 | public Boolean wifiDisconnect() { 86 | return mWifi.disconnect(); 87 | } 88 | 89 | @Rpc(description = "Returns information about the currently active access point.") 90 | public WifiInfo wifiGetConnectionInfo() { 91 | return mWifi.getConnectionInfo(); 92 | } 93 | 94 | @Rpc(description = "Reassociates with the currently active access point.", returns = "True if the operation succeeded.") 95 | public Boolean wifiReassociate() { 96 | return mWifi.reassociate(); 97 | } 98 | 99 | @Rpc(description = "Reconnects to the currently active access point.", returns = "True if the operation succeeded.") 100 | public Boolean wifiReconnect() { 101 | return mWifi.reconnect(); 102 | } 103 | 104 | @Override 105 | public void shutdown() { 106 | wifiLockRelease(); 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /src/main/java/org/qpython/qsl4a/qsl4a/facade/ui/DatePickerDialogTask.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2010 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 | * use this file except in compliance with the License. You may obtain a copy of 6 | * the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations under 14 | * the License. 15 | */ 16 | 17 | package org.qpython.qsl4a.qsl4a.facade.ui; 18 | 19 | import android.app.DatePickerDialog; 20 | import android.content.DialogInterface; 21 | import android.util.AndroidRuntimeException; 22 | import android.widget.DatePicker; 23 | 24 | import org.json.JSONException; 25 | import org.json.JSONObject; 26 | 27 | /** 28 | * Wrapper class for date picker dialog running in separate thread. 29 | * 30 | * @author MeanEYE.rcf (meaneye.rcf@gmail.com) 31 | */ 32 | public class DatePickerDialogTask extends DialogTask { 33 | public static int mYear; 34 | public static int mMonth; 35 | public static int mDay; 36 | 37 | public DatePickerDialogTask(int year, int month, int day) { 38 | mYear = year; 39 | mMonth = month - 1; 40 | mDay = day; 41 | } 42 | 43 | @Override 44 | public void onCreate() { 45 | super.onCreate(); 46 | mDialog = new DatePickerDialog(getActivity(), new DatePickerDialog.OnDateSetListener() { 47 | @Override 48 | public void onDateSet(DatePicker view, int year, int month, int day) { 49 | JSONObject result = new JSONObject(); 50 | try { 51 | result.put("which", "positive"); 52 | result.put("year", year); 53 | result.put("month", month + 1); 54 | result.put("day", day); 55 | setResult(result); 56 | } catch (JSONException e) { 57 | throw new AndroidRuntimeException(e); 58 | } 59 | } 60 | }, mYear, mMonth, mDay); 61 | mDialog.setOnCancelListener(new DialogInterface.OnCancelListener() { 62 | @Override 63 | public void onCancel(DialogInterface view) { 64 | JSONObject result = new JSONObject(); 65 | try { 66 | result.put("which", "neutral"); 67 | result.put("year", mYear); 68 | result.put("month", mMonth + 1); 69 | result.put("day", mDay); 70 | setResult(result); 71 | } catch (JSONException e) { 72 | throw new AndroidRuntimeException(e); 73 | } 74 | } 75 | }); 76 | mDialog.setOnDismissListener(new DialogInterface.OnDismissListener() { 77 | @Override 78 | public void onDismiss(DialogInterface dialog) { 79 | JSONObject result = new JSONObject(); 80 | try { 81 | result.put("which", "negative"); 82 | result.put("year", mYear); 83 | result.put("month", mMonth + 1); 84 | result.put("day", mDay); 85 | setResult(result); 86 | } catch (JSONException e) { 87 | throw new AndroidRuntimeException(e); 88 | } 89 | } 90 | }); 91 | mDialog.show(); 92 | mShowLatch.countDown(); 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /src/main/java/org/qpython/qsl4a/qsl4a/facade/ui/DialogTask.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2010 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 | * use this file except in compliance with the License. You may obtain a copy of 6 | * the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations under 14 | * the License. 15 | */ 16 | 17 | package org.qpython.qsl4a.qsl4a.facade.ui; 18 | 19 | import android.app.Dialog; 20 | 21 | import org.qpython.qsl4a.qsl4a.facade.EventFacade; 22 | import org.qpython.qsl4a.qsl4a.future.FutureActivityTask; 23 | 24 | import java.util.concurrent.CountDownLatch; 25 | 26 | abstract class DialogTask extends FutureActivityTask { 27 | 28 | protected Dialog mDialog; 29 | private EventFacade mEventFacade; 30 | 31 | public EventFacade getEventFacade() { 32 | return mEventFacade; 33 | } 34 | 35 | public void setEventFacade(EventFacade mEventFacade) { 36 | this.mEventFacade = mEventFacade; 37 | } 38 | 39 | @Override 40 | protected void setResult(Object object) { 41 | super.setResult(object); 42 | EventFacade eventFacade = getEventFacade(); 43 | if (eventFacade != null) { 44 | eventFacade.postEvent("dialog", object); 45 | } 46 | } 47 | 48 | protected final CountDownLatch mShowLatch = new CountDownLatch(1); 49 | 50 | /** 51 | * Returns the wrapped {@link Dialog}. 52 | */ 53 | public Dialog getDialog() { 54 | return mDialog; 55 | } 56 | 57 | /** 58 | * Dismiss the {@link Dialog} and close {@link Sl4aActivity}. 59 | */ 60 | public void dismissDialog() { 61 | if (mDialog != null) { 62 | mDialog.dismiss(); 63 | finish(); 64 | } 65 | mDialog = null; 66 | } 67 | 68 | /** 69 | * Returns the {@link CountDownLatch} that is counted down when the dialog is shown. 70 | */ 71 | public CountDownLatch getShowLatch() { 72 | return mShowLatch; 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /src/main/java/org/qpython/qsl4a/qsl4a/facade/ui/ProgressDialogTask.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2010 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 | * use this file except in compliance with the License. You may obtain a copy of 6 | * the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations under 14 | * the License. 15 | */ 16 | 17 | package org.qpython.qsl4a.qsl4a.facade.ui; 18 | 19 | import android.app.ProgressDialog; 20 | 21 | /** 22 | * Wrapper class for progress dialog running in separate thread 23 | * 24 | * @author MeanEYE.rcf (meaneye.rcf@gmail.com) 25 | */ 26 | class ProgressDialogTask extends DialogTask { 27 | 28 | private final int mStyle; 29 | private final int mMax; 30 | private final String mTitle; 31 | private final String mMessage; 32 | private final Boolean mCancelable; 33 | 34 | public ProgressDialogTask(int style, int max, String title, String message, boolean cancelable) { 35 | mStyle = style; 36 | mMax = max; 37 | mTitle = title; 38 | mMessage = message; 39 | mCancelable = cancelable; 40 | } 41 | 42 | @Override 43 | public void onCreate() { 44 | super.onCreate(); 45 | mDialog = new ProgressDialog(getActivity()); 46 | ((ProgressDialog) mDialog).setProgressStyle(mStyle); 47 | ((ProgressDialog) mDialog).setMax(mMax); 48 | mDialog.setCancelable(mCancelable); 49 | mDialog.setTitle(mTitle); 50 | ((ProgressDialog) mDialog).setMessage(mMessage); 51 | mDialog.show(); 52 | mShowLatch.countDown(); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/main/java/org/qpython/qsl4a/qsl4a/facade/ui/TimePickerDialogTask.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2010 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 | * use this file except in compliance with the License. You may obtain a copy of 6 | * the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations under 14 | * the License. 15 | */ 16 | 17 | package org.qpython.qsl4a.qsl4a.facade.ui; 18 | 19 | import android.app.TimePickerDialog; 20 | import android.content.DialogInterface; 21 | import android.util.AndroidRuntimeException; 22 | import android.widget.TimePicker; 23 | 24 | import org.json.JSONException; 25 | import org.json.JSONObject; 26 | 27 | /** 28 | * Wrapper class for time picker dialog running in separate thread. 29 | * 30 | * @author MeanEYE.rcf (meaneye.rcf@gmail.com) 31 | */ 32 | public class TimePickerDialogTask extends DialogTask { 33 | private final int mHour; 34 | private final int mMinute; 35 | private final boolean mIs24Hour; 36 | 37 | public TimePickerDialogTask(int hour, int minute, boolean is24hour) { 38 | mHour = hour; 39 | mMinute = minute; 40 | mIs24Hour = is24hour; 41 | } 42 | 43 | @Override 44 | public void onCreate() { 45 | super.onCreate(); 46 | mDialog = new TimePickerDialog(getActivity(), new TimePickerDialog.OnTimeSetListener() { 47 | @Override 48 | public void onTimeSet(TimePicker view, int hour, int minute) { 49 | JSONObject result = new JSONObject(); 50 | try { 51 | result.put("which", "positive"); 52 | result.put("hour", hour); 53 | result.put("minute", minute); 54 | setResult(result); 55 | } catch (JSONException e) { 56 | throw new AndroidRuntimeException(e); 57 | } 58 | } 59 | }, mHour, mMinute, mIs24Hour); 60 | mDialog.setOnCancelListener(new DialogInterface.OnCancelListener() { 61 | @Override 62 | public void onCancel(DialogInterface view) { 63 | JSONObject result = new JSONObject(); 64 | try { 65 | result.put("which", "neutral"); 66 | result.put("hour", mHour); 67 | result.put("minute", mMinute); 68 | setResult(result); 69 | } catch (JSONException e) { 70 | throw new AndroidRuntimeException(e); 71 | } 72 | } 73 | }); 74 | mDialog.setOnDismissListener(new DialogInterface.OnDismissListener() { 75 | @Override 76 | public void onDismiss(DialogInterface dialog) { 77 | JSONObject result = new JSONObject(); 78 | try { 79 | result.put("which", "negative"); 80 | result.put("hour", mHour); 81 | result.put("minute", mMinute); 82 | setResult(result); 83 | } catch (JSONException e) { 84 | throw new AndroidRuntimeException(e); 85 | } 86 | } 87 | }); 88 | mDialog.show(); 89 | mShowLatch.countDown(); 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /src/main/java/org/qpython/qsl4a/qsl4a/future/FutureActivityTask.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2010 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 | * use this file except in compliance with the License. You may obtain a copy of 6 | * the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations under 14 | * the License. 15 | */ 16 | 17 | package org.qpython.qsl4a.qsl4a.future; 18 | 19 | import android.app.Activity; 20 | import android.content.Intent; 21 | import android.util.Log; 22 | import android.view.ContextMenu; 23 | import android.view.ContextMenu.ContextMenuInfo; 24 | import android.view.KeyEvent; 25 | import android.view.Menu; 26 | import android.view.View; 27 | import android.view.Window; 28 | 29 | import org.qpython.qsl4a.R; 30 | 31 | /** 32 | * Encapsulates an {@link Activity} and a {@link FutureObject}. 33 | * 34 | * @author Damon Kohler (damonkohler@gmail.com) 35 | */ 36 | public abstract class FutureActivityTask { 37 | 38 | final private String TAG = "FutureActivityTask"; 39 | private final FutureResult mResult = new FutureResult(); 40 | private Activity mActivity; 41 | 42 | public void setActivity(Activity activity) { 43 | mActivity = activity; 44 | } 45 | 46 | public Activity getActivity() { 47 | return mActivity; 48 | } 49 | 50 | public void onCreate() { 51 | Log.d(TAG, "onCreate"); 52 | mActivity.getWindow().requestFeature(Window.FEATURE_NO_TITLE); 53 | mActivity.setContentView(R.layout.activity_run_splash); 54 | 55 | } 56 | 57 | public void onStart() { 58 | Log.d(TAG, "onStart"); 59 | 60 | } 61 | 62 | public void onResume() { 63 | Log.d(TAG, "onResume"); 64 | 65 | } 66 | 67 | public void onPause() { 68 | Log.d(TAG, "onPause"); 69 | 70 | } 71 | 72 | public void onStop() { 73 | Log.d(TAG, "onStop"); 74 | 75 | } 76 | 77 | public void onDestroy() { 78 | Log.d(TAG, "onDestroy"); 79 | 80 | } 81 | 82 | public void onNewIntent(Intent intent) { 83 | } 84 | public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) { 85 | } 86 | 87 | public boolean onPrepareOptionsMenu(Menu menu) { 88 | return false; 89 | } 90 | 91 | public void onActivityResult(int requestCode, int resultCode, Intent data) { 92 | } 93 | 94 | protected void setResult(T result) { 95 | mResult.set(result); 96 | } 97 | 98 | public T getResult() throws InterruptedException { 99 | return mResult.get(); 100 | } 101 | 102 | public void finish() { 103 | mActivity.finish(); 104 | } 105 | 106 | public void startActivity(Intent intent) { 107 | mActivity.startActivity(intent); 108 | } 109 | 110 | public void startActivityForResult(Intent intent, int requestCode) { 111 | mActivity.startActivityForResult(intent, requestCode); 112 | } 113 | 114 | public boolean onKeyDown(int keyCode, KeyEvent event) { 115 | // Placeholder. 116 | return false; 117 | } 118 | } 119 | -------------------------------------------------------------------------------- /src/main/java/org/qpython/qsl4a/qsl4a/future/FutureResult.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2010 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 | * use this file except in compliance with the License. You may obtain a copy of 6 | * the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations under 14 | * the License. 15 | */ 16 | 17 | package org.qpython.qsl4a.qsl4a.future; 18 | 19 | import java.util.concurrent.CountDownLatch; 20 | import java.util.concurrent.Future; 21 | import java.util.concurrent.TimeUnit; 22 | 23 | /** 24 | * FutureResult represents an eventual execution result for asynchronous operations. 25 | * 26 | * @author Damon Kohler (damonkohler@gmail.com) 27 | */ 28 | public class FutureResult implements Future { 29 | 30 | private final CountDownLatch mLatch = new CountDownLatch(1); 31 | private volatile T mResult; 32 | 33 | public void set(T result) { 34 | mResult = result; 35 | mLatch.countDown(); 36 | } 37 | 38 | @Override 39 | public boolean cancel(boolean mayInterruptIfRunning) { 40 | return false; 41 | } 42 | 43 | @Override 44 | public T get() throws InterruptedException { 45 | mLatch.await(); 46 | return mResult; 47 | } 48 | 49 | @Override 50 | public T get(long timeout, TimeUnit unit) throws InterruptedException { 51 | mLatch.await(timeout, unit); 52 | return mResult; 53 | } 54 | 55 | @Override 56 | public boolean isCancelled() { 57 | return false; 58 | } 59 | 60 | @Override 61 | public boolean isDone() { 62 | return mResult != null; 63 | } 64 | 65 | } 66 | -------------------------------------------------------------------------------- /src/main/java/org/qpython/qsl4a/qsl4a/interpreter/ExternalClassLoader.java: -------------------------------------------------------------------------------- 1 | package org.qpython.qsl4a.qsl4a.interpreter; 2 | 3 | import org.qpython.qsl4a.qsl4a.StringUtils; 4 | 5 | import dalvik.system.DexClassLoader; 6 | 7 | import java.util.Collection; 8 | 9 | public class ExternalClassLoader { 10 | 11 | public Object load(Collection dexPaths, Collection nativePaths, String className) 12 | throws Exception { 13 | String dexOutputDir = "/sdcard/dexoutput"; 14 | String joinedDexPaths = StringUtils.join(dexPaths, ":"); 15 | String joinedNativeLibPaths = nativePaths != null ? StringUtils.join(nativePaths, ":") : null; 16 | DexClassLoader loader = 17 | new DexClassLoader(joinedDexPaths, dexOutputDir, joinedNativeLibPaths, this.getClass() 18 | .getClassLoader()); 19 | Class classToLoad = Class.forName(className, true, loader); 20 | return classToLoad.newInstance(); 21 | } 22 | } -------------------------------------------------------------------------------- /src/main/java/org/qpython/qsl4a/qsl4a/interpreter/InProcessInterpreter.java: -------------------------------------------------------------------------------- 1 | package org.qpython.qsl4a.qsl4a.interpreter; 2 | 3 | import java.io.FileDescriptor; 4 | 5 | public interface InProcessInterpreter { 6 | public FileDescriptor getStdOut(); 7 | 8 | public FileDescriptor getStdIn(); 9 | 10 | public boolean runInteractive(); 11 | 12 | public void runScript(String filename); 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/org/qpython/qsl4a/qsl4a/interpreter/InterpreterConstants.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2010 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 | * use this file except in compliance with the License. You may obtain a copy of 6 | * the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations under 14 | * the License. 15 | */ 16 | 17 | package org.qpython.qsl4a.qsl4a.interpreter; 18 | 19 | import android.os.Environment; 20 | 21 | import com.quseit.util.FileUtils; 22 | 23 | /** 24 | * A collection of constants required for installation/removal of an interpreter. 25 | * 26 | * @author Damon Kohler (damonkohler@gmail.com) 27 | * @author Alexey Reznichenko (alexey.reznichenko@gmail.com) 28 | */ 29 | public interface InterpreterConstants { 30 | 31 | // public static final String SDCARD_ROOT = Environment.getExternalStorageDirectory().getAbsolutePath() + "/"; 32 | 33 | // public static final String SDCARD_SL4A_ROOT = SDCARD_ROOT + "sl4a/"; 34 | 35 | // public static final String SCRIPTS_ROOT = SDCARD_SL4A_ROOT + "scripts/"; 36 | 37 | // public static final String SDCARD_SL4A_DOC = SDCARD_SL4A_ROOT + "doc/"; 38 | 39 | // public static final String SL4A_DALVIK_CACHE_ROOT = "/dalvik-cache/"; 40 | 41 | public static final String INTERPRETER_EXTRAS_ROOT = "/extras/"; 42 | 43 | // Interpreters discovery mechanism. 44 | public static final String ACTION_DISCOVER_INTERPRETERS = 45 | "com.googlecode.android_scripting.DISCOVER_INTERPRETERS"; 46 | 47 | // Interpreters broadcasts. 48 | public static final String ACTION_INTERPRETER_ADDED = 49 | "com.googlecode.android_scripting.INTERPRETER_ADDED"; 50 | public static final String ACTION_INTERPRETER_REMOVED = 51 | "com.googlecode.android_scripting.INTERPRETER_REMOVED"; 52 | 53 | // Interpreter content provider. 54 | public static final String PROVIDER_PROPERTIES = "com.googlecode.android_scripting.base"; 55 | public static final String PROVIDER_ENVIRONMENT_VARIABLES = 56 | "com.googlecode.android_scripting.env"; 57 | public static final String PROVIDER_ARGUMENTS = "com.googlecode.android_scripting.args"; 58 | 59 | public static final String INSTALLED_PREFERENCE_KEY = "SL4A.interpreter.installed"; 60 | 61 | public static final String MIME = "script/"; 62 | } 63 | -------------------------------------------------------------------------------- /src/main/java/org/qpython/qsl4a/qsl4a/interpreter/InterpreterDescriptor.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2010 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 | * use this file except in compliance with the License. You may obtain a copy of 6 | * the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations under 14 | * the License. 15 | */ 16 | 17 | package org.qpython.qsl4a.qsl4a.interpreter; 18 | 19 | import android.content.Context; 20 | 21 | import java.io.File; 22 | import java.util.List; 23 | import java.util.Map; 24 | 25 | /** 26 | * Provides interpreter-specific info for execution/installation/removal purposes. 27 | * 28 | * @author Alexey Reznichenko (alexey.reznichenko@gmail.com) 29 | */ 30 | public interface InterpreterDescriptor { 31 | 32 | /** 33 | * Returns unique name of the interpreter. 34 | */ 35 | public String getName(); 36 | 37 | /** 38 | * Returns display name of the interpreter. 39 | */ 40 | public String getNiceName(); 41 | 42 | /** 43 | * Returns supported script-file extension. 44 | */ 45 | public String getExtension(); 46 | 47 | /** 48 | * Returns interpreter version number. 49 | */ 50 | public int getVersion(); 51 | 52 | /** 53 | * Returns the binary as a File object. Context is the InterpreterProvider's {@link Context} and 54 | * is provided to find the interpreter installation directory. 55 | */ 56 | public File getBinary(Context context); 57 | 58 | /** 59 | * Returns execution parameters in case when script name is not provided (when interpreter is 60 | * started in a shell mode); 61 | */ 62 | public String getInteractiveCommand(Context context); 63 | 64 | /** 65 | * Returns command line arguments to execute a with a given script (format string with one 66 | * argument). 67 | */ 68 | public String getScriptCommand(Context context); 69 | 70 | /** 71 | * Returns an array of command line arguments required to execute the interpreter (it's essential 72 | * that the order in the array is consistent with order of arguments in the command line). 73 | */ 74 | public List getArguments(Context context); 75 | 76 | /** 77 | * Should return a map of environment variables names and their values (or null if interpreter 78 | * does not require any environment variables). 79 | */ 80 | public Map getEnvironmentVariables(Context context); 81 | 82 | /** 83 | * Returns true if interpreter has an archive. 84 | */ 85 | public boolean hasInterpreterArchive(); 86 | 87 | /** 88 | * Returns true if interpreter has an extras archive. 89 | */ 90 | public boolean hasExtrasArchive(); 91 | 92 | /** 93 | * Returns true if interpreter comes with a scripts archive. 94 | */ 95 | public boolean hasScriptsArchive(); 96 | 97 | /** 98 | * Returns file name of the interpreter archive. 99 | */ 100 | public String getInterpreterArchiveName(); 101 | 102 | /** 103 | * Returns file name of the extras archive. 104 | */ 105 | public String getExtrasArchiveName(); 106 | 107 | /** 108 | * Returns file name of the scripts archive. 109 | */ 110 | public String getScriptsArchiveName(); 111 | 112 | /** 113 | * Returns URL location of the interpreter archive. 114 | */ 115 | public String getInterpreterArchiveUrl(); 116 | 117 | /** 118 | * Returns URL location of the scripts archive. 119 | */ 120 | public String getScriptsArchiveUrl(); 121 | 122 | /** 123 | * Returns URL location of the extras archive. 124 | */ 125 | public String getExtrasArchiveUrl(); 126 | 127 | /** 128 | * Returns true if interpreter can be executed in interactive mode. 129 | */ 130 | public boolean hasInteractiveMode(); 131 | } 132 | -------------------------------------------------------------------------------- /src/main/java/org/qpython/qsl4a/qsl4a/interpreter/InterpreterProcess.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2009 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 | * use this file except in compliance with the License. You may obtain a copy of 6 | * the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations under 14 | * the License. 15 | */ 16 | 17 | package org.qpython.qsl4a.qsl4a.interpreter; 18 | 19 | import android.content.Context; 20 | 21 | import org.qpython.qsl4a.qsl4a.Analytics; 22 | import org.qpython.qsl4a.qsl4a.AndroidProxy; 23 | import org.qpython.qsl4a.qsl4a.FileUtils; 24 | import org.qpython.qsl4a.qsl4a.LogUtil; 25 | import org.qpython.qsl4a.qsl4a.Process; 26 | import org.qpython.qsl4a.qsl4a.SimpleServer; 27 | import org.qpython.qsl4a.qsl4a.jsonrpc.RpcReceiverManagerFactory; 28 | 29 | import java.net.InetSocketAddress; 30 | import java.net.SocketException; 31 | import java.net.UnknownHostException; 32 | 33 | /** 34 | * This is a skeletal implementation of an interpreter process. 35 | * 36 | * @author Damon Kohler (damonkohler@gmail.com) 37 | */ 38 | public class InterpreterProcess extends Process { 39 | 40 | private final AndroidProxy mProxy; 41 | private final Interpreter mInterpreter; 42 | private String mCommand; 43 | 44 | /** 45 | * Creates a new {@link InterpreterProcess}. 46 | * 47 | * @param launchScript 48 | * the absolute path to a script that should be launched with the interpreter 49 | * @param port 50 | * the port that the AndroidProxy is listening on 51 | */ 52 | public InterpreterProcess(Interpreter interpreter, AndroidProxy proxy) { 53 | mProxy = proxy; 54 | mInterpreter = interpreter; 55 | 56 | setBinary(interpreter.getBinary()); 57 | setName(interpreter.getNiceName()); 58 | setCommand(interpreter.getInteractiveCommand()); 59 | addAllArguments(interpreter.getArguments()); 60 | putAllEnvironmentVariables(System.getenv()); 61 | putEnvironmentVariable("AP_HOST", getHost()); 62 | putEnvironmentVariable("AP_PORT", Integer.toString(getPort())); 63 | if (proxy.getSecret() != null) { 64 | putEnvironmentVariable("AP_HANDSHAKE", getSecret()); 65 | } 66 | putAllEnvironmentVariables(interpreter.getEnvironmentVariables()); 67 | } 68 | 69 | protected void setCommand(String command) { 70 | mCommand = command; 71 | } 72 | 73 | public Interpreter getInterpreter() { 74 | return mInterpreter; 75 | } 76 | 77 | public String getHost() { 78 | String result = mProxy.getAddress().getHostName(); 79 | if (result.equals("0.0.0.0")) { // Wildcard. 80 | try { 81 | return SimpleServer.getPublicInetAddress().getHostName(); 82 | } catch (UnknownHostException e) { 83 | LogUtil.i("public address", e); 84 | e.printStackTrace(); 85 | } catch (SocketException e) { 86 | LogUtil.i("public address", e); 87 | } 88 | } 89 | return result; 90 | } 91 | 92 | public int getPort() { 93 | return mProxy.getAddress().getPort(); 94 | } 95 | 96 | public InetSocketAddress getAddress() { 97 | return mProxy.getAddress(); 98 | } 99 | 100 | public String getSecret() { 101 | return mProxy.getSecret(); 102 | } 103 | 104 | public RpcReceiverManagerFactory getRpcReceiverManagerFactory() { 105 | return mProxy.getRpcReceiverManagerFactory(); 106 | } 107 | 108 | @Override 109 | public void start(Context context, final Runnable shutdownHook) { 110 | Analytics.track(mInterpreter.getName()); 111 | // NOTE(damonkohler): String.isEmpty() doesn't work on Cupcake. 112 | if (!mCommand.equals("")) { 113 | addArgument(mCommand); 114 | } 115 | super.start(context,shutdownHook); 116 | } 117 | 118 | @Override 119 | public void kill() { 120 | super.kill(); 121 | mProxy.shutdown(); 122 | } 123 | 124 | @Override 125 | public String getWorkingDirectory(Context context) { 126 | return FileUtils.getScriptsRootPath(context); 127 | } 128 | } -------------------------------------------------------------------------------- /src/main/java/org/qpython/qsl4a/qsl4a/interpreter/InterpreterPropertyNames.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2010 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 | * use this file except in compliance with the License. You may obtain a copy of 6 | * the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations under 14 | * the License. 15 | */ 16 | 17 | package org.qpython.qsl4a.qsl4a.interpreter; 18 | 19 | /** 20 | * A collection of {@link String} keys for querying an InterpreterProvider. 21 | * 22 | * @author Alexey Reznichenko (alexey.reznichenko@gmail.com) 23 | */ 24 | public interface InterpreterPropertyNames { 25 | 26 | /** 27 | * Unique name of the interpreter. 28 | */ 29 | public static final String NAME = "name"; 30 | 31 | /** 32 | * Display name of the interpreter. 33 | */ 34 | public static final String NICE_NAME = "niceName"; 35 | 36 | /** 37 | * Supported script file extension. 38 | */ 39 | public static final String EXTENSION = "extension"; 40 | 41 | /** 42 | * Absolute path of the interpreter executable. 43 | */ 44 | public static final String BINARY = "binary"; 45 | 46 | /** 47 | * Final argument to interpreter binary when running the interpreter interactively. 48 | */ 49 | public static final String INTERACTIVE_COMMAND = "interactiveCommand"; 50 | 51 | /** 52 | * Final argument to interpreter binary when running a script. 53 | */ 54 | public static final String SCRIPT_COMMAND = "scriptCommand"; 55 | 56 | /** 57 | * Interpreter interactive mode flag. 58 | */ 59 | public static final String HAS_INTERACTIVE_MODE = "hasInteractiveMode"; 60 | 61 | } 62 | -------------------------------------------------------------------------------- /src/main/java/org/qpython/qsl4a/qsl4a/interpreter/InterpreterUtils.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2010 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 | * use this file except in compliance with the License. You may obtain a copy of 6 | * the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations under 14 | * the License. 15 | */ 16 | 17 | package org.qpython.qsl4a.qsl4a.interpreter; 18 | 19 | import android.content.Context; 20 | 21 | import java.io.File; 22 | 23 | public class InterpreterUtils { 24 | 25 | private InterpreterUtils() { 26 | // Utility class 27 | } 28 | 29 | public static File getInterpreterRoot(Context context) { 30 | return context.getFilesDir(); 31 | } 32 | 33 | public static File getInterpreterRoot(Context context, String interpreterName) { 34 | return new File(getInterpreterRoot(context), interpreterName); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/org/qpython/qsl4a/qsl4a/interpreter/MyInterpreter.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2010 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 | * use this file except in compliance with the License. You may obtain a copy of 6 | * the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations under 14 | * the License. 15 | */ 16 | 17 | package org.qpython.qsl4a.qsl4a.interpreter; 18 | 19 | import java.util.List; 20 | 21 | /** 22 | * Wrapper for the Interpreter class. 23 | * 24 | * Workaround for the default access modifier on the getArguments() method 25 | * in the Interpreter class 26 | */ 27 | public class MyInterpreter { 28 | private Interpreter interpreter; 29 | 30 | public MyInterpreter(Interpreter interpreter){ 31 | this.interpreter = interpreter; 32 | } 33 | 34 | public Interpreter getInterpreter() { 35 | return this.interpreter; 36 | } 37 | 38 | public List getArguments() { 39 | return interpreter.getArguments(); 40 | } 41 | } -------------------------------------------------------------------------------- /src/main/java/org/qpython/qsl4a/qsl4a/interpreter/html/HtmlInterpreter.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2010 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 | * use this file except in compliance with the License. You may obtain a copy of 6 | * the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations under 14 | * the License. 15 | */ 16 | 17 | package org.qpython.qsl4a.qsl4a.interpreter.html; 18 | 19 | import android.content.Context; 20 | 21 | import org.qpython.qsl4a.qsl4a.FileUtils; 22 | import org.qpython.qsl4a.qsl4a.interpreter.Interpreter; 23 | import org.qpython.qsl4a.qsl4a.language.HtmlLanguage; 24 | 25 | import java.io.IOException; 26 | 27 | public class HtmlInterpreter extends Interpreter { 28 | 29 | public static final String HTML = "html"; 30 | public static final String HTML_EXTENSION = ".html"; 31 | 32 | public static final String JSON_FILE = "json2.js"; 33 | public static final String ANDROID_JS_FILE = "android.js"; 34 | public static final String TEMPLATE_FILE = "webapp.html"; 35 | 36 | public static final String HTML_NICE_NAME = "HTML and JavaScript"; 37 | 38 | private final String mJson; 39 | private final String mAndroidJs; 40 | private final String mTemplate; 41 | 42 | 43 | public HtmlInterpreter(Context context) throws IOException { 44 | setExtension(HTML_EXTENSION); 45 | setName(HTML); 46 | setNiceName(HTML_NICE_NAME); 47 | setInteractiveCommand(""); 48 | setScriptCommand("%s"); 49 | setLanguage(new HtmlLanguage()); 50 | setHasInteractiveMode(false); 51 | mJson = FileUtils.readFromAssetsFile(context, JSON_FILE); 52 | mAndroidJs = FileUtils.readFromAssetsFile(context, ANDROID_JS_FILE); 53 | mTemplate = FileUtils.readFromAssetsFile(context, TEMPLATE_FILE); 54 | } 55 | 56 | public boolean hasInterpreterArchive() { 57 | return false; 58 | } 59 | 60 | public boolean hasExtrasArchive() { 61 | return false; 62 | } 63 | 64 | public boolean hasScriptsArchive() { 65 | return false; 66 | } 67 | 68 | public int getVersion() { 69 | return 0; 70 | } 71 | 72 | @Override 73 | public boolean isUninstallable() { 74 | return false; 75 | } 76 | 77 | @Override 78 | public boolean isInstalled() { 79 | return true; 80 | } 81 | 82 | public String getJsonSource() { 83 | return mJson; 84 | } 85 | 86 | public String getAndroidJsSource() { 87 | return mAndroidJs; 88 | } 89 | public String getTemplateSource() { 90 | return mTemplate; 91 | } 92 | 93 | } 94 | -------------------------------------------------------------------------------- /src/main/java/org/qpython/qsl4a/qsl4a/interpreter/shell/ShellInterpreter.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2009 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 | * use this file except in compliance with the License. You may obtain a copy of 6 | * the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations under 14 | * the License. 15 | */ 16 | 17 | package org.qpython.qsl4a.qsl4a.interpreter.shell; 18 | 19 | import org.qpython.qsl4a.qsl4a.interpreter.Interpreter; 20 | import org.qpython.qsl4a.qsl4a.language.ShellLanguage; 21 | 22 | import java.io.File; 23 | 24 | /** 25 | * Represents the shell. 26 | * 27 | * @author Damon Kohler (damonkohler@gmail.com) 28 | */ 29 | public class ShellInterpreter extends Interpreter { 30 | private final static String SHELL_BIN = "/system/bin/sh"; 31 | 32 | public ShellInterpreter() { 33 | setExtension(".sh"); 34 | setName("sh"); 35 | setNiceName("Shell"); 36 | setBinary(new File(SHELL_BIN)); 37 | setInteractiveCommand(""); 38 | setScriptCommand("%s"); 39 | setLanguage(new ShellLanguage()); 40 | setHasInteractiveMode(true); 41 | } 42 | 43 | public boolean hasInterpreterArchive() { 44 | return false; 45 | } 46 | 47 | public boolean hasExtrasArchive() { 48 | return false; 49 | } 50 | 51 | public boolean hasScriptsArchive() { 52 | return false; 53 | } 54 | 55 | public int getVersion() { 56 | return 0; 57 | } 58 | 59 | @Override 60 | public boolean isUninstallable() { 61 | return false; 62 | } 63 | 64 | @Override 65 | public boolean isInstalled() { 66 | return true; 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /src/main/java/org/qpython/qsl4a/qsl4a/jsonrpc/JsonRpcResult.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2009 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 | * use this file except in compliance with the License. You may obtain a copy of 6 | * the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations under 14 | * the License. 15 | */ 16 | 17 | package org.qpython.qsl4a.qsl4a.jsonrpc; 18 | 19 | import org.json.JSONException; 20 | import org.json.JSONObject; 21 | 22 | /** 23 | * Represents a JSON RPC result. 24 | * 25 | * @see http://json-rpc.org/wiki/specification 26 | * 27 | * @author Damon Kohler (damonkohler@gmail.com) 28 | */ 29 | public class JsonRpcResult { 30 | 31 | private JsonRpcResult() { 32 | // Utility class. 33 | } 34 | 35 | public static JSONObject empty(int id) throws JSONException { 36 | JSONObject json = new JSONObject(); 37 | json.put("id", id); 38 | json.put("result", JSONObject.NULL); 39 | json.put("error", JSONObject.NULL); 40 | return json; 41 | } 42 | 43 | public static JSONObject result(int id, Object data) throws JSONException { 44 | JSONObject json = new JSONObject(); 45 | json.put("id", id); 46 | json.put("result", JsonBuilder.build(data)); 47 | json.put("error", JSONObject.NULL); 48 | return json; 49 | } 50 | 51 | public static JSONObject error(int id, Throwable t) throws JSONException { 52 | JSONObject json = new JSONObject(); 53 | json.put("id", id); 54 | json.put("result", JSONObject.NULL); 55 | json.put("error", t.toString()); 56 | return json; 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/main/java/org/qpython/qsl4a/qsl4a/jsonrpc/JsonRpcServer.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2009 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 | * use this file except in compliance with the License. You may obtain a copy of 6 | * the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations under 14 | * the License. 15 | */ 16 | 17 | package org.qpython.qsl4a.qsl4a.jsonrpc; 18 | 19 | import org.qpython.qsl4a.qsl4a.LogUtil; 20 | import org.qpython.qsl4a.qsl4a.SimpleServer; 21 | import org.qpython.qsl4a.qsl4a.rpc.MethodDescriptor; 22 | import org.qpython.qsl4a.qsl4a.rpc.RpcError; 23 | 24 | import java.io.BufferedReader; 25 | import java.io.InputStreamReader; 26 | import java.io.PrintWriter; 27 | import java.net.Socket; 28 | 29 | import org.json.JSONArray; 30 | import org.json.JSONException; 31 | import org.json.JSONObject; 32 | 33 | /** 34 | * A JSON RPC server that forwards RPC calls to a specified receiver object. 35 | * 36 | * @author Damon Kohler (damonkohler@gmail.com) 37 | */ 38 | public class JsonRpcServer extends SimpleServer { 39 | 40 | private final RpcReceiverManagerFactory mRpcReceiverManagerFactory; 41 | private final String mHandshake; 42 | 43 | /** 44 | * Construct a {@link JsonRpcServer} connected to the provided {@link RpcReceiverManager}. 45 | * 46 | * @param managerFactory 47 | * the {@link RpcReceiverManager} to register with the server 48 | * @param handshake 49 | * the secret handshake required for authorization to use this server 50 | */ 51 | public JsonRpcServer(RpcReceiverManagerFactory managerFactory, String handshake) { 52 | mHandshake = handshake; 53 | mRpcReceiverManagerFactory = managerFactory; 54 | } 55 | 56 | @Override 57 | public void shutdown() { 58 | super.shutdown(); 59 | // Notify all RPC receiving objects. They may have to clean up some of their state. 60 | for (RpcReceiverManager manager : mRpcReceiverManagerFactory.getRpcReceiverManagers()) { 61 | manager.shutdown(); 62 | } 63 | } 64 | 65 | @Override 66 | protected void handleConnection(Socket socket) throws Exception { 67 | RpcReceiverManager receiverManager = mRpcReceiverManagerFactory.create(); 68 | BufferedReader reader = 69 | new BufferedReader(new InputStreamReader(socket.getInputStream()), 8192); 70 | PrintWriter writer = new PrintWriter(socket.getOutputStream(), true); 71 | boolean passedAuthentication = false; 72 | String data; 73 | while ((data = reader.readLine()) != null) { 74 | LogUtil.v("Received: " + data); 75 | JSONObject request = new JSONObject(data); 76 | int id = request.getInt("id"); 77 | String method = request.getString("method"); 78 | JSONArray params = request.getJSONArray("params"); 79 | 80 | // First RPC must be _authenticate if a handshake was specified. 81 | if (!passedAuthentication && mHandshake != null) { 82 | if (!checkHandshake(method, params)) { 83 | SecurityException exception = new SecurityException("Authentication failed!"); 84 | send(writer, JsonRpcResult.error(id, exception)); 85 | shutdown(); 86 | throw exception; 87 | } 88 | passedAuthentication = true; 89 | send(writer, JsonRpcResult.result(id, true)); 90 | continue; 91 | } 92 | 93 | MethodDescriptor rpc = receiverManager.getMethodDescriptor(method); 94 | if (rpc == null) { 95 | send(writer, JsonRpcResult.error(id, new RpcError("Unknown RPC:"+method))); 96 | continue; 97 | } 98 | try { 99 | send(writer, JsonRpcResult.result(id, rpc.invoke(receiverManager, params))); 100 | } catch (Throwable t) { 101 | LogUtil.e("Invocation error.", t); 102 | send(writer, JsonRpcResult.error(id, t)); 103 | } 104 | } 105 | } 106 | 107 | private boolean checkHandshake(String method, JSONArray params) throws JSONException { 108 | if (!method.equals("_authenticate") || !mHandshake.equals(params.getString(0))) { 109 | return false; 110 | } 111 | return true; 112 | } 113 | 114 | private void send(PrintWriter writer, JSONObject result) { 115 | writer.write(result + "\n"); 116 | writer.flush(); 117 | LogUtil.v("Sent: " + result); 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /src/main/java/org/qpython/qsl4a/qsl4a/jsonrpc/RpcReceiver.java: -------------------------------------------------------------------------------- 1 | // Copyright 2010 Google Inc. All Rights Reserved. 2 | 3 | package org.qpython.qsl4a.qsl4a.jsonrpc; 4 | 5 | public abstract class RpcReceiver { 6 | 7 | protected final RpcReceiverManager mManager; 8 | 9 | public RpcReceiver(RpcReceiverManager manager) { 10 | // To make reflection easier, we ensures that all the subclasses agree on this common 11 | // constructor. 12 | mManager = manager; 13 | } 14 | 15 | /** Invoked when the receiver is shut down. */ 16 | public abstract void shutdown(); 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/org/qpython/qsl4a/qsl4a/jsonrpc/RpcReceiverManager.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2010 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 | * use this file except in compliance with the License. You may obtain a copy of 6 | * the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations under 14 | * the License. 15 | */ 16 | 17 | package org.qpython.qsl4a.qsl4a.jsonrpc; 18 | 19 | import org.qpython.qsl4a.qsl4a.LogUtil; 20 | import org.qpython.qsl4a.qsl4a.rpc.MethodDescriptor; 21 | 22 | import java.lang.reflect.Constructor; 23 | import java.lang.reflect.Method; 24 | import java.util.Collection; 25 | import java.util.HashMap; 26 | import java.util.Map; 27 | 28 | public abstract class RpcReceiverManager { 29 | 30 | private final Map, RpcReceiver> mReceivers; 31 | 32 | /** 33 | * A map of strings to known RPCs. 34 | */ 35 | private final Map mKnownRpcs = new HashMap(); 36 | 37 | public RpcReceiverManager(Collection> classList) { 38 | mReceivers = new HashMap, RpcReceiver>(); 39 | for (Class receiverClass : classList) { 40 | mReceivers.put(receiverClass, null); 41 | Collection methodList = MethodDescriptor.collectFrom(receiverClass); 42 | for (MethodDescriptor m : methodList) { 43 | if (mKnownRpcs.containsKey(m.getName())) { 44 | // We already know an RPC of the same name. We don't catch this anywhere because this is a 45 | // programming error. 46 | throw new RuntimeException("An RPC with the name " + m.getName() + " is already known."); 47 | } 48 | mKnownRpcs.put(m.getName(), m); 49 | } 50 | } 51 | } 52 | 53 | public Collection> getRpcReceiverClasses() { 54 | return mReceivers.keySet(); 55 | } 56 | 57 | private RpcReceiver get(Class clazz) { 58 | RpcReceiver object = mReceivers.get(clazz); 59 | if (object != null) { 60 | return object; 61 | } 62 | 63 | Constructor constructor; 64 | try { 65 | constructor = clazz.getConstructor(getClass()); 66 | object = constructor.newInstance(this); 67 | mReceivers.put(clazz, object); 68 | } catch (Exception e) { 69 | LogUtil.e(e); 70 | } 71 | 72 | return object; 73 | } 74 | 75 | public T getReceiver(Class clazz) { 76 | RpcReceiver receiver = get(clazz); 77 | return clazz.cast(receiver); 78 | } 79 | 80 | public MethodDescriptor getMethodDescriptor(String methodName) { 81 | return mKnownRpcs.get(methodName); 82 | } 83 | 84 | public Object invoke(Class clazz, Method method, Object[] args) 85 | throws Exception { 86 | RpcReceiver object = get(clazz); 87 | return method.invoke(object, args); 88 | } 89 | 90 | public void shutdown() { 91 | for (RpcReceiver receiver : mReceivers.values()) { 92 | if (receiver != null) { 93 | receiver.shutdown(); 94 | } 95 | } 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /src/main/java/org/qpython/qsl4a/qsl4a/jsonrpc/RpcReceiverManagerFactory.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2010 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 | * use this file except in compliance with the License. You may obtain a copy of 6 | * the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations under 14 | * the License. 15 | */ 16 | 17 | package org.qpython.qsl4a.qsl4a.jsonrpc; 18 | 19 | import java.util.List; 20 | 21 | public interface RpcReceiverManagerFactory { 22 | public RpcReceiverManager create(); 23 | 24 | public List getRpcReceiverManagers(); 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/org/qpython/qsl4a/qsl4a/language/BeanShellLanguage.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2010 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 | * use this file except in compliance with the License. You may obtain a copy of 6 | * the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations under 14 | * the License. 15 | */ 16 | 17 | package org.qpython.qsl4a.qsl4a.language; 18 | 19 | 20 | import org.qpython.qsl4a.qsl4a.rpc.ParameterDescriptor; 21 | 22 | /** 23 | * Represents the BeanShell programming language. 24 | * 25 | * @author igor.v.karp@gmail.com (Igor Karp) 26 | */ 27 | public class BeanShellLanguage extends Language { 28 | 29 | @Override 30 | protected String getImportStatement() { 31 | // FIXME(igor.v.karp): this is interpreter specific 32 | return "source(\"/sdcard/com.googlecode.bshforandroid/extras/bsh/android.bsh\");\n"; 33 | } 34 | 35 | @Override 36 | protected String getRpcReceiverDeclaration(String rpcReceiver) { 37 | return rpcReceiver + " = Android();\n"; 38 | } 39 | 40 | @Override 41 | protected String getMethodCallText(String receiver, String method, 42 | ParameterDescriptor[] parameters) { 43 | StringBuilder result = 44 | new StringBuilder().append(getApplyReceiverText(receiver)).append(getApplyOperatorText()) 45 | .append(method); 46 | if (parameters.length > 0) { 47 | result.append(getLeftParametersText()); 48 | } else { 49 | result.append(getQuote()); 50 | } 51 | String separator = ""; 52 | for (ParameterDescriptor parameter : parameters) { 53 | result.append(separator).append(getValueText(parameter)); 54 | separator = getParameterSeparator(); 55 | } 56 | result.append(getRightParametersText()); 57 | 58 | return result.toString(); 59 | } 60 | 61 | @Override 62 | protected String getApplyOperatorText() { 63 | return ".call(\""; 64 | } 65 | 66 | @Override 67 | protected String getLeftParametersText() { 68 | return "\", "; 69 | } 70 | 71 | @Override 72 | protected String getRightParametersText() { 73 | return ")"; 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /src/main/java/org/qpython/qsl4a/qsl4a/language/HtmlLanguage.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2010 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 | * use this file except in compliance with the License. You may obtain a copy of 6 | * the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations under 14 | * the License. 15 | */ 16 | 17 | package org.qpython.qsl4a.qsl4a.language; 18 | 19 | 20 | import org.qpython.qsl4a.qsl4a.rpc.ParameterDescriptor; 21 | 22 | public class HtmlLanguage extends Language { 23 | 24 | /** Returns the Android package import statement. */ 25 | @Override 26 | protected String getImportStatement() { 27 | return "\n\n\n\n\n\n\n", 33 | rpcReceiver); 34 | } 35 | 36 | @Override 37 | protected String getMethodCallText(String receiver, String method, 38 | ParameterDescriptor[] parameters) { 39 | StringBuilder result = 40 | new StringBuilder().append(getApplyReceiverText(receiver)).append(getApplyOperatorText()) 41 | .append(method); 42 | if (parameters.length > 0) { 43 | result.append(getLeftParametersText()); 44 | } else { 45 | result.append(getQuote()); 46 | } 47 | String separator = ""; 48 | for (ParameterDescriptor parameter : parameters) { 49 | result.append(separator).append(getValueText(parameter)); 50 | separator = getParameterSeparator(); 51 | } 52 | result.append(getRightParametersText()); 53 | 54 | return result.toString(); 55 | } 56 | 57 | @Override 58 | protected String getApplyOperatorText() { 59 | return ".call('"; 60 | } 61 | 62 | @Override 63 | protected String getLeftParametersText() { 64 | return "', "; 65 | } 66 | 67 | @Override 68 | protected String getRightParametersText() { 69 | return ")"; 70 | } 71 | 72 | @Override 73 | protected String getQuote() { 74 | return "'"; 75 | } 76 | 77 | } 78 | -------------------------------------------------------------------------------- /src/main/java/org/qpython/qsl4a/qsl4a/language/JavaScriptLanguage.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2010 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 | * use this file except in compliance with the License. You may obtain a copy of 6 | * the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations under 14 | * the License. 15 | */ 16 | 17 | package org.qpython.qsl4a.qsl4a.language; 18 | 19 | /** 20 | * Represents the JavaScript programming language. 21 | * 22 | * @author igor.v.karp@gmail.com (Igor Karp) 23 | */ 24 | public class JavaScriptLanguage extends Language { 25 | 26 | @Override 27 | protected String getImportStatement() { 28 | // FIXME(igor.v.karp): this is interpreter specific 29 | return "load(\"file:///android_asset/android.js\");\n"; 30 | } 31 | 32 | @Override 33 | protected String getRpcReceiverDeclaration(String rpcReceiver) { 34 | return "var " + rpcReceiver + " = Android();\n"; 35 | } 36 | 37 | } 38 | -------------------------------------------------------------------------------- /src/main/java/org/qpython/qsl4a/qsl4a/language/LuaLanguage.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2010 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 | * use this file except in compliance with the License. You may obtain a copy of 6 | * the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations under 14 | * the License. 15 | */ 16 | 17 | package org.qpython.qsl4a.qsl4a.language; 18 | 19 | /** 20 | * Represents the Lua programming language. 21 | * 22 | * @author igor.v.karp@gmail.com (Igor Karp) 23 | */ 24 | public class LuaLanguage extends Language { 25 | 26 | @Override 27 | protected String getImportStatement() { 28 | return "require \"android\"\n"; 29 | } 30 | 31 | @Override 32 | protected String getDefaultRpcReceiver() { 33 | return "android"; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/org/qpython/qsl4a/qsl4a/language/PerlLanguage.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2010 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 | * use this file except in compliance with the License. You may obtain a copy of 6 | * the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations under 14 | * the License. 15 | */ 16 | 17 | package org.qpython.qsl4a.qsl4a.language; 18 | 19 | /** 20 | * Represents the Perl programming language. 21 | * 22 | * @author igor.v.karp@gmail.com (Igor Karp) 23 | */ 24 | public class PerlLanguage extends Language { 25 | 26 | @Override 27 | protected String getImportStatement() { 28 | return "use Android;\n"; 29 | } 30 | 31 | @Override 32 | protected String getRpcReceiverDeclaration(String rpcReceiver) { 33 | return "my " + rpcReceiver + " = Android->new();\n"; 34 | } 35 | 36 | @Override 37 | protected String getDefaultRpcReceiver() { 38 | return "$droid"; 39 | } 40 | 41 | @Override 42 | protected String getApplyOperatorText() { 43 | return "->"; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/main/java/org/qpython/qsl4a/qsl4a/language/PhpLanguage.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2010 Irontec SL 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 | * use this file except in compliance with the License. You may obtain a copy of 6 | * the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations under 14 | * the License. 15 | */ 16 | 17 | package org.qpython.qsl4a.qsl4a.language; 18 | 19 | /** 20 | * Represents the PHP programming language. 21 | * 22 | * @author ivan@irontec.com (Ivan Mosquera Paulo) 23 | */ 24 | public class PhpLanguage extends Language { 25 | 26 | @Override 27 | protected String getImportStatement() { 28 | return ""; 45 | } 46 | 47 | @Override 48 | protected String getQuote() { 49 | return "'"; 50 | } 51 | 52 | } -------------------------------------------------------------------------------- /src/main/java/org/qpython/qsl4a/qsl4a/language/PythonLanguage.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2010 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 | * use this file except in compliance with the License. You may obtain a copy of 6 | * the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations under 14 | * the License. 15 | */ 16 | 17 | package org.qpython.qsl4a.qsl4a.language; 18 | 19 | /** 20 | * Represents the Python programming language. 21 | * 22 | * @author igor.v.karp@gmail.com (Igor Karp) 23 | */ 24 | public class PythonLanguage extends Language { 25 | 26 | @Override 27 | protected String getImportStatement() { 28 | return "import android\n"; 29 | } 30 | 31 | @Override 32 | protected String getRpcReceiverDeclaration(String rpcReceiver) { 33 | return rpcReceiver + " = android.Android()\n"; 34 | } 35 | 36 | @Override 37 | protected String getQuote() { 38 | return "'"; 39 | } 40 | 41 | @Override 42 | protected String getNull() { 43 | return "None"; 44 | } 45 | 46 | @Override 47 | protected String getTrue() { 48 | return "True"; 49 | } 50 | 51 | @Override 52 | protected String getFalse() { 53 | return "False"; 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/main/java/org/qpython/qsl4a/qsl4a/language/RubyLanguage.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2010 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 | * use this file except in compliance with the License. You may obtain a copy of 6 | * the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations under 14 | * the License. 15 | */ 16 | 17 | package org.qpython.qsl4a.qsl4a.language; 18 | 19 | /** 20 | * Represents the Ruby programming language. 21 | * 22 | * @author igor.v.karp@gmail.com (Igor Karp) 23 | */ 24 | public class RubyLanguage extends Language { 25 | 26 | @Override 27 | protected String getImportStatement() { 28 | return "require \"android\";\n"; 29 | } 30 | 31 | @Override 32 | protected String getRpcReceiverDeclaration(String rpcReceiver) { 33 | return rpcReceiver + " = Droid.new\n"; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/org/qpython/qsl4a/qsl4a/language/ShellLanguage.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2010 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 | * use this file except in compliance with the License. You may obtain a copy of 6 | * the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations under 14 | * the License. 15 | */ 16 | 17 | package org.qpython.qsl4a.qsl4a.language; 18 | 19 | /** 20 | * Represents the Shell programming language. 21 | * 22 | * @author igor.v.karp@gmail.com (Igor Karp) 23 | */ 24 | public class ShellLanguage extends Language { 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/org/qpython/qsl4a/qsl4a/language/SleepLanguage.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2010 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 | * use this file except in compliance with the License. You may obtain a copy of 6 | * the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations under 14 | * the License. 15 | */ 16 | 17 | package org.qpython.qsl4a.qsl4a.language; 18 | 19 | /** 20 | * Represents the Sleep programming language. 21 | * 22 | * @author tomcatalbino@gmail.com 23 | */ 24 | public class SleepLanguage extends Language { 25 | 26 | @Override 27 | protected String getImportStatement() { 28 | return "import com.googlecode.rpc.*;\n"; 29 | } 30 | 31 | @Override 32 | protected String getRpcReceiverDeclaration(String rpcReceiver) { 33 | return rpcReceiver + " = [new Android];\n"; 34 | } 35 | 36 | @Override 37 | protected String getDefaultRpcReceiver() { 38 | return "$droid"; 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /src/main/java/org/qpython/qsl4a/qsl4a/language/SquirrelLanguage.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2010 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 | * use this file except in compliance with the License. You may obtain a copy of 6 | * the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations under 14 | * the License. 15 | */ 16 | 17 | package org.qpython.qsl4a.qsl4a.language; 18 | 19 | /** 20 | * Represents the Squirrel programming language, by Alberto Demichelis 21 | * this file adapted by Andy Tai, atai@atai.org 22 | * based on the Python version by 23 | * @author igor.v.karp@gmail.com (Igor Karp) 24 | */ 25 | public class SquirrelLanguage extends Language { 26 | 27 | @Override 28 | protected String getImportStatement() { 29 | /* initialization code */ 30 | return ""; 31 | } 32 | 33 | @Override 34 | protected String getRpcReceiverDeclaration(String rpcReceiver) { 35 | return rpcReceiver + " <- Android();\n"; 36 | } 37 | 38 | @Override 39 | protected String getQuote() { 40 | return "\""; 41 | } 42 | 43 | @Override 44 | protected String getNull() { 45 | return "null"; 46 | } 47 | 48 | @Override 49 | protected String getTrue() { 50 | return "true"; 51 | } 52 | 53 | @Override 54 | protected String getFalse() { 55 | return "false"; 56 | } 57 | } 58 | 59 | -------------------------------------------------------------------------------- /src/main/java/org/qpython/qsl4a/qsl4a/language/SupportedLanguages.java: -------------------------------------------------------------------------------- 1 | package org.qpython.qsl4a.qsl4a.language; 2 | 3 | import org.qpython.qsl4a.qsl4a.LogUtil; 4 | 5 | import java.util.HashMap; 6 | import java.util.Map; 7 | 8 | public class SupportedLanguages { 9 | 10 | private static enum KnownLanguage { 11 | // SHELL(".sh", ShellLanguage.class), // We don't really support Shell language 12 | HTML(".html", HtmlLanguage.class), BEANSHELL(".bsh", BeanShellLanguage.class), JAVASCRIPT( 13 | ".js", JavaScriptLanguage.class), LUA(".lua", LuaLanguage.class), PERL(".pl", 14 | PerlLanguage.class), PYTHON(".py", PythonLanguage.class), RUBY(".rb", RubyLanguage.class), 15 | TCL(".tcl", TclLanguage.class), PHP(".php", PhpLanguage.class), SLEEP(".sl", 16 | SleepLanguage.class), SQUIRREL(".nut", SquirrelLanguage.class); 17 | 18 | private final String mmExtension; 19 | private final Class mmClass; 20 | 21 | private KnownLanguage(String ext, Class clazz) { 22 | mmExtension = ext; 23 | mmClass = clazz; 24 | } 25 | 26 | private String getExtension() { 27 | return mmExtension; 28 | } 29 | 30 | private Class getLanguageClass() { 31 | return mmClass; 32 | } 33 | } 34 | 35 | private static Map> sSupportedLanguages; 36 | 37 | static { 38 | sSupportedLanguages = new HashMap>(); 39 | for (KnownLanguage language : KnownLanguage.values()) { 40 | sSupportedLanguages.put(language.getExtension(), language.getLanguageClass()); 41 | } 42 | } 43 | 44 | public static Language getLanguageByExtension(String extension) { 45 | extension = extension.toLowerCase(); 46 | if (!extension.startsWith(".")) { 47 | throw new RuntimeException("Extension does not start with a dot: " + extension); 48 | } 49 | Language lang = null; 50 | 51 | Class clazz = sSupportedLanguages.get(extension); 52 | if (clazz == null) { 53 | clazz = Language.class; // revert to default language. 54 | } 55 | if (clazz != null) { 56 | try { 57 | lang = clazz.newInstance(); 58 | } catch (IllegalAccessException e) { 59 | LogUtil.e(e); 60 | } catch (InstantiationException e) { 61 | LogUtil.e(e); 62 | } 63 | } 64 | return lang; 65 | } 66 | 67 | public static boolean checkLanguageSupported(String name) { 68 | String extension = name.toLowerCase(); 69 | int index = extension.lastIndexOf('.'); 70 | if (index < 0) { 71 | extension = "." + extension; 72 | } else if (index > 0) { 73 | extension = extension.substring(index); 74 | } 75 | return sSupportedLanguages.containsKey(extension); 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /src/main/java/org/qpython/qsl4a/qsl4a/language/TclLanguage.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2010 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 | * use this file except in compliance with the License. You may obtain a copy of 6 | * the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations under 14 | * the License. 15 | */ 16 | 17 | package org.qpython.qsl4a.qsl4a.language; 18 | 19 | /** 20 | * Represents the Tcl programming language. 21 | * 22 | * @author igor.v.karp@gmail.com (Igor Karp) 23 | */ 24 | public class TclLanguage extends Language { 25 | 26 | @Override 27 | protected String getImportStatement() { 28 | return "package require android\n"; 29 | } 30 | 31 | @Override 32 | protected String getRpcReceiverDeclaration(String rpcReceiver) { 33 | return "set " + rpcReceiver + " [android new]\n"; 34 | } 35 | 36 | @Override 37 | protected String getApplyReceiverText(String receiver) { 38 | return "$" + receiver; 39 | } 40 | 41 | @Override 42 | protected String getApplyOperatorText() { 43 | return " "; 44 | } 45 | 46 | @Override 47 | protected String getLeftParametersText() { 48 | return " "; 49 | } 50 | 51 | @Override 52 | protected String getRightParametersText() { 53 | return ""; 54 | } 55 | 56 | @Override 57 | protected String getParameterSeparator() { 58 | return " "; 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/main/java/org/qpython/qsl4a/qsl4a/rpc/Converter.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2010 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 | * use this file except in compliance with the License. You may obtain a copy of 6 | * the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations under 14 | * the License. 15 | */ 16 | 17 | package org.qpython.qsl4a.qsl4a.rpc; 18 | 19 | /** 20 | * A converter can take a String and turn it into an instance of type T (the type parameter to the 21 | * converter). 22 | * 23 | * @author igor.v.karp@gmail.com (Igor Karp) 24 | */ 25 | public interface Converter { 26 | 27 | /** Convert a string into type T. */ 28 | T convert(String value); 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/org/qpython/qsl4a/qsl4a/rpc/ParameterDescriptor.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2010 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 | * use this file except in compliance with the License. You may obtain a copy of 6 | * the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations under 14 | * the License. 15 | */ 16 | 17 | package org.qpython.qsl4a.qsl4a.rpc; 18 | 19 | import java.lang.reflect.Type; 20 | 21 | /** 22 | * RPC parameter description. 23 | * 24 | * @author igor.v.karp@gmail.com (Igor Karp) 25 | */ 26 | public final class ParameterDescriptor { 27 | private final String value; 28 | private final Type type; 29 | 30 | public ParameterDescriptor(String value, Type type) { 31 | this.value = value; 32 | this.type = type; 33 | } 34 | 35 | public String getValue() { 36 | return value; 37 | } 38 | 39 | public Type getType() { 40 | return type; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/main/java/org/qpython/qsl4a/qsl4a/rpc/Rpc.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2009 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 | * use this file except in compliance with the License. You may obtain a copy of 6 | * the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations under 14 | * the License. 15 | */ 16 | 17 | package org.qpython.qsl4a.qsl4a.rpc; 18 | 19 | import java.lang.annotation.Documented; 20 | import java.lang.annotation.ElementType; 21 | import java.lang.annotation.Retention; 22 | import java.lang.annotation.RetentionPolicy; 23 | import java.lang.annotation.Target; 24 | 25 | /** 26 | * The {@link Rpc} annotation is used to annotate server-side implementations of RPCs. It describes 27 | * meta-information (currently a brief documentation of the function), and marks a function as the 28 | * implementation of an RPC. 29 | */ 30 | @Retention(RetentionPolicy.RUNTIME) 31 | @Target(ElementType.METHOD) 32 | @Documented 33 | public @interface Rpc { 34 | /** 35 | * Returns brief description of the function. Should be limited to one or two sentences. 36 | */ 37 | String description(); 38 | 39 | /** 40 | * Gives a brief description of the functions return value (and the underlying data structure). 41 | */ 42 | String returns() default ""; 43 | } 44 | -------------------------------------------------------------------------------- /src/main/java/org/qpython/qsl4a/qsl4a/rpc/RpcDefault.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2010 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 | * use this file except in compliance with the License. You may obtain a copy of 6 | * the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations under 14 | * the License. 15 | */ 16 | 17 | package org.qpython.qsl4a.qsl4a.rpc; 18 | 19 | import java.lang.annotation.Documented; 20 | import java.lang.annotation.ElementType; 21 | import java.lang.annotation.Retention; 22 | import java.lang.annotation.RetentionPolicy; 23 | import java.lang.annotation.Target; 24 | 25 | /** 26 | * Use this annotation to mark an RPC parameter that have a default value. 27 | * 28 | * @author igor.v.karp@gmail.com (Igor Karp) 29 | */ 30 | @Retention(RetentionPolicy.RUNTIME) 31 | @Target(ElementType.PARAMETER) 32 | @Documented 33 | public @interface RpcDefault { 34 | /** The default value of the RPC parameter. */ 35 | public String value(); 36 | 37 | @SuppressWarnings("rawtypes") 38 | public Class converter() default Converter.class; 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/org/qpython/qsl4a/qsl4a/rpc/RpcDeprecated.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2010 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 | * use this file except in compliance with the License. You may obtain a copy of 6 | * the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations under 14 | * the License. 15 | */ 16 | 17 | package org.qpython.qsl4a.qsl4a.rpc; 18 | 19 | import java.lang.annotation.Documented; 20 | import java.lang.annotation.ElementType; 21 | import java.lang.annotation.Retention; 22 | import java.lang.annotation.RetentionPolicy; 23 | import java.lang.annotation.Target; 24 | 25 | /** 26 | * Use this annotation to mark RPC method as deprecated. 27 | */ 28 | @Retention(RetentionPolicy.RUNTIME) 29 | @Target(ElementType.METHOD) 30 | @Documented 31 | public @interface RpcDeprecated { 32 | /** The method that replaced this one. */ 33 | public String value(); 34 | 35 | /** Release of SL4A when deprecation occurred. */ 36 | public String release() default "r4"; 37 | } 38 | -------------------------------------------------------------------------------- /src/main/java/org/qpython/qsl4a/qsl4a/rpc/RpcError.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2010 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 | * use this file except in compliance with the License. You may obtain a copy of 6 | * the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations under 14 | * the License. 15 | */ 16 | 17 | package org.qpython.qsl4a.qsl4a.rpc; 18 | 19 | @SuppressWarnings("serial") 20 | public class RpcError extends Exception { 21 | 22 | public RpcError(String message) { 23 | super(message); 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/org/qpython/qsl4a/qsl4a/rpc/RpcMinSdk.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2010 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 | * use this file except in compliance with the License. You may obtain a copy of 6 | * the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations under 14 | * the License. 15 | */ 16 | 17 | package org.qpython.qsl4a.qsl4a.rpc; 18 | 19 | import java.lang.annotation.Documented; 20 | import java.lang.annotation.Retention; 21 | import java.lang.annotation.RetentionPolicy; 22 | 23 | /** 24 | * Use this annotation to specify minimum SDK level (if higher than 3). 25 | * 26 | */ 27 | @Retention(RetentionPolicy.RUNTIME) 28 | @Documented 29 | public @interface RpcMinSdk { 30 | /** Minimum SDK Level. */ 31 | public int value(); 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/org/qpython/qsl4a/qsl4a/rpc/RpcName.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2010 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 | * use this file except in compliance with the License. You may obtain a copy of 6 | * the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations under 14 | * the License. 15 | */ 16 | 17 | package org.qpython.qsl4a.qsl4a.rpc; 18 | 19 | import java.lang.annotation.Documented; 20 | import java.lang.annotation.ElementType; 21 | import java.lang.annotation.Retention; 22 | import java.lang.annotation.RetentionPolicy; 23 | import java.lang.annotation.Target; 24 | 25 | /** 26 | * Use this annotation to mark an RPC parameter that have a default value. 27 | * 28 | * @author igor.v.karp@gmail.com (Igor Karp) 29 | */ 30 | @Retention(RetentionPolicy.RUNTIME) 31 | @Target(ElementType.METHOD) 32 | @Documented 33 | public @interface RpcName { 34 | /** The default value of the RPC parameter. */ 35 | public String name(); 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/org/qpython/qsl4a/qsl4a/rpc/RpcOptional.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2010 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 | * use this file except in compliance with the License. You may obtain a copy of 6 | * the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations under 14 | * the License. 15 | */ 16 | 17 | package org.qpython.qsl4a.qsl4a.rpc; 18 | 19 | import java.lang.annotation.Documented; 20 | import java.lang.annotation.ElementType; 21 | import java.lang.annotation.Retention; 22 | import java.lang.annotation.RetentionPolicy; 23 | import java.lang.annotation.Target; 24 | 25 | /** 26 | * Use this annotation to mark RPC parameter as optional. 27 | * 28 | *

29 | * The parameter marked as optional has no explicit default value. {@code null} is used as default 30 | * value. 31 | * 32 | * @author igor.v.karp@gmail.com (Igor Karp) 33 | */ 34 | @Retention(RetentionPolicy.RUNTIME) 35 | @Target(ElementType.PARAMETER) 36 | @Documented 37 | public @interface RpcOptional { 38 | } 39 | -------------------------------------------------------------------------------- /src/main/java/org/qpython/qsl4a/qsl4a/rpc/RpcParameter.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2009 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 | * use this file except in compliance with the License. You may obtain a copy of 6 | * the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations under 14 | * the License. 15 | */ 16 | 17 | package org.qpython.qsl4a.qsl4a.rpc; 18 | 19 | import java.lang.annotation.Documented; 20 | import java.lang.annotation.ElementType; 21 | import java.lang.annotation.Retention; 22 | import java.lang.annotation.RetentionPolicy; 23 | import java.lang.annotation.Target; 24 | 25 | /** 26 | * An annotation that is used to document the parameters of an RPC. 27 | * 28 | * @author Felix Arends (felix.arends@gmail.com) 29 | * 30 | */ 31 | @Retention(RetentionPolicy.RUNTIME) 32 | @Target(ElementType.PARAMETER) 33 | @Documented 34 | public @interface RpcParameter { 35 | /** 36 | * The name of the formal parameter. This should be in agreement with the java code. 37 | */ 38 | public String name(); 39 | 40 | /** 41 | * Description of the RPC. This should be a short descriptive statement without a full stop, such 42 | * as 'disables the WiFi mode'. 43 | */ 44 | public String description() default ""; 45 | } 46 | -------------------------------------------------------------------------------- /src/main/java/org/qpython/qsl4a/qsl4a/rpc/RpcStartEvent.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2010 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 | * use this file except in compliance with the License. You may obtain a copy of 6 | * the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations under 14 | * the License. 15 | */ 16 | 17 | package org.qpython.qsl4a.qsl4a.rpc; 18 | 19 | import java.lang.annotation.Documented; 20 | import java.lang.annotation.ElementType; 21 | import java.lang.annotation.Retention; 22 | import java.lang.annotation.RetentionPolicy; 23 | import java.lang.annotation.Target; 24 | 25 | /** 26 | * Use this annotation to mark an RPC as one that starts generating events. 27 | * 28 | * @author damonkohler@gmail.com (Damon Kohler) 29 | */ 30 | @Retention(RetentionPolicy.RUNTIME) 31 | @Target(ElementType.METHOD) 32 | @Documented 33 | public @interface RpcStartEvent { 34 | /** The name of the event that is generated. */ 35 | public String value(); 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/org/qpython/qsl4a/qsl4a/rpc/RpcStopEvent.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2010 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 | * use this file except in compliance with the License. You may obtain a copy of 6 | * the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations under 14 | * the License. 15 | */ 16 | 17 | package org.qpython.qsl4a.qsl4a.rpc; 18 | 19 | import java.lang.annotation.Documented; 20 | import java.lang.annotation.ElementType; 21 | import java.lang.annotation.Retention; 22 | import java.lang.annotation.RetentionPolicy; 23 | import java.lang.annotation.Target; 24 | 25 | /** 26 | * Use this annotation to mark an RPC as one that stops generating events. 27 | * 28 | * @author damonkohler@gmail.com (Damon Kohler) 29 | */ 30 | @Retention(RetentionPolicy.RUNTIME) 31 | @Target(ElementType.METHOD) 32 | @Documented 33 | public @interface RpcStopEvent { 34 | /** The name of the event that stops being generated. */ 35 | public String value(); 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/org/qpython/qsl4a/qsl4a/trigger/EventGenerationControllingObserver.java: -------------------------------------------------------------------------------- 1 | package org.qpython.qsl4a.qsl4a.trigger; 2 | 3 | import com.google.common.collect.Maps; 4 | import org.qpython.qsl4a.qsl4a.facade.FacadeConfiguration; 5 | import org.qpython.qsl4a.qsl4a.facade.FacadeManager; 6 | import org.qpython.qsl4a.qsl4a.rpc.MethodDescriptor; 7 | 8 | import java.util.Map; 9 | 10 | import org.json.JSONArray; 11 | 12 | /** 13 | * A {@link TriggerRepository.TriggerRepositoryObserver} that starts and stops the monitoring of events depending on 14 | * whether or not triggers for the event exist. 15 | * 16 | * @author Felix Arends (felix.arends@gmail.com) 17 | */ 18 | public class EventGenerationControllingObserver implements TriggerRepository.TriggerRepositoryObserver { 19 | private final FacadeManager mFacadeManager; 20 | private final Map mStartEventGeneratingMethodDescriptors; 21 | private final Map mStopEventGeneratingMethodDescriptors; 22 | private final Map mEventTriggerRefCounts = Maps.newHashMap(); 23 | 24 | /** 25 | * Creates a new StartEventMonitoringObserver for the given trigger repository. 26 | * 27 | * @param facadeManager 28 | * @param triggerRepository 29 | */ 30 | public EventGenerationControllingObserver(FacadeManager facadeManager) { 31 | mFacadeManager = facadeManager; 32 | mStartEventGeneratingMethodDescriptors = 33 | FacadeConfiguration.collectStartEventMethodDescriptors(); 34 | mStopEventGeneratingMethodDescriptors = FacadeConfiguration.collectStopEventMethodDescriptors(); 35 | } 36 | 37 | private synchronized int incrementAndGetRefCount(String eventName) { 38 | int refCount = 39 | (mEventTriggerRefCounts.containsKey(eventName)) ? mEventTriggerRefCounts.get(eventName) : 0; 40 | refCount++; 41 | mEventTriggerRefCounts.put(eventName, refCount); 42 | return refCount; 43 | } 44 | 45 | private synchronized int decrementAndGetRefCount(String eventName) { 46 | int refCount = 47 | (mEventTriggerRefCounts.containsKey(eventName)) ? mEventTriggerRefCounts.get(eventName) : 0; 48 | refCount--; 49 | mEventTriggerRefCounts.put(eventName, refCount); 50 | return refCount; 51 | } 52 | 53 | @Override 54 | public synchronized void onPut(Trigger trigger) { 55 | // If we're not already monitoring the events corresponding to this trigger, do so. 56 | if (incrementAndGetRefCount(trigger.getEventName()) == 1) { 57 | startMonitoring(trigger.getEventName()); 58 | } 59 | } 60 | 61 | @Override 62 | public synchronized void onRemove(Trigger trigger) { 63 | // If there are no more triggers listening to this event, then we need to stop monitoring. 64 | if (decrementAndGetRefCount(trigger.getEventName()) == 1) { 65 | stopMonitoring(trigger.getEventName()); 66 | } 67 | } 68 | 69 | private void startMonitoring(String eventName) { 70 | MethodDescriptor startEventGeneratingMethod = 71 | mStartEventGeneratingMethodDescriptors.get(eventName); 72 | try { 73 | startEventGeneratingMethod.invoke(mFacadeManager, new JSONArray()); 74 | } catch (Throwable t) { 75 | throw new RuntimeException(t); 76 | } 77 | } 78 | 79 | private void stopMonitoring(String eventName) { 80 | MethodDescriptor stopEventGeneratingMethod = 81 | mStopEventGeneratingMethodDescriptors.get(eventName); 82 | try { 83 | stopEventGeneratingMethod.invoke(mFacadeManager, new JSONArray()); 84 | } catch (Throwable t) { 85 | throw new RuntimeException(t); 86 | } 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /src/main/java/org/qpython/qsl4a/qsl4a/trigger/ScriptTrigger.java: -------------------------------------------------------------------------------- 1 | package org.qpython.qsl4a.qsl4a.trigger; 2 | 3 | import android.content.Context; 4 | import android.content.Intent; 5 | 6 | import org.qpython.qsl4a.qsl4a.IntentBuilders; 7 | import org.qpython.qsl4a.qsl4a.event.Event; 8 | 9 | import java.io.File; 10 | 11 | /** 12 | * A trigger implementation that launches a given script when the event occurs. 13 | * 14 | * @author Felix Arends (felix.arends@gmail.com) 15 | */ 16 | public class ScriptTrigger implements Trigger { 17 | private static final long serialVersionUID = 1804599219214041409L; 18 | private final File mScript; 19 | private final String mEventName; 20 | 21 | public ScriptTrigger(String eventName, File script) { 22 | mEventName = eventName; 23 | mScript = script; 24 | } 25 | 26 | @Override 27 | public void handleEvent(Event event, Context context) { 28 | Intent intent = IntentBuilders.buildStartInBackgroundIntent(mScript); 29 | // This is required since the script is being started from the TriggerService. 30 | intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 31 | context.startActivity(intent); 32 | } 33 | 34 | @Override 35 | public String getEventName() { 36 | return mEventName; 37 | } 38 | 39 | public File getScript() { 40 | return mScript; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/main/java/org/qpython/qsl4a/qsl4a/trigger/Trigger.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2010 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 | * use this file except in compliance with the License. You may obtain a copy of 6 | * the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations under 14 | * the License. 15 | */ 16 | 17 | package org.qpython.qsl4a.qsl4a.trigger; 18 | 19 | import android.content.Context; 20 | 21 | 22 | import org.qpython.qsl4a.qsl4a.event.Event; 23 | 24 | import java.io.Serializable; 25 | 26 | /** 27 | * Interface implemented by objects listening to events on the event queue inside of the 28 | * {@link SerivceManager}. 29 | * 30 | * @author Felix Arends (felix.arends@gmail.com) 31 | */ 32 | public interface Trigger extends Serializable { 33 | /** 34 | * Handles an event from the event queue. 35 | * 36 | * @param event 37 | * Event to handle 38 | * @param context 39 | * TODO 40 | */ 41 | void handleEvent(Event event, Context context); 42 | 43 | /** 44 | * Returns the event name that this {@link Trigger} is interested in. 45 | */ 46 | // TODO(damonkohler): This could be removed by maintaining a reverse mapping from Trigger to event 47 | // name in the TriggerRespository. 48 | String getEventName(); 49 | } 50 | -------------------------------------------------------------------------------- /src/main/java/org/qpython/qsl4a/qsl4a/util/VisibleForTesting.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2010 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 | * use this file except in compliance with the License. You may obtain a copy of 6 | * the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations under 14 | * the License. 15 | */ 16 | 17 | package org.qpython.qsl4a.qsl4a.util; 18 | 19 | /** 20 | * An annotation that indicates that the visibility of a type or member has been relaxed from 21 | * private to package to make the code testable. 22 | * 23 | * @author igor.v.karp@gmail.com (Igor Karp) 24 | */ 25 | // TODO(igor.v.karp): Consider replacing this annotation by one from Guava or GCL 26 | public @interface VisibleForTesting { 27 | } 28 | -------------------------------------------------------------------------------- /src/main/res/drawable-xxhdpi/img_home_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qpython-android/qpysl4a/166d72af4a90cd904ca3fa981c70061f19452b0c/src/main/res/drawable-xxhdpi/img_home_logo.png -------------------------------------------------------------------------------- /src/main/res/drawable-xxhdpi/img_home_logo_3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qpython-android/qpysl4a/166d72af4a90cd904ca3fa981c70061f19452b0c/src/main/res/drawable-xxhdpi/img_home_logo_3.png -------------------------------------------------------------------------------- /src/main/res/drawable/toolbar_button_bg.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /src/main/res/layout/activity_run_splash.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 9 | 10 | 17 | 18 | 23 | 24 | 25 | 30 | 31 | 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /src/main/res/layout/widget_run_control.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 8 | 9 | 15 | 16 | 17 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #FF4A4A4A 4 | #FF363636 5 | #FF4BAC07 6 | #ffffff 7 | #FF9B9B9B 8 | 9 | #CACCCB 10 | #333333 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | QSL4A 4 | -------------------------------------------------------------------------------- /src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /tests/AndroidFacade-Clipboard.md: -------------------------------------------------------------------------------- 1 | # Testcase for setClipboard & getClipboard 2 | 3 | ## Test Result 4 | 5 | - √ setClipboard 6 | - √ getClipboard 7 | 8 | ## Test Script 9 | ``` 10 | # Test Code for setClipboard & getClipboard 11 | # You can put some content into clipboard before running this test script and you will see the first makeToast shows the content 12 | 13 | from androidhelper import Android 14 | droid = Android() 15 | 16 | clipboard = droid.getClipboard().result 17 | 18 | droid.makeToast("clipboard: %s" % clipboard) 19 | 20 | input(">Enter 1 continue\n") 21 | #setClipboard 22 | droid.setClipboard("Hello World") 23 | 24 | #getClipboard 25 | clipboard = droid.getClipboard().result 26 | 27 | droid.makeToast("clipboard: %s" % clipboard) 28 | ``` 29 | 30 | ## Test QrCode 31 | 32 | [Open QRCode to Scan](http://qr.qpython.com.cn/?p=f1c788ec-360e-11ea-a0b0-fa163e575766) 33 | --------------------------------------------------------------------------------