mirror of
https://github.com/apache/cordova-android.git
synced 2026-05-11 00:00:05 +08:00
Rename to Cordova
This commit is contained in:
@@ -1,308 +0,0 @@
|
||||
/*
|
||||
Licensed to the Apache Software Foundation (ASF) under one
|
||||
or more contributor license agreements. See the NOTICE file
|
||||
distributed with this work for additional information
|
||||
regarding copyright ownership. The ASF licenses this file
|
||||
to you under the Apache License, Version 2.0 (the
|
||||
"License"); you may not use this file except in compliance
|
||||
with the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing,
|
||||
software distributed under the License is distributed on an
|
||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
KIND, either express or implied. See the License for the
|
||||
specific language governing permissions and limitations
|
||||
under the License.
|
||||
*/
|
||||
package com.phonegap;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import com.phonegap.api.PhonegapActivity;
|
||||
import com.phonegap.api.Plugin;
|
||||
import com.phonegap.api.PluginResult;
|
||||
|
||||
import android.hardware.Sensor;
|
||||
import android.hardware.SensorEvent;
|
||||
import android.hardware.SensorEventListener;
|
||||
import android.hardware.SensorManager;
|
||||
import android.content.Context;
|
||||
|
||||
/**
|
||||
* This class listens to the accelerometer sensor and stores the latest
|
||||
* acceleration values x,y,z.
|
||||
*/
|
||||
public class AccelListener extends Plugin implements SensorEventListener {
|
||||
|
||||
public static int STOPPED = 0;
|
||||
public static int STARTING = 1;
|
||||
public static int RUNNING = 2;
|
||||
public static int ERROR_FAILED_TO_START = 3;
|
||||
|
||||
public float TIMEOUT = 30000; // Timeout in msec to shut off listener
|
||||
|
||||
float x,y,z; // most recent acceleration values
|
||||
long timestamp; // time of most recent value
|
||||
int status; // status of listener
|
||||
long lastAccessTime; // time the value was last retrieved
|
||||
|
||||
private SensorManager sensorManager;// Sensor manager
|
||||
Sensor mSensor; // Acceleration sensor returned by sensor manager
|
||||
|
||||
/**
|
||||
* Create an accelerometer listener.
|
||||
*/
|
||||
public AccelListener() {
|
||||
this.x = 0;
|
||||
this.y = 0;
|
||||
this.z = 0;
|
||||
this.timestamp = 0;
|
||||
this.setStatus(AccelListener.STOPPED);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the context of the Command. This can then be used to do things like
|
||||
* get file paths associated with the Activity.
|
||||
*
|
||||
* @param ctx The context of the main Activity.
|
||||
*/
|
||||
public void setContext(PhonegapActivity ctx) {
|
||||
super.setContext(ctx);
|
||||
this.sensorManager = (SensorManager) ctx.getSystemService(Context.SENSOR_SERVICE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes the request and returns PluginResult.
|
||||
*
|
||||
* @param action The action to execute.
|
||||
* @param args JSONArry of arguments for the plugin.
|
||||
* @param callbackId The callback id used when calling back into JavaScript.
|
||||
* @return A PluginResult object with a status and message.
|
||||
*/
|
||||
public PluginResult execute(String action, JSONArray args, String callbackId) {
|
||||
PluginResult.Status status = PluginResult.Status.OK;
|
||||
String result = "";
|
||||
|
||||
try {
|
||||
if (action.equals("getStatus")) {
|
||||
int i = this.getStatus();
|
||||
return new PluginResult(status, i);
|
||||
}
|
||||
else if (action.equals("start")) {
|
||||
int i = this.start();
|
||||
return new PluginResult(status, i);
|
||||
}
|
||||
else if (action.equals("stop")) {
|
||||
this.stop();
|
||||
return new PluginResult(status, 0);
|
||||
}
|
||||
else if (action.equals("getAcceleration")) {
|
||||
// If not running, then this is an async call, so don't worry about waiting
|
||||
if (this.status != AccelListener.RUNNING) {
|
||||
int r = this.start();
|
||||
if (r == AccelListener.ERROR_FAILED_TO_START) {
|
||||
return new PluginResult(PluginResult.Status.IO_EXCEPTION, AccelListener.ERROR_FAILED_TO_START);
|
||||
}
|
||||
// Wait until running
|
||||
long timeout = 2000;
|
||||
while ((this.status == STARTING) && (timeout > 0)) {
|
||||
timeout = timeout - 100;
|
||||
try {
|
||||
Thread.sleep(100);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
if (timeout == 0) {
|
||||
return new PluginResult(PluginResult.Status.IO_EXCEPTION, AccelListener.ERROR_FAILED_TO_START);
|
||||
}
|
||||
}
|
||||
this.lastAccessTime = System.currentTimeMillis();
|
||||
JSONObject r = new JSONObject();
|
||||
r.put("x", this.x);
|
||||
r.put("y", this.y);
|
||||
r.put("z", this.z);
|
||||
// TODO: Should timestamp be sent?
|
||||
r.put("timestamp", this.timestamp);
|
||||
return new PluginResult(status, r);
|
||||
}
|
||||
else if (action.equals("setTimeout")) {
|
||||
try {
|
||||
float timeout = Float.parseFloat(args.getString(0));
|
||||
this.setTimeout(timeout);
|
||||
return new PluginResult(status, 0);
|
||||
} catch (NumberFormatException e) {
|
||||
status = PluginResult.Status.INVALID_ACTION;
|
||||
e.printStackTrace();
|
||||
} catch (JSONException e) {
|
||||
status = PluginResult.Status.JSON_EXCEPTION;
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
else if (action.equals("getTimeout")) {
|
||||
float f = this.getTimeout();
|
||||
return new PluginResult(status, f);
|
||||
}
|
||||
return new PluginResult(status, result);
|
||||
} catch (JSONException e) {
|
||||
return new PluginResult(PluginResult.Status.JSON_EXCEPTION);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Identifies if action to be executed returns a value and should be run synchronously.
|
||||
*
|
||||
* @param action The action to execute
|
||||
* @return T=returns value
|
||||
*/
|
||||
public boolean isSynch(String action) {
|
||||
if (action.equals("getStatus")) {
|
||||
return true;
|
||||
}
|
||||
else if (action.equals("getAcceleration")) {
|
||||
// Can only return value if RUNNING
|
||||
if (this.status == RUNNING) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if (action.equals("getTimeout")) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called by AccelBroker when listener is to be shut down.
|
||||
* Stop listener.
|
||||
*/
|
||||
public void onDestroy() {
|
||||
this.stop();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// LOCAL METHODS
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Start listening for acceleration sensor.
|
||||
*
|
||||
* @return status of listener
|
||||
*/
|
||||
public int start() {
|
||||
|
||||
// If already starting or running, then just return
|
||||
if ((this.status == AccelListener.RUNNING) || (this.status == AccelListener.STARTING)) {
|
||||
return this.status;
|
||||
}
|
||||
|
||||
// Get accelerometer from sensor manager
|
||||
List<Sensor> list = this.sensorManager.getSensorList(Sensor.TYPE_ACCELEROMETER);
|
||||
|
||||
// If found, then register as listener
|
||||
if ((list != null) && (list.size() > 0)) {
|
||||
this.mSensor = list.get(0);
|
||||
this.sensorManager.registerListener(this, this.mSensor, SensorManager.SENSOR_DELAY_FASTEST);
|
||||
this.setStatus(AccelListener.STARTING);
|
||||
this.lastAccessTime = System.currentTimeMillis();
|
||||
}
|
||||
|
||||
// If error, then set status to error
|
||||
else {
|
||||
this.setStatus(AccelListener.ERROR_FAILED_TO_START);
|
||||
}
|
||||
|
||||
return this.status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop listening to acceleration sensor.
|
||||
*/
|
||||
public void stop() {
|
||||
if (this.status != AccelListener.STOPPED) {
|
||||
this.sensorManager.unregisterListener(this);
|
||||
}
|
||||
this.setStatus(AccelListener.STOPPED);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the accuracy of the sensor has changed.
|
||||
*
|
||||
* @param sensor
|
||||
* @param accuracy
|
||||
*/
|
||||
public void onAccuracyChanged(Sensor sensor, int accuracy) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Sensor listener event.
|
||||
*
|
||||
* @param SensorEvent event
|
||||
*/
|
||||
public void onSensorChanged(SensorEvent event) {
|
||||
|
||||
// Only look at accelerometer events
|
||||
if (event.sensor.getType() != Sensor.TYPE_ACCELEROMETER) {
|
||||
return;
|
||||
}
|
||||
|
||||
// If not running, then just return
|
||||
if (this.status == AccelListener.STOPPED) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Save time that event was received
|
||||
this.timestamp = System.currentTimeMillis();
|
||||
this.x = event.values[0];
|
||||
this.y = event.values[1];
|
||||
this.z = event.values[2];
|
||||
|
||||
this.setStatus(AccelListener.RUNNING);
|
||||
|
||||
// If values haven't been read for TIMEOUT time, then turn off accelerometer sensor to save power
|
||||
if ((this.timestamp - this.lastAccessTime) > this.TIMEOUT) {
|
||||
this.stop();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get status of accelerometer sensor.
|
||||
*
|
||||
* @return status
|
||||
*/
|
||||
public int getStatus() {
|
||||
return this.status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the timeout to turn off accelerometer sensor if getX() hasn't been called.
|
||||
*
|
||||
* @param timeout Timeout in msec.
|
||||
*/
|
||||
public void setTimeout(float timeout) {
|
||||
this.TIMEOUT = timeout;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the timeout to turn off accelerometer sensor if getX() hasn't been called.
|
||||
*
|
||||
* @return timeout in msec
|
||||
*/
|
||||
public float getTimeout() {
|
||||
return this.TIMEOUT;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the status and send it to JavaScript.
|
||||
* @param status
|
||||
*/
|
||||
private void setStatus(int status) {
|
||||
this.status = status;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,198 +0,0 @@
|
||||
/*
|
||||
Licensed to the Apache Software Foundation (ASF) under one
|
||||
or more contributor license agreements. See the NOTICE file
|
||||
distributed with this work for additional information
|
||||
regarding copyright ownership. The ASF licenses this file
|
||||
to you under the Apache License, Version 2.0 (the
|
||||
"License"); you may not use this file except in compliance
|
||||
with the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing,
|
||||
software distributed under the License is distributed on an
|
||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
KIND, either express or implied. See the License for the
|
||||
specific language governing permissions and limitations
|
||||
under the License.
|
||||
*/
|
||||
|
||||
package com.phonegap;
|
||||
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
import com.phonegap.api.LOG;
|
||||
import com.phonegap.api.Plugin;
|
||||
import com.phonegap.api.PluginResult;
|
||||
import java.util.HashMap;
|
||||
|
||||
/**
|
||||
* This class exposes methods in DroidGap that can be called from JavaScript.
|
||||
*/
|
||||
public class App extends Plugin {
|
||||
|
||||
/**
|
||||
* Executes the request and returns PluginResult.
|
||||
*
|
||||
* @param action The action to execute.
|
||||
* @param args JSONArry of arguments for the plugin.
|
||||
* @param callbackId The callback id used when calling back into JavaScript.
|
||||
* @return A PluginResult object with a status and message.
|
||||
*/
|
||||
public PluginResult execute(String action, JSONArray args, String callbackId) {
|
||||
PluginResult.Status status = PluginResult.Status.OK;
|
||||
String result = "";
|
||||
|
||||
try {
|
||||
if (action.equals("clearCache")) {
|
||||
this.clearCache();
|
||||
}
|
||||
else if (action.equals("loadUrl")) {
|
||||
this.loadUrl(args.getString(0), args.optJSONObject(1));
|
||||
}
|
||||
else if (action.equals("cancelLoadUrl")) {
|
||||
this.cancelLoadUrl();
|
||||
}
|
||||
else if (action.equals("clearHistory")) {
|
||||
this.clearHistory();
|
||||
}
|
||||
else if (action.equals("backHistory")) {
|
||||
this.backHistory();
|
||||
}
|
||||
else if (action.equals("overrideBackbutton")) {
|
||||
this.overrideBackbutton(args.getBoolean(0));
|
||||
}
|
||||
else if (action.equals("isBackbuttonOverridden")) {
|
||||
boolean b = this.isBackbuttonOverridden();
|
||||
return new PluginResult(status, b);
|
||||
}
|
||||
else if (action.equals("exitApp")) {
|
||||
this.exitApp();
|
||||
}
|
||||
return new PluginResult(status, result);
|
||||
} catch (JSONException e) {
|
||||
return new PluginResult(PluginResult.Status.JSON_EXCEPTION);
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// LOCAL METHODS
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Clear the resource cache.
|
||||
*/
|
||||
public void clearCache() {
|
||||
((DroidGap)this.ctx).clearCache();
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the url into the webview.
|
||||
*
|
||||
* @param url
|
||||
* @param props Properties that can be passed in to the DroidGap activity (i.e. loadingDialog, wait, ...)
|
||||
* @throws JSONException
|
||||
*/
|
||||
public void loadUrl(String url, JSONObject props) throws JSONException {
|
||||
LOG.d("App", "App.loadUrl("+url+","+props+")");
|
||||
int wait = 0;
|
||||
boolean openExternal = false;
|
||||
boolean clearHistory = false;
|
||||
|
||||
// If there are properties, then set them on the Activity
|
||||
HashMap<String, Object> params = new HashMap<String, Object>();
|
||||
if (props != null) {
|
||||
JSONArray keys = props.names();
|
||||
for (int i=0; i<keys.length(); i++) {
|
||||
String key = keys.getString(i);
|
||||
if (key.equals("wait")) {
|
||||
wait = props.getInt(key);
|
||||
}
|
||||
else if (key.equalsIgnoreCase("openexternal")) {
|
||||
openExternal = props.getBoolean(key);
|
||||
}
|
||||
else if (key.equalsIgnoreCase("clearhistory")) {
|
||||
clearHistory = props.getBoolean(key);
|
||||
}
|
||||
else {
|
||||
Object value = props.get(key);
|
||||
if (value == null) {
|
||||
|
||||
}
|
||||
else if (value.getClass().equals(String.class)) {
|
||||
params.put(key, (String)value);
|
||||
}
|
||||
else if (value.getClass().equals(Boolean.class)) {
|
||||
params.put(key, (Boolean)value);
|
||||
}
|
||||
else if (value.getClass().equals(Integer.class)) {
|
||||
params.put(key, (Integer)value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If wait property, then delay loading
|
||||
|
||||
if (wait > 0) {
|
||||
try {
|
||||
synchronized(this) {
|
||||
this.wait(wait);
|
||||
}
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
((DroidGap)this.ctx).showWebPage(url, openExternal, clearHistory, params);
|
||||
}
|
||||
|
||||
/**
|
||||
* Cancel loadUrl before it has been loaded.
|
||||
*/
|
||||
public void cancelLoadUrl() {
|
||||
((DroidGap)this.ctx).cancelLoadUrl();
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear page history for the app.
|
||||
*/
|
||||
public void clearHistory() {
|
||||
((DroidGap)this.ctx).clearHistory();
|
||||
}
|
||||
|
||||
/**
|
||||
* Go to previous page displayed.
|
||||
* This is the same as pressing the backbutton on Android device.
|
||||
*/
|
||||
public void backHistory() {
|
||||
((DroidGap)this.ctx).backHistory();
|
||||
}
|
||||
|
||||
/**
|
||||
* Override the default behavior of the Android back button.
|
||||
* If overridden, when the back button is pressed, the "backKeyDown" JavaScript event will be fired.
|
||||
*
|
||||
* @param override T=override, F=cancel override
|
||||
*/
|
||||
public void overrideBackbutton(boolean override) {
|
||||
LOG.i("DroidGap", "WARNING: Back Button Default Behaviour will be overridden. The backbutton event will be fired!");
|
||||
((DroidGap)this.ctx).bound = override;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether the Android back button is overridden by the user.
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public boolean isBackbuttonOverridden() {
|
||||
return ((DroidGap)this.ctx).bound;
|
||||
}
|
||||
|
||||
/**
|
||||
* Exit the Android application.
|
||||
*/
|
||||
public void exitApp() {
|
||||
((DroidGap)this.ctx).endActivity();
|
||||
}
|
||||
}
|
||||
@@ -1,363 +0,0 @@
|
||||
/*
|
||||
Licensed to the Apache Software Foundation (ASF) under one
|
||||
or more contributor license agreements. See the NOTICE file
|
||||
distributed with this work for additional information
|
||||
regarding copyright ownership. The ASF licenses this file
|
||||
to you under the Apache License, Version 2.0 (the
|
||||
"License"); you may not use this file except in compliance
|
||||
with the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing,
|
||||
software distributed under the License is distributed on an
|
||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
KIND, either express or implied. See the License for the
|
||||
specific language governing permissions and limitations
|
||||
under the License.
|
||||
*/
|
||||
package com.phonegap;
|
||||
|
||||
import android.content.Context;
|
||||
import android.media.AudioManager;
|
||||
import com.phonegap.api.Plugin;
|
||||
import com.phonegap.api.PluginResult;
|
||||
import java.util.ArrayList;
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
|
||||
import com.phonegap.api.LOG;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
/**
|
||||
* This class called by PhonegapActivity to play and record audio.
|
||||
* The file can be local or over a network using http.
|
||||
*
|
||||
* Audio formats supported (tested):
|
||||
* .mp3, .wav
|
||||
*
|
||||
* Local audio files must reside in one of two places:
|
||||
* android_asset: file name must start with /android_asset/sound.mp3
|
||||
* sdcard: file name is just sound.mp3
|
||||
*/
|
||||
public class AudioHandler extends Plugin {
|
||||
|
||||
public static String TAG = "AudioHandler";
|
||||
HashMap<String,AudioPlayer> players; // Audio player object
|
||||
ArrayList<AudioPlayer> pausedForPhone; // Audio players that were paused when phone call came in
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
public AudioHandler() {
|
||||
this.players = new HashMap<String,AudioPlayer>();
|
||||
this.pausedForPhone = new ArrayList<AudioPlayer>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes the request and returns PluginResult.
|
||||
*
|
||||
* @param action The action to execute.
|
||||
* @param args JSONArry of arguments for the plugin.
|
||||
* @param callbackId The callback id used when calling back into JavaScript.
|
||||
* @return A PluginResult object with a status and message.
|
||||
*/
|
||||
public PluginResult execute(String action, JSONArray args, String callbackId) {
|
||||
PluginResult.Status status = PluginResult.Status.OK;
|
||||
String result = "";
|
||||
|
||||
try {
|
||||
if (action.equals("startRecordingAudio")) {
|
||||
this.startRecordingAudio(args.getString(0), args.getString(1));
|
||||
}
|
||||
else if (action.equals("stopRecordingAudio")) {
|
||||
this.stopRecordingAudio(args.getString(0));
|
||||
}
|
||||
else if (action.equals("startPlayingAudio")) {
|
||||
this.startPlayingAudio(args.getString(0), args.getString(1));
|
||||
}
|
||||
else if (action.equals("seekToAudio")) {
|
||||
this.seekToAudio(args.getString(0), args.getInt(1));
|
||||
}
|
||||
else if (action.equals("pausePlayingAudio")) {
|
||||
this.pausePlayingAudio(args.getString(0));
|
||||
}
|
||||
else if (action.equals("stopPlayingAudio")) {
|
||||
this.stopPlayingAudio(args.getString(0));
|
||||
} else if (action.equals("setVolume")) {
|
||||
try {
|
||||
this.setVolume(args.getString(0), Float.parseFloat(args.getString(1)));
|
||||
} catch (NumberFormatException nfe) {
|
||||
//no-op
|
||||
}
|
||||
} else if (action.equals("getCurrentPositionAudio")) {
|
||||
float f = this.getCurrentPositionAudio(args.getString(0));
|
||||
return new PluginResult(status, f);
|
||||
}
|
||||
else if (action.equals("getDurationAudio")) {
|
||||
float f = this.getDurationAudio(args.getString(0), args.getString(1));
|
||||
return new PluginResult(status, f);
|
||||
}
|
||||
else if (action.equals("release")) {
|
||||
boolean b = this.release(args.getString(0));
|
||||
return new PluginResult(status, b);
|
||||
}
|
||||
return new PluginResult(status, result);
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
return new PluginResult(PluginResult.Status.JSON_EXCEPTION);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Identifies if action to be executed returns a value and should be run synchronously.
|
||||
*
|
||||
* @param action The action to execute
|
||||
* @return T=returns value
|
||||
*/
|
||||
public boolean isSynch(String action) {
|
||||
if (action.equals("getCurrentPositionAudio")) {
|
||||
return true;
|
||||
}
|
||||
else if (action.equals("getDurationAudio")) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop all audio players and recorders.
|
||||
*/
|
||||
public void onDestroy() {
|
||||
for (AudioPlayer audio : this.players.values()) {
|
||||
audio.destroy();
|
||||
}
|
||||
this.players.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when a message is sent to plugin.
|
||||
*
|
||||
* @param id The message id
|
||||
* @param data The message data
|
||||
*/
|
||||
public void onMessage(String id, Object data) {
|
||||
|
||||
// If phone message
|
||||
if (id.equals("telephone")) {
|
||||
|
||||
// If phone ringing, then pause playing
|
||||
if ("ringing".equals(data) || "offhook".equals(data)) {
|
||||
|
||||
// Get all audio players and pause them
|
||||
for (AudioPlayer audio : this.players.values()) {
|
||||
if (audio.getState() == AudioPlayer.MEDIA_RUNNING) {
|
||||
this.pausedForPhone.add(audio);
|
||||
audio.pausePlaying();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// If phone idle, then resume playing those players we paused
|
||||
else if ("idle".equals(data)) {
|
||||
for (AudioPlayer audio : this.pausedForPhone) {
|
||||
audio.startPlaying(null);
|
||||
}
|
||||
this.pausedForPhone.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// LOCAL METHODS
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Release the audio player instance to save memory.
|
||||
*
|
||||
* @param id The id of the audio player
|
||||
*/
|
||||
private boolean release(String id) {
|
||||
if (!this.players.containsKey(id)) {
|
||||
return false;
|
||||
}
|
||||
AudioPlayer audio = this.players.get(id);
|
||||
this.players.remove(id);
|
||||
audio.destroy();
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Start recording and save the specified file.
|
||||
*
|
||||
* @param id The id of the audio player
|
||||
* @param file The name of the file
|
||||
*/
|
||||
public void startRecordingAudio(String id, String file) {
|
||||
// If already recording, then just return;
|
||||
if (this.players.containsKey(id)) {
|
||||
return;
|
||||
}
|
||||
AudioPlayer audio = new AudioPlayer(this, id);
|
||||
this.players.put(id, audio);
|
||||
audio.startRecording(file);
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop recording and save to the file specified when recording started.
|
||||
*
|
||||
* @param id The id of the audio player
|
||||
*/
|
||||
public void stopRecordingAudio(String id) {
|
||||
AudioPlayer audio = this.players.get(id);
|
||||
if (audio != null) {
|
||||
audio.stopRecording();
|
||||
this.players.remove(id);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Start or resume playing audio file.
|
||||
*
|
||||
* @param id The id of the audio player
|
||||
* @param file The name of the audio file.
|
||||
*/
|
||||
public void startPlayingAudio(String id, String file) {
|
||||
AudioPlayer audio = this.players.get(id);
|
||||
if (audio == null) {
|
||||
audio = new AudioPlayer(this, id);
|
||||
this.players.put(id, audio);
|
||||
}
|
||||
audio.startPlaying(file);
|
||||
}
|
||||
|
||||
/**
|
||||
* Seek to a location.
|
||||
*
|
||||
*
|
||||
* @param id The id of the audio player
|
||||
* @param miliseconds int: number of milliseconds to skip 1000 = 1 second
|
||||
*/
|
||||
public void seekToAudio(String id, int milliseconds) {
|
||||
AudioPlayer audio = this.players.get(id);
|
||||
if (audio != null) {
|
||||
audio.seekToPlaying(milliseconds);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Pause playing.
|
||||
*
|
||||
* @param id The id of the audio player
|
||||
*/
|
||||
public void pausePlayingAudio(String id) {
|
||||
AudioPlayer audio = this.players.get(id);
|
||||
if (audio != null) {
|
||||
audio.pausePlaying();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop playing the audio file.
|
||||
*
|
||||
* @param id The id of the audio player
|
||||
*/
|
||||
public void stopPlayingAudio(String id) {
|
||||
AudioPlayer audio = this.players.get(id);
|
||||
if (audio != null) {
|
||||
audio.stopPlaying();
|
||||
//audio.destroy();
|
||||
//this.players.remove(id);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get current position of playback.
|
||||
*
|
||||
* @param id The id of the audio player
|
||||
* @return position in msec
|
||||
*/
|
||||
public float getCurrentPositionAudio(String id) {
|
||||
AudioPlayer audio = this.players.get(id);
|
||||
if (audio != null) {
|
||||
return(audio.getCurrentPosition()/1000.0f);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the duration of the audio file.
|
||||
*
|
||||
* @param id The id of the audio player
|
||||
* @param file The name of the audio file.
|
||||
* @return The duration in msec.
|
||||
*/
|
||||
public float getDurationAudio(String id, String file) {
|
||||
|
||||
// Get audio file
|
||||
AudioPlayer audio = this.players.get(id);
|
||||
if (audio != null) {
|
||||
return(audio.getDuration(file));
|
||||
}
|
||||
|
||||
// If not already open, then open the file
|
||||
else {
|
||||
audio = new AudioPlayer(this, id);
|
||||
this.players.put(id, audio);
|
||||
return(audio.getDuration(file));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the audio device to be used for playback.
|
||||
*
|
||||
* @param output 1=earpiece, 2=speaker
|
||||
*/
|
||||
public void setAudioOutputDevice(int output) {
|
||||
AudioManager audiMgr = (AudioManager) this.ctx.getSystemService(Context.AUDIO_SERVICE);
|
||||
if (output == 2) {
|
||||
audiMgr.setRouting(AudioManager.MODE_NORMAL, AudioManager.ROUTE_SPEAKER, AudioManager.ROUTE_ALL);
|
||||
}
|
||||
else if (output == 1) {
|
||||
audiMgr.setRouting(AudioManager.MODE_NORMAL, AudioManager.ROUTE_EARPIECE, AudioManager.ROUTE_ALL);
|
||||
}
|
||||
else {
|
||||
System.out.println("AudioHandler.setAudioOutputDevice() Error: Unknown output device.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the audio device to be used for playback.
|
||||
*
|
||||
* @return 1=earpiece, 2=speaker
|
||||
*/
|
||||
public int getAudioOutputDevice() {
|
||||
AudioManager audiMgr = (AudioManager) this.ctx.getSystemService(Context.AUDIO_SERVICE);
|
||||
if (audiMgr.getRouting(AudioManager.MODE_NORMAL) == AudioManager.ROUTE_EARPIECE) {
|
||||
return 1;
|
||||
}
|
||||
else if (audiMgr.getRouting(AudioManager.MODE_NORMAL) == AudioManager.ROUTE_SPEAKER) {
|
||||
return 2;
|
||||
}
|
||||
else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the volume for an audio device
|
||||
*
|
||||
* @param id The id of the audio player
|
||||
* @param volume Volume to adjust to 0.0f - 1.0f
|
||||
*/
|
||||
public void setVolume(String id, float volume) {
|
||||
AudioPlayer audio = this.players.get(id);
|
||||
if (audio != null) {
|
||||
audio.setVolume(volume);
|
||||
} else {
|
||||
System.out.println("AudioHandler.setVolume() Error: Unknown Audio Player " + id);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,450 +0,0 @@
|
||||
/*
|
||||
Licensed to the Apache Software Foundation (ASF) under one
|
||||
or more contributor license agreements. See the NOTICE file
|
||||
distributed with this work for additional information
|
||||
regarding copyright ownership. The ASF licenses this file
|
||||
to you under the Apache License, Version 2.0 (the
|
||||
"License"); you may not use this file except in compliance
|
||||
with the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing,
|
||||
software distributed under the License is distributed on an
|
||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
KIND, either express or implied. See the License for the
|
||||
specific language governing permissions and limitations
|
||||
under the License.
|
||||
*/
|
||||
package com.phonegap;
|
||||
|
||||
import android.media.AudioManager;
|
||||
import android.media.MediaPlayer;
|
||||
import android.media.MediaPlayer.OnCompletionListener;
|
||||
import android.media.MediaPlayer.OnErrorListener;
|
||||
import android.media.MediaPlayer.OnPreparedListener;
|
||||
import android.media.MediaRecorder;
|
||||
import android.os.Environment;
|
||||
import android.util.Log;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* This class implements the audio playback and recording capabilities used by PhoneGap.
|
||||
* It is called by the AudioHandler PhoneGap class.
|
||||
* Only one file can be played or recorded per class instance.
|
||||
*
|
||||
* Local audio files must reside in one of two places:
|
||||
* android_asset: file name must start with /android_asset/sound.mp3
|
||||
* sdcard: file name is just sound.mp3
|
||||
*/
|
||||
public class AudioPlayer implements OnCompletionListener, OnPreparedListener, OnErrorListener {
|
||||
|
||||
private static final String LOG_TAG = "AudioPlayer";
|
||||
|
||||
// AudioPlayer states
|
||||
public static int MEDIA_NONE = 0;
|
||||
public static int MEDIA_STARTING = 1;
|
||||
public static int MEDIA_RUNNING = 2;
|
||||
public static int MEDIA_PAUSED = 3;
|
||||
public static int MEDIA_STOPPED = 4;
|
||||
|
||||
// AudioPlayer message ids
|
||||
private static int MEDIA_STATE = 1;
|
||||
private static int MEDIA_DURATION = 2;
|
||||
private static int MEDIA_POSITION = 3;
|
||||
private static int MEDIA_ERROR = 9;
|
||||
|
||||
// Media error codes
|
||||
private static int MEDIA_ERR_NONE_ACTIVE = 0;
|
||||
private static int MEDIA_ERR_ABORTED = 1;
|
||||
private static int MEDIA_ERR_NETWORK = 2;
|
||||
private static int MEDIA_ERR_DECODE = 3;
|
||||
private static int MEDIA_ERR_NONE_SUPPORTED = 4;
|
||||
|
||||
private AudioHandler handler; // The AudioHandler object
|
||||
private String id; // The id of this player (used to identify Media object in JavaScript)
|
||||
private int state = MEDIA_NONE; // State of recording or playback
|
||||
private String audioFile = null; // File name to play or record to
|
||||
private float duration = -1; // Duration of audio
|
||||
|
||||
private MediaRecorder recorder = null; // Audio recording object
|
||||
private String tempFile = null; // Temporary recording file name
|
||||
|
||||
private MediaPlayer mPlayer = null; // Audio player object
|
||||
private boolean prepareOnly = false;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param handler The audio handler object
|
||||
* @param id The id of this audio player
|
||||
*/
|
||||
public AudioPlayer(AudioHandler handler, String id) {
|
||||
this.handler = handler;
|
||||
this.id = id;
|
||||
this.tempFile = Environment.getExternalStorageDirectory().getAbsolutePath() + "/tmprecording.mp3";
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroy player and stop audio playing or recording.
|
||||
*/
|
||||
public void destroy() {
|
||||
|
||||
// Stop any play or record
|
||||
if (this.mPlayer != null) {
|
||||
if ((this.state == MEDIA_RUNNING) || (this.state == MEDIA_PAUSED)) {
|
||||
this.mPlayer.stop();
|
||||
this.setState(MEDIA_STOPPED);
|
||||
}
|
||||
this.mPlayer.release();
|
||||
this.mPlayer = null;
|
||||
}
|
||||
if (this.recorder != null) {
|
||||
this.stopRecording();
|
||||
this.recorder.release();
|
||||
this.recorder = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Start recording the specified file.
|
||||
*
|
||||
* @param file The name of the file
|
||||
*/
|
||||
public void startRecording(String file) {
|
||||
if (this.mPlayer != null) {
|
||||
Log.d(LOG_TAG, "AudioPlayer Error: Can't record in play mode.");
|
||||
this.handler.sendJavascript("PhoneGap.Media.onStatus('" + this.id + "', "+MEDIA_ERROR+", "+MEDIA_ERR_ABORTED+");");
|
||||
}
|
||||
|
||||
// Make sure we're not already recording
|
||||
else if (this.recorder == null) {
|
||||
this.audioFile = file;
|
||||
this.recorder = new MediaRecorder();
|
||||
this.recorder.setAudioSource(MediaRecorder.AudioSource.MIC);
|
||||
this.recorder.setOutputFormat(MediaRecorder.OutputFormat.DEFAULT); // THREE_GPP);
|
||||
this.recorder.setAudioEncoder(MediaRecorder.AudioEncoder.DEFAULT); //AMR_NB);
|
||||
this.recorder.setOutputFile(this.tempFile);
|
||||
try {
|
||||
this.recorder.prepare();
|
||||
this.recorder.start();
|
||||
this.setState(MEDIA_RUNNING);
|
||||
return;
|
||||
} catch (IllegalStateException e) {
|
||||
e.printStackTrace();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
this.handler.sendJavascript("PhoneGap.Media.onStatus('" + this.id + "', "+MEDIA_ERROR+", "+MEDIA_ERR_ABORTED+");");
|
||||
}
|
||||
else {
|
||||
Log.d(LOG_TAG, "AudioPlayer Error: Already recording.");
|
||||
this.handler.sendJavascript("PhoneGap.Media.onStatus('" + this.id + "', "+MEDIA_ERROR+", "+MEDIA_ERR_ABORTED+");");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Save temporary recorded file to specified name
|
||||
*
|
||||
* @param file
|
||||
*/
|
||||
public void moveFile(String file) {
|
||||
|
||||
/* this is a hack to save the file as the specified name */
|
||||
File f = new File(this.tempFile);
|
||||
f.renameTo(new File("/sdcard/" + file));
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop recording and save to the file specified when recording started.
|
||||
*/
|
||||
public void stopRecording() {
|
||||
if (this.recorder != null) {
|
||||
try{
|
||||
if (this.state == MEDIA_RUNNING) {
|
||||
this.recorder.stop();
|
||||
this.setState(MEDIA_STOPPED);
|
||||
}
|
||||
this.moveFile(this.audioFile);
|
||||
}
|
||||
catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Start or resume playing audio file.
|
||||
*
|
||||
* @param file The name of the audio file.
|
||||
*/
|
||||
public void startPlaying(String file) {
|
||||
if (this.recorder != null) {
|
||||
Log.d(LOG_TAG, "AudioPlayer Error: Can't play in record mode.");
|
||||
this.handler.sendJavascript("PhoneGap.Media.onStatus('" + this.id + "', "+MEDIA_ERROR+", "+MEDIA_ERR_ABORTED+");");
|
||||
}
|
||||
|
||||
// If this is a new request to play audio, or stopped
|
||||
else if ((this.mPlayer == null) || (this.state == MEDIA_STOPPED)) {
|
||||
try {
|
||||
// If stopped, then reset player
|
||||
if (this.mPlayer != null) {
|
||||
this.mPlayer.reset();
|
||||
}
|
||||
// Otherwise, create a new one
|
||||
else {
|
||||
this.mPlayer = new MediaPlayer();
|
||||
}
|
||||
this.audioFile = file;
|
||||
|
||||
// If streaming file
|
||||
if (this.isStreaming(file)) {
|
||||
this.mPlayer.setDataSource(file);
|
||||
this.mPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
|
||||
this.setState(MEDIA_STARTING);
|
||||
this.mPlayer.setOnPreparedListener(this);
|
||||
this.mPlayer.prepareAsync();
|
||||
}
|
||||
|
||||
// If local file
|
||||
else {
|
||||
if (file.startsWith("/android_asset/")) {
|
||||
String f = file.substring(15);
|
||||
android.content.res.AssetFileDescriptor fd = this.handler.ctx.getBaseContext().getAssets().openFd(f);
|
||||
this.mPlayer.setDataSource(fd.getFileDescriptor(), fd.getStartOffset(), fd.getLength());
|
||||
}
|
||||
else {
|
||||
this.mPlayer.setDataSource("/sdcard/" + file);
|
||||
}
|
||||
this.setState(MEDIA_STARTING);
|
||||
this.mPlayer.setOnPreparedListener(this);
|
||||
this.mPlayer.prepare();
|
||||
|
||||
// Get duration
|
||||
this.duration = getDurationInSeconds();
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
this.handler.sendJavascript("PhoneGap.Media.onStatus('" + this.id + "', "+MEDIA_ERROR+", "+MEDIA_ERR_ABORTED+");");
|
||||
}
|
||||
}
|
||||
|
||||
// If we have already have created an audio player
|
||||
else {
|
||||
|
||||
// If player has been paused, then resume playback
|
||||
if ((this.state == MEDIA_PAUSED) || (this.state == MEDIA_STARTING)) {
|
||||
this.mPlayer.start();
|
||||
this.setState(MEDIA_RUNNING);
|
||||
}
|
||||
else {
|
||||
Log.d(LOG_TAG, "AudioPlayer Error: startPlaying() called during invalid state: "+this.state);
|
||||
this.handler.sendJavascript("PhoneGap.Media.onStatus('" + this.id + "', "+MEDIA_ERROR+", "+MEDIA_ERR_ABORTED+");");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Seek or jump to a new time in the track.
|
||||
*/
|
||||
public void seekToPlaying(int milliseconds) {
|
||||
if (this.mPlayer != null) {
|
||||
this.mPlayer.seekTo(milliseconds);
|
||||
Log.d(LOG_TAG, "Send a onStatus update for the new seek");
|
||||
this.handler.sendJavascript("PhoneGap.Media.onStatus('" + this.id + "', "+MEDIA_POSITION+", "+milliseconds/1000.0f+");");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Pause playing.
|
||||
*/
|
||||
public void pausePlaying() {
|
||||
|
||||
// If playing, then pause
|
||||
if (this.state == MEDIA_RUNNING) {
|
||||
this.mPlayer.pause();
|
||||
this.setState(MEDIA_PAUSED);
|
||||
}
|
||||
else {
|
||||
Log.d(LOG_TAG, "AudioPlayer Error: pausePlaying() called during invalid state: "+this.state);
|
||||
this.handler.sendJavascript("PhoneGap.Media.onStatus('" + this.id + "', "+MEDIA_ERROR+", "+MEDIA_ERR_NONE_ACTIVE+");");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop playing the audio file.
|
||||
*/
|
||||
public void stopPlaying() {
|
||||
if ((this.state == MEDIA_RUNNING) || (this.state == MEDIA_PAUSED)) {
|
||||
this.mPlayer.stop();
|
||||
this.setState(MEDIA_STOPPED);
|
||||
}
|
||||
else {
|
||||
Log.d(LOG_TAG, "AudioPlayer Error: stopPlaying() called during invalid state: "+this.state);
|
||||
this.handler.sendJavascript("PhoneGap.Media.onStatus('" + this.id + "', "+MEDIA_ERROR+", "+MEDIA_ERR_NONE_ACTIVE+");");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback to be invoked when playback of a media source has completed.
|
||||
*
|
||||
* @param mPlayer The MediaPlayer that reached the end of the file
|
||||
*/
|
||||
public void onCompletion(MediaPlayer mPlayer) {
|
||||
this.setState(MEDIA_STOPPED);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get current position of playback.
|
||||
*
|
||||
* @return position in msec or -1 if not playing
|
||||
*/
|
||||
public long getCurrentPosition() {
|
||||
if ((this.state == MEDIA_RUNNING) || (this.state == MEDIA_PAUSED)) {
|
||||
int curPos = this.mPlayer.getCurrentPosition();
|
||||
this.handler.sendJavascript("PhoneGap.Media.onStatus('" + this.id + "', "+MEDIA_POSITION+", "+curPos/1000.0f+");");
|
||||
return curPos;
|
||||
}
|
||||
else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if playback file is streaming or local.
|
||||
* It is streaming if file name starts with "http://"
|
||||
*
|
||||
* @param file The file name
|
||||
* @return T=streaming, F=local
|
||||
*/
|
||||
public boolean isStreaming(String file) {
|
||||
if (file.contains("http://") || file.contains("https://")) {
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the duration of the audio file.
|
||||
*
|
||||
* @param file The name of the audio file.
|
||||
* @return The duration in msec.
|
||||
* -1=can't be determined
|
||||
* -2=not allowed
|
||||
*/
|
||||
public float getDuration(String file) {
|
||||
|
||||
// Can't get duration of recording
|
||||
if (this.recorder != null) {
|
||||
return(-2); // not allowed
|
||||
}
|
||||
|
||||
// If audio file already loaded and started, then return duration
|
||||
if (this.mPlayer != null) {
|
||||
return this.duration;
|
||||
}
|
||||
|
||||
// If no player yet, then create one
|
||||
else {
|
||||
this.prepareOnly = true;
|
||||
this.startPlaying(file);
|
||||
|
||||
// This will only return value for local, since streaming
|
||||
// file hasn't been read yet.
|
||||
return this.duration;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback to be invoked when the media source is ready for playback.
|
||||
*
|
||||
* @param mPlayer The MediaPlayer that is ready for playback
|
||||
*/
|
||||
public void onPrepared(MediaPlayer mPlayer) {
|
||||
// Listen for playback completion
|
||||
this.mPlayer.setOnCompletionListener(this);
|
||||
|
||||
// If start playing after prepared
|
||||
if (!this.prepareOnly) {
|
||||
|
||||
// Start playing
|
||||
this.mPlayer.start();
|
||||
|
||||
// Set player init flag
|
||||
this.setState(MEDIA_RUNNING);
|
||||
}
|
||||
|
||||
// Save off duration
|
||||
this.duration = getDurationInSeconds();
|
||||
this.prepareOnly = false;
|
||||
|
||||
// Send status notification to JavaScript
|
||||
this.handler.sendJavascript("PhoneGap.Media.onStatus('" + this.id + "', "+MEDIA_DURATION+","+this.duration+");");
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* By default Android returns the length of audio in mills but we want seconds
|
||||
*
|
||||
* @return length of clip in seconds
|
||||
*/
|
||||
private float getDurationInSeconds() {
|
||||
return (this.mPlayer.getDuration() / 1000.0f);
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback to be invoked when there has been an error during an asynchronous operation
|
||||
* (other errors will throw exceptions at method call time).
|
||||
*
|
||||
* @param mPlayer the MediaPlayer the error pertains to
|
||||
* @param arg1 the type of error that has occurred: (MEDIA_ERROR_UNKNOWN, MEDIA_ERROR_SERVER_DIED)
|
||||
* @param arg2 an extra code, specific to the error.
|
||||
*/
|
||||
public boolean onError(MediaPlayer mPlayer, int arg1, int arg2) {
|
||||
Log.d(LOG_TAG, "AudioPlayer.onError(" + arg1 + ", " + arg2+")");
|
||||
|
||||
// TODO: Not sure if this needs to be sent?
|
||||
this.mPlayer.stop();
|
||||
this.mPlayer.release();
|
||||
|
||||
// Send error notification to JavaScript
|
||||
this.handler.sendJavascript("PhoneGap.Media.onStatus('" + this.id + "', "+MEDIA_ERROR+", "+arg1+");");
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the state and send it to JavaScript.
|
||||
*
|
||||
* @param state
|
||||
*/
|
||||
private void setState(int state) {
|
||||
if (this.state != state) {
|
||||
this.handler.sendJavascript("PhoneGap.Media.onStatus('" + this.id + "', "+MEDIA_STATE+", "+state+");");
|
||||
}
|
||||
|
||||
this.state = state;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the audio state.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public int getState() {
|
||||
return this.state;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the volume for audio player
|
||||
*
|
||||
* @param volume
|
||||
*/
|
||||
public void setVolume(float volume) {
|
||||
this.mPlayer.setVolume(volume, volume);
|
||||
}
|
||||
}
|
||||
@@ -1,51 +0,0 @@
|
||||
package com.phonegap;
|
||||
|
||||
/**
|
||||
* The Class AuthenticationToken defines the userName and password to be used for authenticating a web resource
|
||||
*/
|
||||
public class AuthenticationToken {
|
||||
private String userName;
|
||||
private String password;
|
||||
|
||||
/**
|
||||
* Gets the user name.
|
||||
*
|
||||
* @return the user name
|
||||
*/
|
||||
public String getUserName() {
|
||||
return userName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the user name.
|
||||
*
|
||||
* @param userName
|
||||
* the new user name
|
||||
*/
|
||||
public void setUserName(String userName) {
|
||||
this.userName = userName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the password.
|
||||
*
|
||||
* @return the password
|
||||
*/
|
||||
public String getPassword() {
|
||||
return password;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the password.
|
||||
*
|
||||
* @param password
|
||||
* the new password
|
||||
*/
|
||||
public void setPassword(String password) {
|
||||
this.password = password;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -1,156 +0,0 @@
|
||||
/*
|
||||
Licensed to the Apache Software Foundation (ASF) under one
|
||||
or more contributor license agreements. See the NOTICE file
|
||||
distributed with this work for additional information
|
||||
regarding copyright ownership. The ASF licenses this file
|
||||
to you under the Apache License, Version 2.0 (the
|
||||
"License"); you may not use this file except in compliance
|
||||
with the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing,
|
||||
software distributed under the License is distributed on an
|
||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
KIND, either express or implied. See the License for the
|
||||
specific language governing permissions and limitations
|
||||
under the License.
|
||||
*/
|
||||
package com.phonegap;
|
||||
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import com.phonegap.api.Plugin;
|
||||
import com.phonegap.api.PluginResult;
|
||||
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.util.Log;
|
||||
|
||||
public class BatteryListener extends Plugin {
|
||||
|
||||
private static final String LOG_TAG = "BatteryManager";
|
||||
|
||||
BroadcastReceiver receiver;
|
||||
|
||||
private String batteryCallbackId = null;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
public BatteryListener() {
|
||||
this.receiver = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes the request and returns PluginResult.
|
||||
*
|
||||
* @param action The action to execute.
|
||||
* @param args JSONArry of arguments for the plugin.
|
||||
* @param callbackId The callback id used when calling back into JavaScript.
|
||||
* @return A PluginResult object with a status and message.
|
||||
*/
|
||||
public PluginResult execute(String action, JSONArray args, String callbackId) {
|
||||
PluginResult.Status status = PluginResult.Status.INVALID_ACTION;
|
||||
String result = "Unsupported Operation: " + action;
|
||||
|
||||
if (action.equals("start")) {
|
||||
if (this.batteryCallbackId != null) {
|
||||
return new PluginResult(PluginResult.Status.ERROR, "Battery listener already running.");
|
||||
}
|
||||
this.batteryCallbackId = callbackId;
|
||||
|
||||
// We need to listen to power events to update battery status
|
||||
IntentFilter intentFilter = new IntentFilter() ;
|
||||
intentFilter.addAction(Intent.ACTION_BATTERY_CHANGED);
|
||||
if (this.receiver == null) {
|
||||
this.receiver = new BroadcastReceiver() {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
updateBatteryInfo(intent);
|
||||
}
|
||||
};
|
||||
ctx.registerReceiver(this.receiver, intentFilter);
|
||||
}
|
||||
|
||||
// Don't return any result now, since status results will be sent when events come in from broadcast receiver
|
||||
PluginResult pluginResult = new PluginResult(PluginResult.Status.NO_RESULT);
|
||||
pluginResult.setKeepCallback(true);
|
||||
return pluginResult;
|
||||
}
|
||||
|
||||
else if (action.equals("stop")) {
|
||||
removeBatteryListener();
|
||||
this.sendUpdate(new JSONObject(), false); // release status callback in JS side
|
||||
this.batteryCallbackId = null;
|
||||
return new PluginResult(PluginResult.Status.OK);
|
||||
}
|
||||
|
||||
return new PluginResult(status, result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop battery receiver.
|
||||
*/
|
||||
public void onDestroy() {
|
||||
removeBatteryListener();
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop the battery receiver and set it to null.
|
||||
*/
|
||||
private void removeBatteryListener() {
|
||||
if (this.receiver != null) {
|
||||
try {
|
||||
this.ctx.unregisterReceiver(this.receiver);
|
||||
this.receiver = null;
|
||||
} catch (Exception e) {
|
||||
Log.e(LOG_TAG, "Error unregistering battery receiver: " + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a JSONObject with the current battery information
|
||||
*
|
||||
* @param batteryIntent the current battery information
|
||||
* @return a JSONObject containing the battery status information
|
||||
*/
|
||||
private JSONObject getBatteryInfo(Intent batteryIntent) {
|
||||
JSONObject obj = new JSONObject();
|
||||
try {
|
||||
obj.put("level", batteryIntent.getIntExtra(android.os.BatteryManager.EXTRA_LEVEL, 0));
|
||||
obj.put("isPlugged", batteryIntent.getIntExtra(android.os.BatteryManager.EXTRA_PLUGGED, -1) > 0 ? true : false);
|
||||
} catch (JSONException e) {
|
||||
Log.e(LOG_TAG, e.getMessage(), e);
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the JavaScript side whenever the battery changes
|
||||
*
|
||||
* @param batteryIntent the current battery information
|
||||
* @return
|
||||
*/
|
||||
private void updateBatteryInfo(Intent batteryIntent) {
|
||||
sendUpdate(this.getBatteryInfo(batteryIntent), true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new plugin result and send it back to JavaScript
|
||||
*
|
||||
* @param connection the network info to set as navigator.connection
|
||||
*/
|
||||
private void sendUpdate(JSONObject info, boolean keepCallback) {
|
||||
if (this.batteryCallbackId != null) {
|
||||
PluginResult result = new PluginResult(PluginResult.Status.OK, info);
|
||||
result.setKeepCallback(keepCallback);
|
||||
this.success(result, this.batteryCallbackId);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,431 +0,0 @@
|
||||
/*
|
||||
Licensed to the Apache Software Foundation (ASF) under one
|
||||
or more contributor license agreements. See the NOTICE file
|
||||
distributed with this work for additional information
|
||||
regarding copyright ownership. The ASF licenses this file
|
||||
to you under the Apache License, Version 2.0 (the
|
||||
"License"); you may not use this file except in compliance
|
||||
with the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing,
|
||||
software distributed under the License is distributed on an
|
||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
KIND, either express or implied. See the License for the
|
||||
specific language governing permissions and limitations
|
||||
under the License.
|
||||
*/
|
||||
package com.phonegap;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.ServerSocket;
|
||||
import java.net.Socket;
|
||||
import java.net.URLEncoder;
|
||||
import java.util.LinkedList;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
/**
|
||||
* This class provides a way for Java to run JavaScript in the web page that has loaded PhoneGap.
|
||||
* The CallbackServer class implements an XHR server and a polling server with a list of JavaScript
|
||||
* statements that are to be executed on the web page.
|
||||
*
|
||||
* The process flow for XHR is:
|
||||
* 1. JavaScript makes an async XHR call.
|
||||
* 2. The server holds the connection open until data is available.
|
||||
* 3. The server writes the data to the client and closes the connection.
|
||||
* 4. The server immediately starts listening for the next XHR call.
|
||||
* 5. The client receives this XHR response, processes it.
|
||||
* 6. The client sends a new async XHR request.
|
||||
*
|
||||
* The CallbackServer class requires the following permission in Android manifest file
|
||||
* <uses-permission android:name="android.permission.INTERNET" />
|
||||
*
|
||||
* If the device has a proxy set, then XHR cannot be used, so polling must be used instead.
|
||||
* This can be determined by the client by calling CallbackServer.usePolling().
|
||||
*
|
||||
* The process flow for polling is:
|
||||
* 1. The client calls CallbackServer.getJavascript() to retrieve next statement.
|
||||
* 2. If statement available, then client processes it.
|
||||
* 3. The client repeats #1 in loop.
|
||||
*/
|
||||
public class CallbackServer implements Runnable {
|
||||
|
||||
private static final String LOG_TAG = "CallbackServer";
|
||||
|
||||
/**
|
||||
* The list of JavaScript statements to be sent to JavaScript.
|
||||
*/
|
||||
private LinkedList<String> javascript;
|
||||
|
||||
/**
|
||||
* The port to listen on.
|
||||
*/
|
||||
private int port;
|
||||
|
||||
/**
|
||||
* The server thread.
|
||||
*/
|
||||
private Thread serverThread;
|
||||
|
||||
/**
|
||||
* Indicates the server is running.
|
||||
*/
|
||||
private boolean active;
|
||||
|
||||
/**
|
||||
* Indicates that the JavaScript statements list is empty
|
||||
*/
|
||||
private boolean empty;
|
||||
|
||||
/**
|
||||
* Indicates that polling should be used instead of XHR.
|
||||
*/
|
||||
private boolean usePolling = true;
|
||||
|
||||
/**
|
||||
* Security token to prevent other apps from accessing this callback server via XHR
|
||||
*/
|
||||
private String token;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
public CallbackServer() {
|
||||
//System.out.println("CallbackServer()");
|
||||
this.active = false;
|
||||
this.empty = true;
|
||||
this.port = 0;
|
||||
this.javascript = new LinkedList<String>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Init callback server and start XHR if running local app.
|
||||
*
|
||||
* If PhoneGap app is loaded from file://, then we can use XHR
|
||||
* otherwise we have to use polling due to cross-domain security restrictions.
|
||||
*
|
||||
* @param url The URL of the PhoneGap app being loaded
|
||||
*/
|
||||
public void init(String url) {
|
||||
//System.out.println("CallbackServer.start("+url+")");
|
||||
this.active = false;
|
||||
this.empty = true;
|
||||
this.port = 0;
|
||||
this.javascript = new LinkedList<String>();
|
||||
|
||||
// Determine if XHR or polling is to be used
|
||||
if ((url != null) && !url.startsWith("file://")) {
|
||||
this.usePolling = true;
|
||||
this.stopServer();
|
||||
}
|
||||
else if (android.net.Proxy.getDefaultHost() != null) {
|
||||
this.usePolling = true;
|
||||
this.stopServer();
|
||||
}
|
||||
else {
|
||||
this.usePolling = false;
|
||||
this.startServer();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Re-init when loading a new HTML page into webview.
|
||||
*
|
||||
* @param url The URL of the PhoneGap app being loaded
|
||||
*/
|
||||
public void reinit(String url) {
|
||||
this.stopServer();
|
||||
this.init(url);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return if polling is being used instead of XHR.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public boolean usePolling() {
|
||||
return this.usePolling;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the port that this server is running on.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public int getPort() {
|
||||
return this.port;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the security token that this server requires when calling getJavascript().
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public String getToken() {
|
||||
return this.token;
|
||||
}
|
||||
|
||||
/**
|
||||
* Start the server on a new thread.
|
||||
*/
|
||||
public void startServer() {
|
||||
//System.out.println("CallbackServer.startServer()");
|
||||
this.active = false;
|
||||
|
||||
// Start server on new thread
|
||||
this.serverThread = new Thread(this);
|
||||
this.serverThread.start();
|
||||
}
|
||||
|
||||
/**
|
||||
* Restart the server on a new thread.
|
||||
*/
|
||||
public void restartServer() {
|
||||
|
||||
// Stop server
|
||||
this.stopServer();
|
||||
|
||||
// Start server again
|
||||
this.startServer();
|
||||
}
|
||||
|
||||
/**
|
||||
* Start running the server.
|
||||
* This is called automatically when the server thread is started.
|
||||
*/
|
||||
public void run() {
|
||||
|
||||
// Start server
|
||||
try {
|
||||
this.active = true;
|
||||
String request;
|
||||
ServerSocket waitSocket = new ServerSocket(0);
|
||||
this.port = waitSocket.getLocalPort();
|
||||
//System.out.println("CallbackServer -- using port " +this.port);
|
||||
this.token = java.util.UUID.randomUUID().toString();
|
||||
//System.out.println("CallbackServer -- using token "+this.token);
|
||||
|
||||
while (this.active) {
|
||||
//System.out.println("CallbackServer: Waiting for data on socket");
|
||||
Socket connection = waitSocket.accept();
|
||||
BufferedReader xhrReader = new BufferedReader(new InputStreamReader(connection.getInputStream()),40);
|
||||
DataOutputStream output = new DataOutputStream(connection.getOutputStream());
|
||||
request = xhrReader.readLine();
|
||||
String response = "";
|
||||
//System.out.println("CallbackServerRequest="+request);
|
||||
if (this.active && (request != null)) {
|
||||
if (request.contains("GET")) {
|
||||
|
||||
// Get requested file
|
||||
String[] requestParts = request.split(" ");
|
||||
|
||||
// Must have security token
|
||||
if ((requestParts.length == 3) && (requestParts[1].substring(1).equals(this.token))) {
|
||||
//System.out.println("CallbackServer -- Processing GET request");
|
||||
|
||||
// Wait until there is some data to send, or send empty data every 10 sec
|
||||
// to prevent XHR timeout on the client
|
||||
synchronized (this) {
|
||||
while (this.empty) {
|
||||
try {
|
||||
this.wait(10000); // prevent timeout from happening
|
||||
//System.out.println("CallbackServer>>> break <<<");
|
||||
break;
|
||||
}
|
||||
catch (Exception e) { }
|
||||
}
|
||||
}
|
||||
|
||||
// If server is still running
|
||||
if (this.active) {
|
||||
|
||||
// If no data, then send 404 back to client before it times out
|
||||
if (this.empty) {
|
||||
//System.out.println("CallbackServer -- sending data 0");
|
||||
response = "HTTP/1.1 404 NO DATA\r\n\r\n "; // need to send content otherwise some Android devices fail, so send space
|
||||
}
|
||||
else {
|
||||
//System.out.println("CallbackServer -- sending item");
|
||||
response = "HTTP/1.1 200 OK\r\n\r\n";
|
||||
String js = this.getJavascript();
|
||||
if (js != null) {
|
||||
response += encode(js, "UTF-8");
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
response = "HTTP/1.1 503 Service Unavailable\r\n\r\n ";
|
||||
}
|
||||
}
|
||||
else {
|
||||
response = "HTTP/1.1 403 Forbidden\r\n\r\n ";
|
||||
}
|
||||
}
|
||||
else {
|
||||
response = "HTTP/1.1 400 Bad Request\r\n\r\n ";
|
||||
}
|
||||
//System.out.println("CallbackServer: response="+response);
|
||||
//System.out.println("CallbackServer: closing output");
|
||||
output.writeBytes(response);
|
||||
output.flush();
|
||||
}
|
||||
output.close();
|
||||
xhrReader.close();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
this.active = false;
|
||||
//System.out.println("CallbackServer.startServer() - EXIT");
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop server.
|
||||
* This stops the thread that the server is running on.
|
||||
*/
|
||||
public void stopServer() {
|
||||
//System.out.println("CallbackServer.stopServer()");
|
||||
if (this.active) {
|
||||
this.active = false;
|
||||
|
||||
// Break out of server wait
|
||||
synchronized (this) {
|
||||
this.notify();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroy
|
||||
*/
|
||||
public void destroy() {
|
||||
this.stopServer();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the number of JavaScript statements.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public int getSize() {
|
||||
synchronized(this) {
|
||||
int size = this.javascript.size();
|
||||
return size;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the next JavaScript statement and remove from list.
|
||||
*
|
||||
* @return String
|
||||
*/
|
||||
public String getJavascript() {
|
||||
synchronized(this) {
|
||||
if (this.javascript.size() == 0) {
|
||||
return null;
|
||||
}
|
||||
String statement = this.javascript.remove(0);
|
||||
if (this.javascript.size() == 0) {
|
||||
this.empty = true;
|
||||
}
|
||||
return statement;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a JavaScript statement to the list.
|
||||
*
|
||||
* @param statement
|
||||
*/
|
||||
public void sendJavascript(String statement) {
|
||||
synchronized (this) {
|
||||
this.javascript.add(statement);
|
||||
this.empty = false;
|
||||
this.notify();
|
||||
}
|
||||
}
|
||||
|
||||
/* The Following code has been modified from original implementation of URLEncoder */
|
||||
|
||||
/* start */
|
||||
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
static final String digits = "0123456789ABCDEF";
|
||||
|
||||
/**
|
||||
* This will encode the return value to JavaScript. We revert the encoding for
|
||||
* common characters that don't require encoding to reduce the size of the string
|
||||
* being passed to JavaScript.
|
||||
*
|
||||
* @param s to be encoded
|
||||
* @param enc encoding type
|
||||
* @return encoded string
|
||||
*/
|
||||
public static String encode(String s, String enc) throws UnsupportedEncodingException {
|
||||
if (s == null || enc == null) {
|
||||
throw new NullPointerException();
|
||||
}
|
||||
// check for UnsupportedEncodingException
|
||||
"".getBytes(enc);
|
||||
|
||||
// Guess a bit bigger for encoded form
|
||||
StringBuilder buf = new StringBuilder(s.length() + 16);
|
||||
int start = -1;
|
||||
for (int i = 0; i < s.length(); i++) {
|
||||
char ch = s.charAt(i);
|
||||
if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z')
|
||||
|| (ch >= '0' && ch <= '9')
|
||||
|| " .-*_'(),<>=?@[]{}:~\"\\/;!".indexOf(ch) > -1) {
|
||||
if (start >= 0) {
|
||||
convert(s.substring(start, i), buf, enc);
|
||||
start = -1;
|
||||
}
|
||||
if (ch != ' ') {
|
||||
buf.append(ch);
|
||||
} else {
|
||||
buf.append(' ');
|
||||
}
|
||||
} else {
|
||||
if (start < 0) {
|
||||
start = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (start >= 0) {
|
||||
convert(s.substring(start, s.length()), buf, enc);
|
||||
}
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
private static void convert(String s, StringBuilder buf, String enc) throws UnsupportedEncodingException {
|
||||
byte[] bytes = s.getBytes(enc);
|
||||
for (int j = 0; j < bytes.length; j++) {
|
||||
buf.append('%');
|
||||
buf.append(digits.charAt((bytes[j] & 0xf0) >> 4));
|
||||
buf.append(digits.charAt(bytes[j] & 0xf));
|
||||
}
|
||||
}
|
||||
|
||||
/* end */
|
||||
}
|
||||
@@ -1,504 +0,0 @@
|
||||
/*
|
||||
Licensed to the Apache Software Foundation (ASF) under one
|
||||
or more contributor license agreements. See the NOTICE file
|
||||
distributed with this work for additional information
|
||||
regarding copyright ownership. The ASF licenses this file
|
||||
to you under the Apache License, Version 2.0 (the
|
||||
"License"); you may not use this file except in compliance
|
||||
with the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing,
|
||||
software distributed under the License is distributed on an
|
||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
KIND, either express or implied. See the License for the
|
||||
specific language governing permissions and limitations
|
||||
under the License.
|
||||
*/
|
||||
package com.phonegap;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
|
||||
import org.apache.commons.codec.binary.Base64;
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import com.phonegap.api.Plugin;
|
||||
import com.phonegap.api.PluginResult;
|
||||
import com.phonegap.api.LOG;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.ContentValues;
|
||||
import android.content.Intent;
|
||||
import android.database.Cursor;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Bitmap.CompressFormat;
|
||||
import android.net.Uri;
|
||||
import android.provider.MediaStore;
|
||||
|
||||
/**
|
||||
* This class launches the camera view, allows the user to take a picture, closes the camera view,
|
||||
* and returns the captured image. When the camera view is closed, the screen displayed before
|
||||
* the camera view was shown is redisplayed.
|
||||
*/
|
||||
public class CameraLauncher extends Plugin {
|
||||
|
||||
private static final int DATA_URL = 0; // Return base64 encoded string
|
||||
private static final int FILE_URI = 1; // Return file uri (content://media/external/images/media/2 for Android)
|
||||
|
||||
private static final int PHOTOLIBRARY = 0; // Choose image from picture library (same as SAVEDPHOTOALBUM for Android)
|
||||
private static final int CAMERA = 1; // Take picture from camera
|
||||
private static final int SAVEDPHOTOALBUM = 2; // Choose image from picture library (same as PHOTOLIBRARY for Android)
|
||||
|
||||
private static final int PICTURE = 0; // allow selection of still pictures only. DEFAULT. Will return format specified via DestinationType
|
||||
private static final int VIDEO = 1; // allow selection of video only, ONLY RETURNS URL
|
||||
private static final int ALLMEDIA = 2; // allow selection from all media types
|
||||
|
||||
private static final int JPEG = 0; // Take a picture of type JPEG
|
||||
private static final int PNG = 1; // Take a picture of type PNG
|
||||
private static final String GET_PICTURE = "Get Picture";
|
||||
private static final String GET_VIDEO = "Get Video";
|
||||
private static final String GET_All = "Get All";
|
||||
|
||||
private static final String LOG_TAG = "CameraLauncher";
|
||||
|
||||
private int mQuality; // Compression quality hint (0-100: 0=low quality & high compression, 100=compress of max quality)
|
||||
private int targetWidth; // desired width of the image
|
||||
private int targetHeight; // desired height of the image
|
||||
private Uri imageUri; // Uri of captured image
|
||||
private int encodingType; // Type of encoding to use
|
||||
private int mediaType; // What type of media to retrieve
|
||||
|
||||
public String callbackId;
|
||||
private int numPics;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
public CameraLauncher() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes the request and returns PluginResult.
|
||||
*
|
||||
* @param action The action to execute.
|
||||
* @param args JSONArry of arguments for the plugin.
|
||||
* @param callbackId The callback id used when calling back into JavaScript.
|
||||
* @return A PluginResult object with a status and message.
|
||||
*/
|
||||
public PluginResult execute(String action, JSONArray args, String callbackId) {
|
||||
PluginResult.Status status = PluginResult.Status.OK;
|
||||
String result = "";
|
||||
this.callbackId = callbackId;
|
||||
|
||||
try {
|
||||
if (action.equals("takePicture")) {
|
||||
int srcType = CAMERA;
|
||||
int destType = FILE_URI;
|
||||
this.targetHeight = 0;
|
||||
this.targetWidth = 0;
|
||||
this.encodingType = JPEG;
|
||||
this.mediaType = PICTURE;
|
||||
this.mQuality = 80;
|
||||
|
||||
JSONObject options = args.optJSONObject(0);
|
||||
if (options != null) {
|
||||
srcType = options.getInt("sourceType");
|
||||
destType = options.getInt("destinationType");
|
||||
this.targetHeight = options.getInt("targetHeight");
|
||||
this.targetWidth = options.getInt("targetWidth");
|
||||
this.encodingType = options.getInt("encodingType");
|
||||
this.mediaType = options.getInt("mediaType");
|
||||
this.mQuality = options.getInt("quality");
|
||||
}
|
||||
|
||||
if (srcType == CAMERA) {
|
||||
this.takePicture(destType, encodingType);
|
||||
}
|
||||
else if ((srcType == PHOTOLIBRARY) || (srcType == SAVEDPHOTOALBUM)) {
|
||||
this.getImage(srcType, destType);
|
||||
}
|
||||
PluginResult r = new PluginResult(PluginResult.Status.NO_RESULT);
|
||||
r.setKeepCallback(true);
|
||||
return r;
|
||||
}
|
||||
return new PluginResult(status, result);
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
return new PluginResult(PluginResult.Status.JSON_EXCEPTION);
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// LOCAL METHODS
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Take a picture with the camera.
|
||||
* When an image is captured or the camera view is cancelled, the result is returned
|
||||
* in PhonegapActivity.onActivityResult, which forwards the result to this.onActivityResult.
|
||||
*
|
||||
* The image can either be returned as a base64 string or a URI that points to the file.
|
||||
* To display base64 string in an img tag, set the source to:
|
||||
* img.src="data:image/jpeg;base64,"+result;
|
||||
* or to display URI in an img tag
|
||||
* img.src=result;
|
||||
*
|
||||
* @param quality Compression quality hint (0-100: 0=low quality & high compression, 100=compress of max quality)
|
||||
* @param returnType Set the type of image to return.
|
||||
*/
|
||||
public void takePicture(int returnType, int encodingType) {
|
||||
// Save the number of images currently on disk for later
|
||||
this.numPics = queryImgDB().getCount();
|
||||
|
||||
// Display camera
|
||||
Intent intent = new Intent("android.media.action.IMAGE_CAPTURE");
|
||||
|
||||
// Specify file so that large image is captured and returned
|
||||
// TODO: What if there isn't any external storage?
|
||||
File photo = createCaptureFile(encodingType);
|
||||
intent.putExtra(android.provider.MediaStore.EXTRA_OUTPUT, Uri.fromFile(photo));
|
||||
this.imageUri = Uri.fromFile(photo);
|
||||
|
||||
this.ctx.startActivityForResult((Plugin) this, intent, (CAMERA+1)*16 + returnType+1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a file in the applications temporary directory based upon the supplied encoding.
|
||||
*
|
||||
* @param encodingType of the image to be taken
|
||||
* @return a File object pointing to the temporary picture
|
||||
*/
|
||||
private File createCaptureFile(int encodingType) {
|
||||
File photo = null;
|
||||
if (encodingType == JPEG) {
|
||||
photo = new File(DirectoryManager.getTempDirectoryPath(ctx), "Pic.jpg");
|
||||
} else if (encodingType == PNG) {
|
||||
photo = new File(DirectoryManager.getTempDirectoryPath(ctx), "Pic.png");
|
||||
} else {
|
||||
throw new IllegalArgumentException("Invalid Encoding Type: " + encodingType);
|
||||
}
|
||||
return photo;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get image from photo library.
|
||||
*
|
||||
* @param quality Compression quality hint (0-100: 0=low quality & high compression, 100=compress of max quality)
|
||||
* @param srcType The album to get image from.
|
||||
* @param returnType Set the type of image to return.
|
||||
*/
|
||||
// TODO: Images selected from SDCARD don't display correctly, but from CAMERA ALBUM do!
|
||||
public void getImage(int srcType, int returnType) {
|
||||
Intent intent = new Intent();
|
||||
String title = GET_PICTURE;
|
||||
if (this.mediaType == PICTURE) {
|
||||
intent.setType("image/*");
|
||||
}
|
||||
else if (this.mediaType == VIDEO) {
|
||||
intent.setType("video/*");
|
||||
title = GET_VIDEO;
|
||||
}
|
||||
else if (this.mediaType == ALLMEDIA) {
|
||||
// I wanted to make the type 'image/*, video/*' but this does not work on all versions
|
||||
// of android so I had to go with the wildcard search.
|
||||
intent.setType("*/*");
|
||||
title = GET_All;
|
||||
}
|
||||
|
||||
intent.setAction(Intent.ACTION_GET_CONTENT);
|
||||
intent.addCategory(Intent.CATEGORY_OPENABLE);
|
||||
this.ctx.startActivityForResult((Plugin) this, Intent.createChooser(intent,
|
||||
new String(title)), (srcType+1)*16 + returnType + 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Scales the bitmap according to the requested size.
|
||||
*
|
||||
* @param bitmap The bitmap to scale.
|
||||
* @return Bitmap A new Bitmap object of the same bitmap after scaling.
|
||||
*/
|
||||
public Bitmap scaleBitmap(Bitmap bitmap) {
|
||||
int newWidth = this.targetWidth;
|
||||
int newHeight = this.targetHeight;
|
||||
int origWidth = bitmap.getWidth();
|
||||
int origHeight = bitmap.getHeight();
|
||||
|
||||
// If no new width or height were specified return the original bitmap
|
||||
if (newWidth <= 0 && newHeight <= 0) {
|
||||
return bitmap;
|
||||
}
|
||||
// Only the width was specified
|
||||
else if (newWidth > 0 && newHeight <= 0) {
|
||||
newHeight = (newWidth * origHeight) / origWidth;
|
||||
}
|
||||
// only the height was specified
|
||||
else if (newWidth <= 0 && newHeight > 0) {
|
||||
newWidth = (newHeight * origWidth) / origHeight;
|
||||
}
|
||||
// If the user specified both a positive width and height
|
||||
// (potentially different aspect ratio) then the width or height is
|
||||
// scaled so that the image fits while maintaining aspect ratio.
|
||||
// Alternatively, the specified width and height could have been
|
||||
// kept and Bitmap.SCALE_TO_FIT specified when scaling, but this
|
||||
// would result in whitespace in the new image.
|
||||
else {
|
||||
double newRatio = newWidth / (double)newHeight;
|
||||
double origRatio = origWidth / (double)origHeight;
|
||||
|
||||
if (origRatio > newRatio) {
|
||||
newHeight = (newWidth * origHeight) / origWidth;
|
||||
} else if (origRatio < newRatio) {
|
||||
newWidth = (newHeight * origWidth) / origHeight;
|
||||
}
|
||||
}
|
||||
|
||||
return Bitmap.createScaledBitmap(bitmap, newWidth, newHeight, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the camera view exits.
|
||||
*
|
||||
* @param requestCode The request code originally supplied to startActivityForResult(),
|
||||
* allowing you to identify who this result came from.
|
||||
* @param resultCode The integer result code returned by the child activity through its setResult().
|
||||
* @param intent An Intent, which can return result data to the caller (various data can be attached to Intent "extras").
|
||||
*/
|
||||
public void onActivityResult(int requestCode, int resultCode, Intent intent) {
|
||||
|
||||
// Get src and dest types from request code
|
||||
int srcType = (requestCode/16) - 1;
|
||||
int destType = (requestCode % 16) - 1;
|
||||
|
||||
// If CAMERA
|
||||
if (srcType == CAMERA) {
|
||||
// If image available
|
||||
if (resultCode == Activity.RESULT_OK) {
|
||||
try {
|
||||
// Create an ExifHelper to save the exif data that is lost during compression
|
||||
ExifHelper exif = new ExifHelper();
|
||||
if (this.encodingType == JPEG) {
|
||||
exif.createInFile(DirectoryManager.getTempDirectoryPath(ctx) + "/Pic.jpg");
|
||||
exif.readExifData();
|
||||
}
|
||||
|
||||
// Read in bitmap of captured image
|
||||
Bitmap bitmap;
|
||||
try {
|
||||
bitmap = android.provider.MediaStore.Images.Media.getBitmap(this.ctx.getContentResolver(), imageUri);
|
||||
} catch (FileNotFoundException e) {
|
||||
Uri uri = intent.getData();
|
||||
android.content.ContentResolver resolver = this.ctx.getContentResolver();
|
||||
bitmap = android.graphics.BitmapFactory.decodeStream(resolver.openInputStream(uri));
|
||||
}
|
||||
|
||||
bitmap = scaleBitmap(bitmap);
|
||||
|
||||
// If sending base64 image back
|
||||
if (destType == DATA_URL) {
|
||||
this.processPicture(bitmap);
|
||||
checkForDuplicateImage(DATA_URL);
|
||||
}
|
||||
|
||||
// If sending filename back
|
||||
else if (destType == FILE_URI){
|
||||
// Create entry in media store for image
|
||||
// (Don't use insertImage() because it uses default compression setting of 50 - no way to change it)
|
||||
ContentValues values = new ContentValues();
|
||||
values.put(android.provider.MediaStore.Images.Media.MIME_TYPE, "image/jpeg");
|
||||
Uri uri = null;
|
||||
try {
|
||||
uri = this.ctx.getContentResolver().insert(android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
|
||||
} catch (UnsupportedOperationException e) {
|
||||
LOG.d(LOG_TAG, "Can't write to external media storage.");
|
||||
try {
|
||||
uri = this.ctx.getContentResolver().insert(android.provider.MediaStore.Images.Media.INTERNAL_CONTENT_URI, values);
|
||||
} catch (UnsupportedOperationException ex) {
|
||||
LOG.d(LOG_TAG, "Can't write to internal media storage.");
|
||||
this.failPicture("Error capturing image - no media storage found.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Add compressed version of captured image to returned media store Uri
|
||||
OutputStream os = this.ctx.getContentResolver().openOutputStream(uri);
|
||||
bitmap.compress(Bitmap.CompressFormat.JPEG, this.mQuality, os);
|
||||
os.close();
|
||||
|
||||
// Restore exif data to file
|
||||
if (this.encodingType == JPEG) {
|
||||
exif.createOutFile(FileUtils.getRealPathFromURI(uri, this.ctx));
|
||||
exif.writeExifData();
|
||||
}
|
||||
|
||||
// Send Uri back to JavaScript for viewing image
|
||||
this.success(new PluginResult(PluginResult.Status.OK, uri.toString()), this.callbackId);
|
||||
}
|
||||
bitmap.recycle();
|
||||
bitmap = null;
|
||||
System.gc();
|
||||
|
||||
checkForDuplicateImage(FILE_URI);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
this.failPicture("Error capturing image.");
|
||||
}
|
||||
}
|
||||
|
||||
// If cancelled
|
||||
else if (resultCode == Activity.RESULT_CANCELED) {
|
||||
this.failPicture("Camera cancelled.");
|
||||
}
|
||||
|
||||
// If something else
|
||||
else {
|
||||
this.failPicture("Did not complete!");
|
||||
}
|
||||
}
|
||||
|
||||
// If retrieving photo from library
|
||||
else if ((srcType == PHOTOLIBRARY) || (srcType == SAVEDPHOTOALBUM)) {
|
||||
if (resultCode == Activity.RESULT_OK) {
|
||||
Uri uri = intent.getData();
|
||||
android.content.ContentResolver resolver = this.ctx.getContentResolver();
|
||||
|
||||
// If you ask for video or all media type you will automatically get back a file URI
|
||||
// and there will be no attempt to resize any returned data
|
||||
if (this.mediaType != PICTURE) {
|
||||
this.success(new PluginResult(PluginResult.Status.OK, uri.toString()), this.callbackId);
|
||||
}
|
||||
else {
|
||||
// If sending base64 image back
|
||||
if (destType == DATA_URL) {
|
||||
try {
|
||||
Bitmap bitmap = android.graphics.BitmapFactory.decodeStream(resolver.openInputStream(uri));
|
||||
bitmap = scaleBitmap(bitmap);
|
||||
this.processPicture(bitmap);
|
||||
bitmap.recycle();
|
||||
bitmap = null;
|
||||
System.gc();
|
||||
} catch (FileNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
this.failPicture("Error retrieving image.");
|
||||
}
|
||||
}
|
||||
|
||||
// If sending filename back
|
||||
else if (destType == FILE_URI) {
|
||||
// Do we need to scale the returned file
|
||||
if (this.targetHeight > 0 && this.targetWidth > 0) {
|
||||
try {
|
||||
Bitmap bitmap = android.graphics.BitmapFactory.decodeStream(resolver.openInputStream(uri));
|
||||
bitmap = scaleBitmap(bitmap);
|
||||
|
||||
String fileName = DirectoryManager.getTempDirectoryPath(ctx) + "/resize.jpg";
|
||||
OutputStream os = new FileOutputStream(fileName);
|
||||
bitmap.compress(Bitmap.CompressFormat.JPEG, this.mQuality, os);
|
||||
os.close();
|
||||
|
||||
bitmap.recycle();
|
||||
bitmap = null;
|
||||
|
||||
// The resized image is cached by the app in order to get around this and not have to delete you
|
||||
// application cache I'm adding the current system time to the end of the file url.
|
||||
this.success(new PluginResult(PluginResult.Status.OK, ("file://" + fileName + "?" + System.currentTimeMillis())), this.callbackId);
|
||||
System.gc();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
this.failPicture("Error retrieving image.");
|
||||
}
|
||||
}
|
||||
else {
|
||||
this.success(new PluginResult(PluginResult.Status.OK, uri.toString()), this.callbackId);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (resultCode == Activity.RESULT_CANCELED) {
|
||||
this.failPicture("Selection cancelled.");
|
||||
}
|
||||
else {
|
||||
this.failPicture("Selection did not complete!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a cursor that can be used to determine how many images we have.
|
||||
*
|
||||
* @return a cursor
|
||||
*/
|
||||
private Cursor queryImgDB() {
|
||||
return this.ctx.getContentResolver().query(
|
||||
android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
|
||||
new String[] { MediaStore.Images.Media._ID },
|
||||
null,
|
||||
null,
|
||||
null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to find out if we are in a situation where the Camera Intent adds to images
|
||||
* to the content store. If we are using a FILE_URI and the number of images in the DB
|
||||
* increases by 2 we have a duplicate, when using a DATA_URL the number is 1.
|
||||
*
|
||||
* @param type FILE_URI or DATA_URL
|
||||
*/
|
||||
private void checkForDuplicateImage(int type) {
|
||||
int diff = 1;
|
||||
Cursor cursor = queryImgDB();
|
||||
int currentNumOfImages = cursor.getCount();
|
||||
|
||||
if (type == FILE_URI) {
|
||||
diff = 2;
|
||||
}
|
||||
|
||||
// delete the duplicate file if the difference is 2 for file URI or 1 for Data URL
|
||||
if ((currentNumOfImages - numPics) == diff) {
|
||||
cursor.moveToLast();
|
||||
int id = Integer.valueOf(cursor.getString(cursor.getColumnIndex(MediaStore.Images.Media._ID))) - 1;
|
||||
Uri uri = Uri.parse(MediaStore.Images.Media.EXTERNAL_CONTENT_URI + "/" + id);
|
||||
this.ctx.getContentResolver().delete(uri, null, null);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Compress bitmap using jpeg, convert to Base64 encoded string, and return to JavaScript.
|
||||
*
|
||||
* @param bitmap
|
||||
*/
|
||||
public void processPicture(Bitmap bitmap) {
|
||||
ByteArrayOutputStream jpeg_data = new ByteArrayOutputStream();
|
||||
try {
|
||||
if (bitmap.compress(CompressFormat.JPEG, mQuality, jpeg_data)) {
|
||||
byte[] code = jpeg_data.toByteArray();
|
||||
byte[] output = Base64.encodeBase64(code);
|
||||
String js_out = new String(output);
|
||||
this.success(new PluginResult(PluginResult.Status.OK, js_out), this.callbackId);
|
||||
js_out = null;
|
||||
output = null;
|
||||
code = null;
|
||||
}
|
||||
}
|
||||
catch(Exception e) {
|
||||
this.failPicture("Error compressing image.");
|
||||
}
|
||||
jpeg_data = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Send error message to JavaScript.
|
||||
*
|
||||
* @param err
|
||||
*/
|
||||
public void failPicture(String err) {
|
||||
this.error(new PluginResult(PluginResult.Status.ERROR, err), this.callbackId);
|
||||
}
|
||||
}
|
||||
@@ -1,399 +0,0 @@
|
||||
/*
|
||||
Licensed to the Apache Software Foundation (ASF) under one
|
||||
or more contributor license agreements. See the NOTICE file
|
||||
distributed with this work for additional information
|
||||
regarding copyright ownership. The ASF licenses this file
|
||||
to you under the Apache License, Version 2.0 (the
|
||||
"License"); you may not use this file except in compliance
|
||||
with the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing,
|
||||
software distributed under the License is distributed on an
|
||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
KIND, either express or implied. See the License for the
|
||||
specific language governing permissions and limitations
|
||||
under the License.
|
||||
*/
|
||||
package com.phonegap;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.ContentValues;
|
||||
import android.content.Intent;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.BitmapFactory;
|
||||
import android.media.MediaPlayer;
|
||||
import android.net.Uri;
|
||||
import android.util.Log;
|
||||
|
||||
import com.phonegap.api.LOG;
|
||||
import com.phonegap.api.Plugin;
|
||||
import com.phonegap.api.PluginResult;
|
||||
|
||||
public class Capture extends Plugin {
|
||||
|
||||
private static final String VIDEO_3GPP = "video/3gpp";
|
||||
private static final String AUDIO_3GPP = "audio/3gpp";
|
||||
private static final String IMAGE_JPEG = "image/jpeg";
|
||||
|
||||
private static final int CAPTURE_AUDIO = 0; // Constant for capture audio
|
||||
private static final int CAPTURE_IMAGE = 1; // Constant for capture image
|
||||
private static final int CAPTURE_VIDEO = 2; // Constant for capture video
|
||||
private static final String LOG_TAG = "Capture";
|
||||
|
||||
private static final int CAPTURE_INTERNAL_ERR = 0;
|
||||
private static final int CAPTURE_APPLICATION_BUSY = 1;
|
||||
private static final int CAPTURE_INVALID_ARGUMENT = 2;
|
||||
private static final int CAPTURE_NO_MEDIA_FILES = 3;
|
||||
private static final int CAPTURE_NOT_SUPPORTED = 20;
|
||||
|
||||
private String callbackId; // The ID of the callback to be invoked with our result
|
||||
private long limit; // the number of pics/vids/clips to take
|
||||
private double duration; // optional duration parameter for video recording
|
||||
private JSONArray results; // The array of results to be returned to the user
|
||||
private Uri imageUri; // Uri of captured image
|
||||
|
||||
@Override
|
||||
public PluginResult execute(String action, JSONArray args, String callbackId) {
|
||||
this.callbackId = callbackId;
|
||||
this.limit = 1;
|
||||
this.duration = 0.0f;
|
||||
this.results = new JSONArray();
|
||||
|
||||
JSONObject options = args.optJSONObject(0);
|
||||
if (options != null) {
|
||||
limit = options.optLong("limit", 1);
|
||||
duration = options.optDouble("duration", 0.0f);
|
||||
}
|
||||
|
||||
if (action.equals("getFormatData")) {
|
||||
try {
|
||||
JSONObject obj = getFormatData(args.getString(0), args.getString(1));
|
||||
return new PluginResult(PluginResult.Status.OK, obj);
|
||||
} catch (JSONException e) {
|
||||
return new PluginResult(PluginResult.Status.ERROR);
|
||||
}
|
||||
}
|
||||
else if (action.equals("captureAudio")) {
|
||||
this.captureAudio();
|
||||
}
|
||||
else if (action.equals("captureImage")) {
|
||||
this.captureImage();
|
||||
}
|
||||
else if (action.equals("captureVideo")) {
|
||||
this.captureVideo(duration);
|
||||
}
|
||||
|
||||
PluginResult r = new PluginResult(PluginResult.Status.NO_RESULT);
|
||||
r.setKeepCallback(true);
|
||||
return r;
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides the media data file data depending on it's mime type
|
||||
*
|
||||
* @param filePath path to the file
|
||||
* @param mimeType of the file
|
||||
* @return a MediaFileData object
|
||||
*/
|
||||
private JSONObject getFormatData(String filePath, String mimeType) {
|
||||
JSONObject obj = new JSONObject();
|
||||
try {
|
||||
// setup defaults
|
||||
obj.put("height", 0);
|
||||
obj.put("width", 0);
|
||||
obj.put("bitrate", 0);
|
||||
obj.put("duration", 0);
|
||||
obj.put("codecs", "");
|
||||
|
||||
// If the mimeType isn't set the rest will fail
|
||||
// so let's see if we can determine it.
|
||||
if (mimeType == null || mimeType.equals("")) {
|
||||
mimeType = FileUtils.getMimeType(filePath);
|
||||
}
|
||||
Log.d(LOG_TAG, "Mime type = " + mimeType);
|
||||
|
||||
if (mimeType.equals(IMAGE_JPEG) || filePath.endsWith(".jpg")) {
|
||||
obj = getImageData(filePath, obj);
|
||||
}
|
||||
else if (mimeType.endsWith(AUDIO_3GPP)) {
|
||||
obj = getAudioVideoData(filePath, obj, false);
|
||||
}
|
||||
else if (mimeType.equals(VIDEO_3GPP)) {
|
||||
obj = getAudioVideoData(filePath, obj, true);
|
||||
}
|
||||
}
|
||||
catch (JSONException e) {
|
||||
Log.d(LOG_TAG, "Error: setting media file data object");
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Image specific attributes
|
||||
*
|
||||
* @param filePath path to the file
|
||||
* @param obj represents the Media File Data
|
||||
* @return a JSONObject that represents the Media File Data
|
||||
* @throws JSONException
|
||||
*/
|
||||
private JSONObject getImageData(String filePath, JSONObject obj) throws JSONException {
|
||||
Bitmap bitmap = BitmapFactory.decodeFile(filePath);
|
||||
obj.put("height", bitmap.getHeight());
|
||||
obj.put("width", bitmap.getWidth());
|
||||
return obj;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Image specific attributes
|
||||
*
|
||||
* @param filePath path to the file
|
||||
* @param obj represents the Media File Data
|
||||
* @param video if true get video attributes as well
|
||||
* @return a JSONObject that represents the Media File Data
|
||||
* @throws JSONException
|
||||
*/
|
||||
private JSONObject getAudioVideoData(String filePath, JSONObject obj, boolean video) throws JSONException {
|
||||
MediaPlayer player = new MediaPlayer();
|
||||
try {
|
||||
player.setDataSource(filePath);
|
||||
player.prepare();
|
||||
obj.put("duration", player.getDuration());
|
||||
if (video) {
|
||||
obj.put("height", player.getVideoHeight());
|
||||
obj.put("width", player.getVideoWidth());
|
||||
}
|
||||
}
|
||||
catch (IOException e) {
|
||||
Log.d(LOG_TAG, "Error: loading video file");
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets up an intent to capture audio. Result handled by onActivityResult()
|
||||
*/
|
||||
private void captureAudio() {
|
||||
Intent intent = new Intent(android.provider.MediaStore.Audio.Media.RECORD_SOUND_ACTION);
|
||||
|
||||
this.ctx.startActivityForResult((Plugin) this, intent, CAPTURE_AUDIO);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets up an intent to capture images. Result handled by onActivityResult()
|
||||
*/
|
||||
private void captureImage() {
|
||||
Intent intent = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
|
||||
|
||||
// Specify file so that large image is captured and returned
|
||||
File photo = new File(DirectoryManager.getTempDirectoryPath(ctx), "Capture.jpg");
|
||||
intent.putExtra(android.provider.MediaStore.EXTRA_OUTPUT, Uri.fromFile(photo));
|
||||
this.imageUri = Uri.fromFile(photo);
|
||||
|
||||
this.ctx.startActivityForResult((Plugin) this, intent, CAPTURE_IMAGE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets up an intent to capture video. Result handled by onActivityResult()
|
||||
*/
|
||||
private void captureVideo(double duration) {
|
||||
Intent intent = new Intent(android.provider.MediaStore.ACTION_VIDEO_CAPTURE);
|
||||
// Introduced in API 8
|
||||
//intent.putExtra(android.provider.MediaStore.EXTRA_DURATION_LIMIT, duration);
|
||||
|
||||
this.ctx.startActivityForResult((Plugin) this, intent, CAPTURE_VIDEO);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the video view exits.
|
||||
*
|
||||
* @param requestCode The request code originally supplied to startActivityForResult(),
|
||||
* allowing you to identify who this result came from.
|
||||
* @param resultCode The integer result code returned by the child activity through its setResult().
|
||||
* @param intent An Intent, which can return result data to the caller (various data can be attached to Intent "extras").
|
||||
* @throws JSONException
|
||||
*/
|
||||
public void onActivityResult(int requestCode, int resultCode, Intent intent) {
|
||||
|
||||
// Result received okay
|
||||
if (resultCode == Activity.RESULT_OK) {
|
||||
// An audio clip was requested
|
||||
if (requestCode == CAPTURE_AUDIO) {
|
||||
// Get the uri of the audio clip
|
||||
Uri data = intent.getData();
|
||||
// create a file object from the uri
|
||||
results.put(createMediaFile(data));
|
||||
|
||||
if (results.length() >= limit) {
|
||||
// Send Uri back to JavaScript for listening to audio
|
||||
this.success(new PluginResult(PluginResult.Status.OK, results, "navigator.device.capture._castMediaFile"), this.callbackId);
|
||||
} else {
|
||||
// still need to capture more audio clips
|
||||
captureAudio();
|
||||
}
|
||||
} else if (requestCode == CAPTURE_IMAGE) {
|
||||
// For some reason if I try to do:
|
||||
// Uri data = intent.getData();
|
||||
// It crashes in the emulator and on my phone with a null pointer exception
|
||||
// To work around it I had to grab the code from CameraLauncher.java
|
||||
try {
|
||||
// Create an ExifHelper to save the exif data that is lost during compression
|
||||
ExifHelper exif = new ExifHelper();
|
||||
exif.createInFile(DirectoryManager.getTempDirectoryPath(ctx) + "/Capture.jpg");
|
||||
exif.readExifData();
|
||||
|
||||
// Read in bitmap of captured image
|
||||
Bitmap bitmap = android.provider.MediaStore.Images.Media.getBitmap(this.ctx.getContentResolver(), imageUri);
|
||||
|
||||
// Create entry in media store for image
|
||||
// (Don't use insertImage() because it uses default compression setting of 50 - no way to change it)
|
||||
ContentValues values = new ContentValues();
|
||||
values.put(android.provider.MediaStore.Images.Media.MIME_TYPE, IMAGE_JPEG);
|
||||
Uri uri = null;
|
||||
try {
|
||||
uri = this.ctx.getContentResolver().insert(android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
|
||||
} catch (UnsupportedOperationException e) {
|
||||
LOG.d(LOG_TAG, "Can't write to external media storage.");
|
||||
try {
|
||||
uri = this.ctx.getContentResolver().insert(android.provider.MediaStore.Images.Media.INTERNAL_CONTENT_URI, values);
|
||||
} catch (UnsupportedOperationException ex) {
|
||||
LOG.d(LOG_TAG, "Can't write to internal media storage.");
|
||||
this.fail(createErrorObject(CAPTURE_INTERNAL_ERR, "Error capturing image - no media storage found."));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Add compressed version of captured image to returned media store Uri
|
||||
OutputStream os = this.ctx.getContentResolver().openOutputStream(uri);
|
||||
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, os);
|
||||
os.close();
|
||||
|
||||
bitmap.recycle();
|
||||
bitmap = null;
|
||||
System.gc();
|
||||
|
||||
// Restore exif data to file
|
||||
exif.createOutFile(FileUtils.getRealPathFromURI(uri, this.ctx));
|
||||
exif.writeExifData();
|
||||
|
||||
// Add image to results
|
||||
results.put(createMediaFile(uri));
|
||||
|
||||
if (results.length() >= limit) {
|
||||
// Send Uri back to JavaScript for viewing image
|
||||
this.success(new PluginResult(PluginResult.Status.OK, results, "navigator.device.capture._castMediaFile"), this.callbackId);
|
||||
} else {
|
||||
// still need to capture more images
|
||||
captureImage();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
this.fail(createErrorObject(CAPTURE_INTERNAL_ERR, "Error capturing image."));
|
||||
}
|
||||
} else if (requestCode == CAPTURE_VIDEO) {
|
||||
// Get the uri of the video clip
|
||||
Uri data = intent.getData();
|
||||
// create a file object from the uri
|
||||
results.put(createMediaFile(data));
|
||||
|
||||
if (results.length() >= limit) {
|
||||
// Send Uri back to JavaScript for viewing video
|
||||
this.success(new PluginResult(PluginResult.Status.OK, results, "navigator.device.capture._castMediaFile"), this.callbackId);
|
||||
} else {
|
||||
// still need to capture more video clips
|
||||
captureVideo(duration);
|
||||
}
|
||||
}
|
||||
}
|
||||
// If canceled
|
||||
else if (resultCode == Activity.RESULT_CANCELED) {
|
||||
// If we have partial results send them back to the user
|
||||
if (results.length() > 0) {
|
||||
this.success(new PluginResult(PluginResult.Status.OK, results, "navigator.device.capture._castMediaFile"), this.callbackId);
|
||||
}
|
||||
// user canceled the action
|
||||
else {
|
||||
this.fail(createErrorObject(CAPTURE_NO_MEDIA_FILES, "Canceled."));
|
||||
}
|
||||
}
|
||||
// If something else
|
||||
else {
|
||||
// If we have partial results send them back to the user
|
||||
if (results.length() > 0) {
|
||||
this.success(new PluginResult(PluginResult.Status.OK, results, "navigator.device.capture._castMediaFile"), this.callbackId);
|
||||
}
|
||||
// something bad happened
|
||||
else {
|
||||
this.fail(createErrorObject(CAPTURE_NO_MEDIA_FILES, "Did not complete!"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a JSONObject that represents a File from the Uri
|
||||
*
|
||||
* @param data the Uri of the audio/image/video
|
||||
* @return a JSONObject that represents a File
|
||||
* @throws IOException
|
||||
*/
|
||||
private JSONObject createMediaFile(Uri data){
|
||||
File fp = new File(FileUtils.getRealPathFromURI(data, this.ctx));
|
||||
JSONObject obj = new JSONObject();
|
||||
|
||||
try {
|
||||
// File properties
|
||||
obj.put("name", fp.getName());
|
||||
obj.put("fullPath", fp.getAbsolutePath());
|
||||
|
||||
// Because of an issue with MimeTypeMap.getMimeTypeFromExtension() all .3gpp files
|
||||
// are reported as video/3gpp. I'm doing this hacky check of the URI to see if it
|
||||
// is stored in the audio or video content store.
|
||||
if (fp.getAbsoluteFile().toString().endsWith(".3gp") || fp.getAbsoluteFile().toString().endsWith(".3gpp")) {
|
||||
if (data.toString().contains("/audio/")) {
|
||||
obj.put("type", AUDIO_3GPP);
|
||||
} else {
|
||||
obj.put("type", VIDEO_3GPP);
|
||||
}
|
||||
} else {
|
||||
obj.put("type", FileUtils.getMimeType(fp.getAbsolutePath()));
|
||||
}
|
||||
|
||||
obj.put("lastModifiedDate", fp.lastModified());
|
||||
obj.put("size", fp.length());
|
||||
} catch (JSONException e) {
|
||||
// this will never happen
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
private JSONObject createErrorObject(int code, String message) {
|
||||
JSONObject obj = new JSONObject();
|
||||
try {
|
||||
obj.put("code", code);
|
||||
obj.put("message", message);
|
||||
} catch (JSONException e) {
|
||||
// This will never happen
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
|
||||
/**
|
||||
* Send error message to JavaScript.
|
||||
*
|
||||
* @param err
|
||||
*/
|
||||
public void fail(JSONObject err) {
|
||||
this.error(new PluginResult(PluginResult.Status.ERROR, err), this.callbackId);
|
||||
}
|
||||
}
|
||||
@@ -1,305 +0,0 @@
|
||||
/*
|
||||
Licensed to the Apache Software Foundation (ASF) under one
|
||||
or more contributor license agreements. See the NOTICE file
|
||||
distributed with this work for additional information
|
||||
regarding copyright ownership. The ASF licenses this file
|
||||
to you under the Apache License, Version 2.0 (the
|
||||
"License"); you may not use this file except in compliance
|
||||
with the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing,
|
||||
software distributed under the License is distributed on an
|
||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
KIND, either express or implied. See the License for the
|
||||
specific language governing permissions and limitations
|
||||
under the License.
|
||||
*/
|
||||
package com.phonegap;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import com.phonegap.api.PhonegapActivity;
|
||||
import com.phonegap.api.Plugin;
|
||||
import com.phonegap.api.PluginResult;
|
||||
|
||||
import android.hardware.Sensor;
|
||||
import android.hardware.SensorEvent;
|
||||
import android.hardware.SensorEventListener;
|
||||
import android.hardware.SensorManager;
|
||||
import android.content.Context;
|
||||
|
||||
/**
|
||||
* This class listens to the compass sensor and stores the latest heading value.
|
||||
*/
|
||||
public class CompassListener extends Plugin implements SensorEventListener {
|
||||
|
||||
public static int STOPPED = 0;
|
||||
public static int STARTING = 1;
|
||||
public static int RUNNING = 2;
|
||||
public static int ERROR_FAILED_TO_START = 3;
|
||||
|
||||
public long TIMEOUT = 30000; // Timeout in msec to shut off listener
|
||||
|
||||
int status; // status of listener
|
||||
float heading; // most recent heading value
|
||||
long timeStamp; // time of most recent value
|
||||
long lastAccessTime; // time the value was last retrieved
|
||||
int accuracy; // accuracy of the sensor
|
||||
|
||||
private SensorManager sensorManager;// Sensor manager
|
||||
Sensor mSensor; // Compass sensor returned by sensor manager
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
public CompassListener() {
|
||||
this.timeStamp = 0;
|
||||
this.setStatus(CompassListener.STOPPED);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the context of the Command. This can then be used to do things like
|
||||
* get file paths associated with the Activity.
|
||||
*
|
||||
* @param ctx The context of the main Activity.
|
||||
*/
|
||||
public void setContext(PhonegapActivity ctx) {
|
||||
super.setContext(ctx);
|
||||
this.sensorManager = (SensorManager) ctx.getSystemService(Context.SENSOR_SERVICE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes the request and returns PluginResult.
|
||||
*
|
||||
* @param action The action to execute.
|
||||
* @param args JSONArry of arguments for the plugin.
|
||||
* @param callbackId The callback id used when calling back into JavaScript.
|
||||
* @return A PluginResult object with a status and message.
|
||||
*/
|
||||
public PluginResult execute(String action, JSONArray args, String callbackId) {
|
||||
PluginResult.Status status = PluginResult.Status.OK;
|
||||
String result = "";
|
||||
|
||||
try {
|
||||
if (action.equals("start")) {
|
||||
this.start();
|
||||
}
|
||||
else if (action.equals("stop")) {
|
||||
this.stop();
|
||||
}
|
||||
else if (action.equals("getStatus")) {
|
||||
int i = this.getStatus();
|
||||
return new PluginResult(status, i);
|
||||
}
|
||||
else if (action.equals("getHeading")) {
|
||||
// If not running, then this is an async call, so don't worry about waiting
|
||||
if (this.status != RUNNING) {
|
||||
int r = this.start();
|
||||
if (r == ERROR_FAILED_TO_START) {
|
||||
return new PluginResult(PluginResult.Status.IO_EXCEPTION, ERROR_FAILED_TO_START);
|
||||
}
|
||||
// Wait until running
|
||||
long timeout = 2000;
|
||||
while ((this.status == STARTING) && (timeout > 0)) {
|
||||
timeout = timeout - 100;
|
||||
try {
|
||||
Thread.sleep(100);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
if (timeout == 0) {
|
||||
return new PluginResult(PluginResult.Status.IO_EXCEPTION, AccelListener.ERROR_FAILED_TO_START);
|
||||
}
|
||||
}
|
||||
//float f = this.getHeading();
|
||||
return new PluginResult(status, getCompassHeading(), "navigator.compass._castDate");
|
||||
}
|
||||
else if (action.equals("setTimeout")) {
|
||||
this.setTimeout(args.getLong(0));
|
||||
}
|
||||
else if (action.equals("getTimeout")) {
|
||||
long l = this.getTimeout();
|
||||
return new PluginResult(status, l);
|
||||
}
|
||||
return new PluginResult(status, result);
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
return new PluginResult(PluginResult.Status.JSON_EXCEPTION);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Identifies if action to be executed returns a value and should be run synchronously.
|
||||
*
|
||||
* @param action The action to execute
|
||||
* @return T=returns value
|
||||
*/
|
||||
public boolean isSynch(String action) {
|
||||
if (action.equals("getStatus")) {
|
||||
return true;
|
||||
}
|
||||
else if (action.equals("getHeading")) {
|
||||
// Can only return value if RUNNING
|
||||
if (this.status == RUNNING) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if (action.equals("getTimeout")) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when listener is to be shut down and object is being destroyed.
|
||||
*/
|
||||
public void onDestroy() {
|
||||
this.stop();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// LOCAL METHODS
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Start listening for compass sensor.
|
||||
*
|
||||
* @return status of listener
|
||||
*/
|
||||
public int start() {
|
||||
|
||||
// If already starting or running, then just return
|
||||
if ((this.status == CompassListener.RUNNING) || (this.status == CompassListener.STARTING)) {
|
||||
return this.status;
|
||||
}
|
||||
|
||||
// Get accelerometer from sensor manager
|
||||
List<Sensor> list = this.sensorManager.getSensorList(Sensor.TYPE_ORIENTATION);
|
||||
|
||||
// If found, then register as listener
|
||||
if (list.size() > 0) {
|
||||
this.mSensor = list.get(0);
|
||||
this.sensorManager.registerListener(this, this.mSensor, SensorManager.SENSOR_DELAY_NORMAL);
|
||||
this.lastAccessTime = System.currentTimeMillis();
|
||||
this.setStatus(CompassListener.STARTING);
|
||||
}
|
||||
|
||||
// If error, then set status to error
|
||||
else {
|
||||
this.setStatus(CompassListener.ERROR_FAILED_TO_START);
|
||||
}
|
||||
|
||||
return this.status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop listening to compass sensor.
|
||||
*/
|
||||
public void stop() {
|
||||
if (this.status != CompassListener.STOPPED) {
|
||||
this.sensorManager.unregisterListener(this);
|
||||
}
|
||||
this.setStatus(CompassListener.STOPPED);
|
||||
}
|
||||
|
||||
|
||||
public void onAccuracyChanged(Sensor sensor, int accuracy) {
|
||||
// TODO Auto-generated method stub
|
||||
}
|
||||
|
||||
/**
|
||||
* Sensor listener event.
|
||||
*
|
||||
* @param SensorEvent event
|
||||
*/
|
||||
public void onSensorChanged(SensorEvent event) {
|
||||
|
||||
// We only care about the orientation as far as it refers to Magnetic North
|
||||
float heading = event.values[0];
|
||||
|
||||
// Save heading
|
||||
this.timeStamp = System.currentTimeMillis();
|
||||
this.heading = heading;
|
||||
this.setStatus(CompassListener.RUNNING);
|
||||
|
||||
// If heading hasn't been read for TIMEOUT time, then turn off compass sensor to save power
|
||||
if ((this.timeStamp - this.lastAccessTime) > this.TIMEOUT) {
|
||||
this.stop();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get status of compass sensor.
|
||||
*
|
||||
* @return status
|
||||
*/
|
||||
public int getStatus() {
|
||||
return this.status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the most recent compass heading.
|
||||
*
|
||||
* @return heading
|
||||
*/
|
||||
public float getHeading() {
|
||||
this.lastAccessTime = System.currentTimeMillis();
|
||||
return this.heading;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the timeout to turn off compass sensor if getHeading() hasn't been called.
|
||||
*
|
||||
* @param timeout Timeout in msec.
|
||||
*/
|
||||
public void setTimeout(long timeout) {
|
||||
this.TIMEOUT = timeout;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the timeout to turn off compass sensor if getHeading() hasn't been called.
|
||||
*
|
||||
* @return timeout in msec
|
||||
*/
|
||||
public long getTimeout() {
|
||||
return this.TIMEOUT;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the status and send it to JavaScript.
|
||||
* @param status
|
||||
*/
|
||||
private void setStatus(int status) {
|
||||
this.status = status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the CompassHeading JSON object to be returned to JavaScript
|
||||
*
|
||||
* @return a compass heading
|
||||
*/
|
||||
private JSONObject getCompassHeading() {
|
||||
JSONObject obj = new JSONObject();
|
||||
|
||||
try {
|
||||
obj.put("magneticHeading", this.getHeading());
|
||||
obj.put("trueHeading", this.getHeading());
|
||||
// Since the magnetic and true heading are always the same our and accuracy
|
||||
// is defined as the difference between true and magnetic always return zero
|
||||
obj.put("headingAccuracy", 0);
|
||||
obj.put("timestamp", this.timeStamp);
|
||||
} catch (JSONException e) {
|
||||
// Should never happen
|
||||
}
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,197 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2009 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.phonegap;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.util.Log;
|
||||
import android.webkit.WebView;
|
||||
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
/**
|
||||
* This abstract class defines SDK-independent API for communication with
|
||||
* Contacts Provider. The actual implementation used by the application depends
|
||||
* on the level of API available on the device. If the API level is Cupcake or
|
||||
* Donut, we want to use the {@link ContactAccessorSdk3_4} class. If it is
|
||||
* Eclair or higher, we want to use {@link ContactAccessorSdk5}.
|
||||
*/
|
||||
public abstract class ContactAccessor {
|
||||
|
||||
protected final String LOG_TAG = "ContactsAccessor";
|
||||
protected Activity mApp;
|
||||
protected WebView mView;
|
||||
|
||||
/**
|
||||
* Check to see if the data associated with the key is required to
|
||||
* be populated in the Contact object.
|
||||
* @param key
|
||||
* @param map created by running buildPopulationSet.
|
||||
* @return true if the key data is required
|
||||
*/
|
||||
protected boolean isRequired(String key, HashMap<String,Boolean> map) {
|
||||
Boolean retVal = map.get(key);
|
||||
return (retVal == null) ? false : retVal.booleanValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a hash map of what data needs to be populated in the Contact object
|
||||
* @param fields the list of fields to populate
|
||||
* @return the hash map of required data
|
||||
*/
|
||||
protected HashMap<String,Boolean> buildPopulationSet(JSONArray fields) {
|
||||
HashMap<String,Boolean> map = new HashMap<String,Boolean>();
|
||||
|
||||
String key;
|
||||
try {
|
||||
if (fields.length() == 1 && fields.getString(0).equals("*")) {
|
||||
map.put("displayName", true);
|
||||
map.put("name", true);
|
||||
map.put("nickname", true);
|
||||
map.put("phoneNumbers", true);
|
||||
map.put("emails", true);
|
||||
map.put("addresses", true);
|
||||
map.put("ims", true);
|
||||
map.put("organizations", true);
|
||||
map.put("birthday", true);
|
||||
map.put("note", true);
|
||||
map.put("urls", true);
|
||||
map.put("photos", true);
|
||||
map.put("categories", true);
|
||||
}
|
||||
else {
|
||||
for (int i=0; i<fields.length(); i++) {
|
||||
key = fields.getString(i);
|
||||
if (key.startsWith("displayName")) {
|
||||
map.put("displayName", true);
|
||||
}
|
||||
else if (key.startsWith("name")) {
|
||||
map.put("name", true);
|
||||
}
|
||||
else if (key.startsWith("nickname")) {
|
||||
map.put("nickname", true);
|
||||
}
|
||||
else if (key.startsWith("phoneNumbers")) {
|
||||
map.put("phoneNumbers", true);
|
||||
}
|
||||
else if (key.startsWith("emails")) {
|
||||
map.put("emails", true);
|
||||
}
|
||||
else if (key.startsWith("addresses")) {
|
||||
map.put("addresses", true);
|
||||
}
|
||||
else if (key.startsWith("ims")) {
|
||||
map.put("ims", true);
|
||||
}
|
||||
else if (key.startsWith("organizations")) {
|
||||
map.put("organizations", true);
|
||||
}
|
||||
else if (key.startsWith("birthday")) {
|
||||
map.put("birthday", true);
|
||||
}
|
||||
else if (key.startsWith("note")) {
|
||||
map.put("note", true);
|
||||
}
|
||||
else if (key.startsWith("urls")) {
|
||||
map.put("urls", true);
|
||||
}
|
||||
else if (key.startsWith("photos")) {
|
||||
map.put("photos", true);
|
||||
}
|
||||
else if (key.startsWith("categories")) {
|
||||
map.put("categories", true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (JSONException e) {
|
||||
Log.e(LOG_TAG, e.getMessage(), e);
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience method to get a string from a JSON object. Saves a
|
||||
* lot of try/catch writing.
|
||||
* If the property is not found in the object null will be returned.
|
||||
*
|
||||
* @param obj contact object to search
|
||||
* @param property to be looked up
|
||||
* @return The value of the property
|
||||
*/
|
||||
protected String getJsonString(JSONObject obj, String property) {
|
||||
String value = null;
|
||||
try {
|
||||
if (obj != null) {
|
||||
value = obj.getString(property);
|
||||
if (value.equals("null")) {
|
||||
Log.d(LOG_TAG, property + " is string called 'null'");
|
||||
value = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (JSONException e) {
|
||||
Log.d(LOG_TAG, "Could not get = " + e.getMessage());
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles adding a JSON Contact object into the database.
|
||||
* @return TODO
|
||||
*/
|
||||
public abstract String save(JSONObject contact);
|
||||
|
||||
/**
|
||||
* Handles searching through SDK-specific contacts API.
|
||||
*/
|
||||
public abstract JSONArray search(JSONArray filter, JSONObject options);
|
||||
|
||||
/**
|
||||
* Handles searching through SDK-specific contacts API.
|
||||
* @throws JSONException
|
||||
*/
|
||||
public abstract JSONObject getContactById(String id) throws JSONException;
|
||||
|
||||
/**
|
||||
* Handles removing a contact from the database.
|
||||
*/
|
||||
public abstract boolean remove(String id);
|
||||
|
||||
/**
|
||||
* A class that represents the where clause to be used in the database query
|
||||
*/
|
||||
class WhereOptions {
|
||||
private String where;
|
||||
private String[] whereArgs;
|
||||
public void setWhere(String where) {
|
||||
this.where = where;
|
||||
}
|
||||
public String getWhere() {
|
||||
return where;
|
||||
}
|
||||
public void setWhereArgs(String[] whereArgs) {
|
||||
this.whereArgs = whereArgs;
|
||||
}
|
||||
public String[] getWhereArgs() {
|
||||
return whereArgs;
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,113 +0,0 @@
|
||||
/*
|
||||
Licensed to the Apache Software Foundation (ASF) under one
|
||||
or more contributor license agreements. See the NOTICE file
|
||||
distributed with this work for additional information
|
||||
regarding copyright ownership. The ASF licenses this file
|
||||
to you under the Apache License, Version 2.0 (the
|
||||
"License"); you may not use this file except in compliance
|
||||
with the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing,
|
||||
software distributed under the License is distributed on an
|
||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
KIND, either express or implied. See the License for the
|
||||
specific language governing permissions and limitations
|
||||
under the License.
|
||||
*/
|
||||
package com.phonegap;
|
||||
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
import com.phonegap.api.Plugin;
|
||||
import com.phonegap.api.PluginResult;
|
||||
import android.util.Log;
|
||||
|
||||
public class ContactManager extends Plugin {
|
||||
|
||||
private ContactAccessor contactAccessor;
|
||||
private static final String LOG_TAG = "Contact Query";
|
||||
|
||||
public static final int UNKNOWN_ERROR = 0;
|
||||
public static final int INVALID_ARGUMENT_ERROR = 1;
|
||||
public static final int TIMEOUT_ERROR = 2;
|
||||
public static final int PENDING_OPERATION_ERROR = 3;
|
||||
public static final int IO_ERROR = 4;
|
||||
public static final int NOT_SUPPORTED_ERROR = 5;
|
||||
public static final int PERMISSION_DENIED_ERROR = 20;
|
||||
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
public ContactManager() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes the request and returns PluginResult.
|
||||
*
|
||||
* @param action The action to execute.
|
||||
* @param args JSONArry of arguments for the plugin.
|
||||
* @param callbackId The callback id used when calling back into JavaScript.
|
||||
* @return A PluginResult object with a status and message.
|
||||
*/
|
||||
public PluginResult execute(String action, JSONArray args, String callbackId) {
|
||||
PluginResult.Status status = PluginResult.Status.OK;
|
||||
String result = "";
|
||||
|
||||
/**
|
||||
* Check to see if we are on an Android 1.X device. If we are return an error as we
|
||||
* do not support this as of PhoneGap 1.0.
|
||||
*/
|
||||
if (android.os.Build.VERSION.RELEASE.startsWith("1.")) {
|
||||
JSONObject res = null;
|
||||
try {
|
||||
res = new JSONObject();
|
||||
res.put("code", NOT_SUPPORTED_ERROR);
|
||||
res.put("message", "Contacts are not supported in Android 1.X devices");
|
||||
} catch (JSONException e) {
|
||||
// This should never happen
|
||||
Log.e(LOG_TAG, e.getMessage(), e);
|
||||
}
|
||||
return new PluginResult(PluginResult.Status.ERROR, res);
|
||||
}
|
||||
|
||||
/**
|
||||
* Only create the contactAccessor after we check the Android version or the program will crash
|
||||
* older phones.
|
||||
*/
|
||||
if (this.contactAccessor == null) {
|
||||
this.contactAccessor = new ContactAccessorSdk5(this.webView, this.ctx);
|
||||
}
|
||||
|
||||
try {
|
||||
if (action.equals("search")) {
|
||||
JSONArray res = contactAccessor.search(args.getJSONArray(0), args.optJSONObject(1));
|
||||
return new PluginResult(status, res, "navigator.contacts.cast");
|
||||
}
|
||||
else if (action.equals("save")) {
|
||||
String id = contactAccessor.save(args.getJSONObject(0));
|
||||
if (id != null) {
|
||||
JSONObject res = contactAccessor.getContactById(id);
|
||||
if (res != null) {
|
||||
return new PluginResult(status, res);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (action.equals("remove")) {
|
||||
if (contactAccessor.remove(args.getString(0))) {
|
||||
return new PluginResult(status, result);
|
||||
}
|
||||
}
|
||||
// If we get to this point an error has occurred
|
||||
JSONObject r = new JSONObject();
|
||||
r.put("code", UNKNOWN_ERROR);
|
||||
return new PluginResult(PluginResult.Status.ERROR, r);
|
||||
} catch (JSONException e) {
|
||||
Log.e(LOG_TAG, e.getMessage(), e);
|
||||
return new PluginResult(PluginResult.Status.JSON_EXCEPTION);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,314 +0,0 @@
|
||||
/*
|
||||
Licensed to the Apache Software Foundation (ASF) under one
|
||||
or more contributor license agreements. See the NOTICE file
|
||||
distributed with this work for additional information
|
||||
regarding copyright ownership. The ASF licenses this file
|
||||
to you under the Apache License, Version 2.0 (the
|
||||
"License"); you may not use this file except in compliance
|
||||
with the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing,
|
||||
software distributed under the License is distributed on an
|
||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
KIND, either express or implied. See the License for the
|
||||
specific language governing permissions and limitations
|
||||
under the License.
|
||||
*/
|
||||
package com.phonegap;
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
|
||||
import com.phonegap.api.LOG;
|
||||
|
||||
import android.app.AlertDialog;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.View;
|
||||
import android.webkit.ConsoleMessage;
|
||||
import android.webkit.JsPromptResult;
|
||||
import android.webkit.JsResult;
|
||||
import android.webkit.WebChromeClient;
|
||||
import android.webkit.WebStorage;
|
||||
import android.webkit.WebView;
|
||||
import android.webkit.GeolocationPermissions.Callback;
|
||||
import android.widget.EditText;
|
||||
|
||||
/**
|
||||
* This class is the WebChromeClient that implements callbacks for our web view.
|
||||
*/
|
||||
public class CordovaChromeClient extends WebChromeClient {
|
||||
|
||||
|
||||
private String TAG = "PhoneGapLog";
|
||||
private long MAX_QUOTA = 100 * 1024 * 1024;
|
||||
private DroidGap ctx;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param ctx
|
||||
*/
|
||||
public CordovaChromeClient(Context ctx) {
|
||||
this.ctx = (DroidGap) ctx;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tell the client to display a javascript alert dialog.
|
||||
*
|
||||
* @param view
|
||||
* @param url
|
||||
* @param message
|
||||
* @param result
|
||||
*/
|
||||
@Override
|
||||
public boolean onJsAlert(WebView view, String url, String message, final JsResult result) {
|
||||
AlertDialog.Builder dlg = new AlertDialog.Builder(this.ctx);
|
||||
dlg.setMessage(message);
|
||||
dlg.setTitle("Alert");
|
||||
//Don't let alerts break the back button
|
||||
dlg.setCancelable(true);
|
||||
dlg.setPositiveButton(android.R.string.ok,
|
||||
new AlertDialog.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
result.confirm();
|
||||
}
|
||||
});
|
||||
dlg.setOnCancelListener(
|
||||
new DialogInterface.OnCancelListener() {
|
||||
public void onCancel(DialogInterface dialog) {
|
||||
result.confirm();
|
||||
}
|
||||
});
|
||||
dlg.setOnKeyListener(new DialogInterface.OnKeyListener() {
|
||||
//DO NOTHING
|
||||
public boolean onKey(DialogInterface dialog, int keyCode, KeyEvent event) {
|
||||
if(keyCode == KeyEvent.KEYCODE_BACK)
|
||||
{
|
||||
result.confirm();
|
||||
return false;
|
||||
}
|
||||
else
|
||||
return true;
|
||||
}
|
||||
});
|
||||
dlg.create();
|
||||
dlg.show();
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tell the client to display a confirm dialog to the user.
|
||||
*
|
||||
* @param view
|
||||
* @param url
|
||||
* @param message
|
||||
* @param result
|
||||
*/
|
||||
@Override
|
||||
public boolean onJsConfirm(WebView view, String url, String message, final JsResult result) {
|
||||
AlertDialog.Builder dlg = new AlertDialog.Builder(this.ctx);
|
||||
dlg.setMessage(message);
|
||||
dlg.setTitle("Confirm");
|
||||
dlg.setCancelable(true);
|
||||
dlg.setPositiveButton(android.R.string.ok,
|
||||
new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
result.confirm();
|
||||
}
|
||||
});
|
||||
dlg.setNegativeButton(android.R.string.cancel,
|
||||
new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
result.cancel();
|
||||
}
|
||||
});
|
||||
dlg.setOnCancelListener(
|
||||
new DialogInterface.OnCancelListener() {
|
||||
public void onCancel(DialogInterface dialog) {
|
||||
result.cancel();
|
||||
}
|
||||
});
|
||||
dlg.setOnKeyListener(new DialogInterface.OnKeyListener() {
|
||||
//DO NOTHING
|
||||
public boolean onKey(DialogInterface dialog, int keyCode, KeyEvent event) {
|
||||
if(keyCode == KeyEvent.KEYCODE_BACK)
|
||||
{
|
||||
result.cancel();
|
||||
return false;
|
||||
}
|
||||
else
|
||||
return true;
|
||||
}
|
||||
});
|
||||
dlg.create();
|
||||
dlg.show();
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tell the client to display a prompt dialog to the user.
|
||||
* If the client returns true, WebView will assume that the client will
|
||||
* handle the prompt dialog and call the appropriate JsPromptResult method.
|
||||
*
|
||||
* Since we are hacking prompts for our own purposes, we should not be using them for
|
||||
* this purpose, perhaps we should hack console.log to do this instead!
|
||||
*
|
||||
* @param view
|
||||
* @param url
|
||||
* @param message
|
||||
* @param defaultValue
|
||||
* @param result
|
||||
*/
|
||||
@Override
|
||||
public boolean onJsPrompt(WebView view, String url, String message, String defaultValue, JsPromptResult result) {
|
||||
|
||||
// Security check to make sure any requests are coming from the page initially
|
||||
// loaded in webview and not another loaded in an iframe.
|
||||
boolean reqOk = false;
|
||||
if (url.startsWith("file://") || url.indexOf(this.ctx.baseUrl) == 0 || ctx.isUrlWhiteListed(url)) {
|
||||
reqOk = true;
|
||||
}
|
||||
|
||||
// Calling PluginManager.exec() to call a native service using
|
||||
// prompt(this.stringify(args), "gap:"+this.stringify([service, action, callbackId, true]));
|
||||
if (reqOk && defaultValue != null && defaultValue.length() > 3 && defaultValue.substring(0, 4).equals("gap:")) {
|
||||
JSONArray array;
|
||||
try {
|
||||
array = new JSONArray(defaultValue.substring(4));
|
||||
String service = array.getString(0);
|
||||
String action = array.getString(1);
|
||||
String callbackId = array.getString(2);
|
||||
boolean async = array.getBoolean(3);
|
||||
String r = ctx.pluginManager.exec(service, action, callbackId, message, async);
|
||||
result.confirm(r);
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
// Polling for JavaScript messages
|
||||
else if (reqOk && defaultValue != null && defaultValue.equals("gap_poll:")) {
|
||||
String r = ctx.callbackServer.getJavascript();
|
||||
result.confirm(r);
|
||||
}
|
||||
|
||||
// Calling into CallbackServer
|
||||
else if (reqOk && defaultValue != null && defaultValue.equals("gap_callbackServer:")) {
|
||||
String r = "";
|
||||
if (message.equals("usePolling")) {
|
||||
r = ""+ ctx.callbackServer.usePolling();
|
||||
}
|
||||
else if (message.equals("restartServer")) {
|
||||
ctx.callbackServer.restartServer();
|
||||
}
|
||||
else if (message.equals("getPort")) {
|
||||
r = Integer.toString(ctx.callbackServer.getPort());
|
||||
}
|
||||
else if (message.equals("getToken")) {
|
||||
r = ctx.callbackServer.getToken();
|
||||
}
|
||||
result.confirm(r);
|
||||
}
|
||||
|
||||
// PhoneGap JS has initialized, so show webview
|
||||
// (This solves white flash seen when rendering HTML)
|
||||
else if (reqOk && defaultValue != null && defaultValue.equals("gap_init:")) {
|
||||
ctx.appView.setVisibility(View.VISIBLE);
|
||||
ctx.spinnerStop();
|
||||
result.confirm("OK");
|
||||
}
|
||||
|
||||
// Show dialog
|
||||
else {
|
||||
final JsPromptResult res = result;
|
||||
AlertDialog.Builder dlg = new AlertDialog.Builder(this.ctx);
|
||||
dlg.setMessage(message);
|
||||
final EditText input = new EditText(this.ctx);
|
||||
if (defaultValue != null) {
|
||||
input.setText(defaultValue);
|
||||
}
|
||||
dlg.setView(input);
|
||||
dlg.setCancelable(false);
|
||||
dlg.setPositiveButton(android.R.string.ok,
|
||||
new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
String usertext = input.getText().toString();
|
||||
res.confirm(usertext);
|
||||
}
|
||||
});
|
||||
dlg.setNegativeButton(android.R.string.cancel,
|
||||
new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
res.cancel();
|
||||
}
|
||||
});
|
||||
dlg.create();
|
||||
dlg.show();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle database quota exceeded notification.
|
||||
*
|
||||
* @param url
|
||||
* @param databaseIdentifier
|
||||
* @param currentQuota
|
||||
* @param estimatedSize
|
||||
* @param totalUsedQuota
|
||||
* @param quotaUpdater
|
||||
*/
|
||||
@Override
|
||||
public void onExceededDatabaseQuota(String url, String databaseIdentifier, long currentQuota, long estimatedSize,
|
||||
long totalUsedQuota, WebStorage.QuotaUpdater quotaUpdater)
|
||||
{
|
||||
LOG.d(TAG, "DroidGap: onExceededDatabaseQuota estimatedSize: %d currentQuota: %d totalUsedQuota: %d", estimatedSize, currentQuota, totalUsedQuota);
|
||||
|
||||
if( estimatedSize < MAX_QUOTA)
|
||||
{
|
||||
//increase for 1Mb
|
||||
long newQuota = estimatedSize;
|
||||
LOG.d(TAG, "calling quotaUpdater.updateQuota newQuota: %d", newQuota);
|
||||
quotaUpdater.updateQuota(newQuota);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Set the quota to whatever it is and force an error
|
||||
// TODO: get docs on how to handle this properly
|
||||
quotaUpdater.updateQuota(currentQuota);
|
||||
}
|
||||
}
|
||||
|
||||
// console.log in api level 7: http://developer.android.com/guide/developing/debug-tasks.html
|
||||
@Override
|
||||
public void onConsoleMessage(String message, int lineNumber, String sourceID)
|
||||
{
|
||||
LOG.d(TAG, "%s: Line %d : %s", sourceID, lineNumber, message);
|
||||
super.onConsoleMessage(message, lineNumber, sourceID);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onConsoleMessage(ConsoleMessage consoleMessage)
|
||||
{
|
||||
if(consoleMessage.message() != null)
|
||||
LOG.d(TAG, consoleMessage.message());
|
||||
return super.onConsoleMessage(consoleMessage);
|
||||
}
|
||||
|
||||
@Override
|
||||
/**
|
||||
* Instructs the client to show a prompt to ask the user to set the Geolocation permission state for the specified origin.
|
||||
*
|
||||
* @param origin
|
||||
* @param callback
|
||||
*/
|
||||
public void onGeolocationPermissionsShowPrompt(String origin, Callback callback) {
|
||||
super.onGeolocationPermissionsShowPrompt(origin, callback);
|
||||
callback.invoke(origin, true, false);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -1,296 +0,0 @@
|
||||
/*
|
||||
Licensed to the Apache Software Foundation (ASF) under one
|
||||
or more contributor license agreements. See the NOTICE file
|
||||
distributed with this work for additional information
|
||||
regarding copyright ownership. The ASF licenses this file
|
||||
to you under the Apache License, Version 2.0 (the
|
||||
"License"); you may not use this file except in compliance
|
||||
with the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing,
|
||||
software distributed under the License is distributed on an
|
||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
KIND, either express or implied. See the License for the
|
||||
specific language governing permissions and limitations
|
||||
under the License.
|
||||
*/
|
||||
package com.phonegap;
|
||||
|
||||
import com.phonegap.api.LOG;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.PackageManager.NameNotFoundException;
|
||||
import android.graphics.Bitmap;
|
||||
import android.net.Uri;
|
||||
import android.net.http.SslError;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
import android.webkit.HttpAuthHandler;
|
||||
import android.webkit.SslErrorHandler;
|
||||
import android.webkit.WebView;
|
||||
import android.webkit.WebViewClient;
|
||||
|
||||
/**
|
||||
* This class is the WebViewClient that implements callbacks for our web view.
|
||||
*/
|
||||
public class CordovaWebViewClient extends WebViewClient {
|
||||
|
||||
private static final String TAG = "Cordova";
|
||||
DroidGap ctx;
|
||||
private boolean doClearHistory = false;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param ctx
|
||||
*/
|
||||
public CordovaWebViewClient(DroidGap ctx) {
|
||||
this.ctx = ctx;
|
||||
}
|
||||
|
||||
/**
|
||||
* Give the host application a chance to take over the control when a new url
|
||||
* is about to be loaded in the current WebView.
|
||||
*
|
||||
* @param view The WebView that is initiating the callback.
|
||||
* @param url The url to be loaded.
|
||||
* @return true to override, false for default behavior
|
||||
*/
|
||||
@Override
|
||||
public boolean shouldOverrideUrlLoading(WebView view, String url) {
|
||||
|
||||
// First give any plugins the chance to handle the url themselves
|
||||
if (this.ctx.pluginManager.onOverrideUrlLoading(url)) {
|
||||
}
|
||||
|
||||
// If dialing phone (tel:5551212)
|
||||
else if (url.startsWith(WebView.SCHEME_TEL)) {
|
||||
try {
|
||||
Intent intent = new Intent(Intent.ACTION_DIAL);
|
||||
intent.setData(Uri.parse(url));
|
||||
ctx.startActivity(intent);
|
||||
} catch (android.content.ActivityNotFoundException e) {
|
||||
LOG.e(TAG, "Error dialing "+url+": "+ e.toString());
|
||||
}
|
||||
}
|
||||
|
||||
// If displaying map (geo:0,0?q=address)
|
||||
else if (url.startsWith("geo:")) {
|
||||
try {
|
||||
Intent intent = new Intent(Intent.ACTION_VIEW);
|
||||
intent.setData(Uri.parse(url));
|
||||
ctx.startActivity(intent);
|
||||
} catch (android.content.ActivityNotFoundException e) {
|
||||
LOG.e(TAG, "Error showing map "+url+": "+ e.toString());
|
||||
}
|
||||
}
|
||||
|
||||
// If sending email (mailto:abc@corp.com)
|
||||
else if (url.startsWith(WebView.SCHEME_MAILTO)) {
|
||||
try {
|
||||
Intent intent = new Intent(Intent.ACTION_VIEW);
|
||||
intent.setData(Uri.parse(url));
|
||||
ctx.startActivity(intent);
|
||||
} catch (android.content.ActivityNotFoundException e) {
|
||||
LOG.e(TAG, "Error sending email "+url+": "+ e.toString());
|
||||
}
|
||||
}
|
||||
|
||||
// If sms:5551212?body=This is the message
|
||||
else if (url.startsWith("sms:")) {
|
||||
try {
|
||||
Intent intent = new Intent(Intent.ACTION_VIEW);
|
||||
|
||||
// Get address
|
||||
String address = null;
|
||||
int parmIndex = url.indexOf('?');
|
||||
if (parmIndex == -1) {
|
||||
address = url.substring(4);
|
||||
}
|
||||
else {
|
||||
address = url.substring(4, parmIndex);
|
||||
|
||||
// If body, then set sms body
|
||||
Uri uri = Uri.parse(url);
|
||||
String query = uri.getQuery();
|
||||
if (query != null) {
|
||||
if (query.startsWith("body=")) {
|
||||
intent.putExtra("sms_body", query.substring(5));
|
||||
}
|
||||
}
|
||||
}
|
||||
intent.setData(Uri.parse("sms:"+address));
|
||||
intent.putExtra("address", address);
|
||||
intent.setType("vnd.android-dir/mms-sms");
|
||||
ctx.startActivity(intent);
|
||||
} catch (android.content.ActivityNotFoundException e) {
|
||||
LOG.e(TAG, "Error sending sms "+url+":"+ e.toString());
|
||||
}
|
||||
}
|
||||
|
||||
// All else
|
||||
else {
|
||||
|
||||
// If our app or file:, then load into a new phonegap webview container by starting a new instance of our activity.
|
||||
// Our app continues to run. When BACK is pressed, our app is redisplayed.
|
||||
if (url.startsWith("file://") || url.indexOf(this.ctx.baseUrl) == 0 || ctx.isUrlWhiteListed(url)) {
|
||||
this.ctx.loadUrl(url);
|
||||
}
|
||||
|
||||
// If not our application, let default viewer handle
|
||||
else {
|
||||
try {
|
||||
Intent intent = new Intent(Intent.ACTION_VIEW);
|
||||
intent.setData(Uri.parse(url));
|
||||
ctx.startActivity(intent);
|
||||
} catch (android.content.ActivityNotFoundException e) {
|
||||
LOG.e(TAG, "Error loading url "+url, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* On received http auth request.
|
||||
* The method reacts on all registered authentication tokens. There is one and only one authentication token for any host + realm combination
|
||||
*
|
||||
* @param view
|
||||
* the view
|
||||
* @param handler
|
||||
* the handler
|
||||
* @param host
|
||||
* the host
|
||||
* @param realm
|
||||
* the realm
|
||||
*/
|
||||
@Override
|
||||
public void onReceivedHttpAuthRequest(WebView view, HttpAuthHandler handler, String host,
|
||||
String realm) {
|
||||
|
||||
// get the authentication token
|
||||
AuthenticationToken token = ctx.getAuthenticationToken(host,realm);
|
||||
|
||||
if(token != null) {
|
||||
handler.proceed(token.getUserName(), token.getPassword());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void onPageStarted(WebView view, String url, Bitmap favicon) {
|
||||
|
||||
// Clear history so history.back() doesn't do anything.
|
||||
// So we can reinit() native side CallbackServer & PluginManager.
|
||||
view.clearHistory();
|
||||
this.doClearHistory = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Notify the host application that a page has finished loading.
|
||||
*
|
||||
* @param view The webview initiating the callback.
|
||||
* @param url The url of the page.
|
||||
*/
|
||||
@Override
|
||||
public void onPageFinished(WebView view, String url) {
|
||||
super.onPageFinished(view, url);
|
||||
|
||||
/**
|
||||
* Because of a timing issue we need to clear this history in onPageFinished as well as
|
||||
* onPageStarted. However we only want to do this if the doClearHistory boolean is set to
|
||||
* true. You see when you load a url with a # in it which is common in jQuery applications
|
||||
* onPageStared is not called. Clearing the history at that point would break jQuery apps.
|
||||
*/
|
||||
if (this.doClearHistory) {
|
||||
view.clearHistory();
|
||||
this.doClearHistory = false;
|
||||
}
|
||||
|
||||
// Clear timeout flag
|
||||
this.ctx.loadUrlTimeout++;
|
||||
|
||||
// Try firing the onNativeReady event in JS. If it fails because the JS is
|
||||
// not loaded yet then just set a flag so that the onNativeReady can be fired
|
||||
// from the JS side when the JS gets to that code.
|
||||
if (!url.equals("about:blank")) {
|
||||
ctx.appView.loadUrl("javascript:try{ PhoneGap.onNativeReady.fire();}catch(e){_nativeReady = true;}");
|
||||
}
|
||||
|
||||
// Make app visible after 2 sec in case there was a JS error and PhoneGap JS never initialized correctly
|
||||
if (ctx.appView.getVisibility() == View.INVISIBLE) {
|
||||
Thread t = new Thread(new Runnable() {
|
||||
public void run() {
|
||||
try {
|
||||
Thread.sleep(2000);
|
||||
ctx.runOnUiThread(new Runnable() {
|
||||
public void run() {
|
||||
ctx.appView.setVisibility(View.VISIBLE);
|
||||
ctx.spinnerStop();
|
||||
}
|
||||
});
|
||||
} catch (InterruptedException e) {
|
||||
}
|
||||
}
|
||||
});
|
||||
t.start();
|
||||
}
|
||||
|
||||
|
||||
// Shutdown if blank loaded
|
||||
if (url.equals("about:blank")) {
|
||||
if (this.ctx.callbackServer != null) {
|
||||
this.ctx.callbackServer.destroy();
|
||||
}
|
||||
this.ctx.endActivity();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Report an error to the host application. These errors are unrecoverable (i.e. the main resource is unavailable).
|
||||
* The errorCode parameter corresponds to one of the ERROR_* constants.
|
||||
*
|
||||
* @param view The WebView that is initiating the callback.
|
||||
* @param errorCode The error code corresponding to an ERROR_* value.
|
||||
* @param description A String describing the error.
|
||||
* @param failingUrl The url that failed to load.
|
||||
*/
|
||||
@Override
|
||||
public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {
|
||||
LOG.d(TAG, "DroidGap: GapViewClient.onReceivedError: Error code=%s Description=%s URL=%s", errorCode, description, failingUrl);
|
||||
|
||||
// Clear timeout flag
|
||||
this.ctx.loadUrlTimeout++;
|
||||
|
||||
// Stop "app loading" spinner if showing
|
||||
this.ctx.spinnerStop();
|
||||
|
||||
// Handle error
|
||||
this.ctx.onReceivedError(errorCode, description, failingUrl);
|
||||
}
|
||||
|
||||
public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) {
|
||||
|
||||
final String packageName = this.ctx.getPackageName();
|
||||
final PackageManager pm = this.ctx.getPackageManager();
|
||||
ApplicationInfo appInfo;
|
||||
try {
|
||||
appInfo = pm.getApplicationInfo(packageName, PackageManager.GET_META_DATA);
|
||||
if ((appInfo.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0) {
|
||||
// debug = true
|
||||
handler.proceed();
|
||||
return;
|
||||
} else {
|
||||
// debug = false
|
||||
super.onReceivedSslError(view, handler, error);
|
||||
}
|
||||
} catch (NameNotFoundException e) {
|
||||
// When it doubt, lock it out!
|
||||
super.onReceivedSslError(view, handler, error);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,218 +0,0 @@
|
||||
/*
|
||||
Licensed to the Apache Software Foundation (ASF) under one
|
||||
or more contributor license agreements. See the NOTICE file
|
||||
distributed with this work for additional information
|
||||
regarding copyright ownership. The ASF licenses this file
|
||||
to you under the Apache License, Version 2.0 (the
|
||||
"License"); you may not use this file except in compliance
|
||||
with the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing,
|
||||
software distributed under the License is distributed on an
|
||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
KIND, either express or implied. See the License for the
|
||||
specific language governing permissions and limitations
|
||||
under the License.
|
||||
*/
|
||||
package com.phonegap;
|
||||
|
||||
import java.util.TimeZone;
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
import com.phonegap.api.LOG;
|
||||
import com.phonegap.api.PhonegapActivity;
|
||||
import com.phonegap.api.Plugin;
|
||||
import com.phonegap.api.PluginResult;
|
||||
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.provider.Settings;
|
||||
import android.telephony.TelephonyManager;
|
||||
|
||||
public class Device extends Plugin {
|
||||
public static final String TAG = "Device";
|
||||
|
||||
public static String phonegapVersion = "1.4.1"; // PhoneGap version
|
||||
public static String platform = "Android"; // Device OS
|
||||
public static String uuid; // Device UUID
|
||||
|
||||
BroadcastReceiver telephonyReceiver = null;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
public Device() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the context of the Command. This can then be used to do things like
|
||||
* get file paths associated with the Activity.
|
||||
*
|
||||
* @param ctx The context of the main Activity.
|
||||
*/
|
||||
public void setContext(PhonegapActivity ctx) {
|
||||
super.setContext(ctx);
|
||||
Device.uuid = getUuid();
|
||||
this.initTelephonyReceiver();
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes the request and returns PluginResult.
|
||||
*
|
||||
* @param action The action to execute.
|
||||
* @param args JSONArry of arguments for the plugin.
|
||||
* @param callbackId The callback id used when calling back into JavaScript.
|
||||
* @return A PluginResult object with a status and message.
|
||||
*/
|
||||
public PluginResult execute(String action, JSONArray args, String callbackId) {
|
||||
PluginResult.Status status = PluginResult.Status.OK;
|
||||
String result = "";
|
||||
|
||||
try {
|
||||
if (action.equals("getDeviceInfo")) {
|
||||
JSONObject r = new JSONObject();
|
||||
r.put("uuid", Device.uuid);
|
||||
r.put("version", this.getOSVersion());
|
||||
r.put("platform", Device.platform);
|
||||
r.put("name", this.getProductName());
|
||||
r.put("phonegap", Device.phonegapVersion);
|
||||
//JSONObject pg = new JSONObject();
|
||||
//pg.put("version", Device.phonegapVersion);
|
||||
//r.put("phonegap", pg);
|
||||
return new PluginResult(status, r);
|
||||
}
|
||||
return new PluginResult(status, result);
|
||||
} catch (JSONException e) {
|
||||
return new PluginResult(PluginResult.Status.JSON_EXCEPTION);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Identifies if action to be executed returns a value and should be run synchronously.
|
||||
*
|
||||
* @param action The action to execute
|
||||
* @return T=returns value
|
||||
*/
|
||||
public boolean isSynch(String action) {
|
||||
if (action.equals("getDeviceInfo")) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Unregister receiver.
|
||||
*/
|
||||
public void onDestroy() {
|
||||
this.ctx.unregisterReceiver(this.telephonyReceiver);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// LOCAL METHODS
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Listen for telephony events: RINGING, OFFHOOK and IDLE
|
||||
* Send these events to all plugins using
|
||||
* DroidGap.onMessage("telephone", "ringing" | "offhook" | "idle")
|
||||
*/
|
||||
private void initTelephonyReceiver() {
|
||||
IntentFilter intentFilter = new IntentFilter() ;
|
||||
intentFilter.addAction(TelephonyManager.ACTION_PHONE_STATE_CHANGED);
|
||||
final PhonegapActivity myctx = this.ctx;
|
||||
this.telephonyReceiver = new BroadcastReceiver() {
|
||||
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
|
||||
// If state has changed
|
||||
if ((intent != null) && intent.getAction().equals(TelephonyManager.ACTION_PHONE_STATE_CHANGED)) {
|
||||
if (intent.hasExtra(TelephonyManager.EXTRA_STATE)) {
|
||||
String extraData = intent.getStringExtra(TelephonyManager.EXTRA_STATE);
|
||||
if (extraData.equals(TelephonyManager.EXTRA_STATE_RINGING)) {
|
||||
LOG.i(TAG, "Telephone RINGING");
|
||||
myctx.postMessage("telephone", "ringing");
|
||||
}
|
||||
else if (extraData.equals(TelephonyManager.EXTRA_STATE_OFFHOOK)) {
|
||||
LOG.i(TAG, "Telephone OFFHOOK");
|
||||
myctx.postMessage("telephone", "offhook");
|
||||
}
|
||||
else if (extraData.equals(TelephonyManager.EXTRA_STATE_IDLE)) {
|
||||
LOG.i(TAG, "Telephone IDLE");
|
||||
myctx.postMessage("telephone", "idle");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Register the receiver
|
||||
this.ctx.registerReceiver(this.telephonyReceiver, intentFilter);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the OS name.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public String getPlatform() {
|
||||
return Device.platform;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the device's Universally Unique Identifier (UUID).
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public String getUuid() {
|
||||
String uuid = Settings.Secure.getString(this.ctx.getContentResolver(), android.provider.Settings.Secure.ANDROID_ID);
|
||||
return uuid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the PhoneGap version.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public String getPhonegapVersion() {
|
||||
return Device.phonegapVersion;
|
||||
}
|
||||
|
||||
public String getModel() {
|
||||
String model = android.os.Build.MODEL;
|
||||
return model;
|
||||
}
|
||||
|
||||
public String getProductName() {
|
||||
String productname = android.os.Build.PRODUCT;
|
||||
return productname;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the OS version.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public String getOSVersion() {
|
||||
String osversion = android.os.Build.VERSION.RELEASE;
|
||||
return osversion;
|
||||
}
|
||||
|
||||
public String getSDKVersion() {
|
||||
String sdkversion = android.os.Build.VERSION.SDK;
|
||||
return sdkversion;
|
||||
}
|
||||
|
||||
|
||||
public String getTimeZoneID() {
|
||||
TimeZone tz = TimeZone.getDefault();
|
||||
return(tz.getID());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,161 +0,0 @@
|
||||
/*
|
||||
Licensed to the Apache Software Foundation (ASF) under one
|
||||
or more contributor license agreements. See the NOTICE file
|
||||
distributed with this work for additional information
|
||||
regarding copyright ownership. The ASF licenses this file
|
||||
to you under the Apache License, Version 2.0 (the
|
||||
"License"); you may not use this file except in compliance
|
||||
with the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing,
|
||||
software distributed under the License is distributed on an
|
||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
KIND, either express or implied. See the License for the
|
||||
specific language governing permissions and limitations
|
||||
under the License.
|
||||
*/
|
||||
package com.phonegap;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.Environment;
|
||||
import android.os.StatFs;
|
||||
|
||||
/**
|
||||
* This class provides file directory utilities.
|
||||
* All file operations are performed on the SD card.
|
||||
*
|
||||
* It is used by the FileUtils class.
|
||||
*/
|
||||
public class DirectoryManager {
|
||||
|
||||
private static final String LOG_TAG = "DirectoryManager";
|
||||
|
||||
/**
|
||||
* Determine if a file or directory exists.
|
||||
*
|
||||
* @param name The name of the file to check.
|
||||
* @return T=exists, F=not found
|
||||
*/
|
||||
protected static boolean testFileExists(String name) {
|
||||
boolean status;
|
||||
|
||||
// If SD card exists
|
||||
if ((testSaveLocationExists()) && (!name.equals(""))) {
|
||||
File path = Environment.getExternalStorageDirectory();
|
||||
File newPath = constructFilePaths(path.toString(), name);
|
||||
status = newPath.exists();
|
||||
}
|
||||
// If no SD card
|
||||
else{
|
||||
status = false;
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the free disk space
|
||||
*
|
||||
* @return Size in KB or -1 if not available
|
||||
*/
|
||||
protected static long getFreeDiskSpace(boolean checkInternal) {
|
||||
String status = Environment.getExternalStorageState();
|
||||
long freeSpace = 0;
|
||||
|
||||
// If SD card exists
|
||||
if (status.equals(Environment.MEDIA_MOUNTED)) {
|
||||
freeSpace = freeSpaceCalculation(Environment.getExternalStorageDirectory().getPath());
|
||||
}
|
||||
else if (checkInternal) {
|
||||
freeSpace = freeSpaceCalculation("/");
|
||||
}
|
||||
// If no SD card and we haven't been asked to check the internal directory then return -1
|
||||
else {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return freeSpace;
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a path return the number of free KB
|
||||
*
|
||||
* @param path to the file system
|
||||
* @return free space in KB
|
||||
*/
|
||||
private static long freeSpaceCalculation(String path) {
|
||||
StatFs stat = new StatFs(path);
|
||||
long blockSize = stat.getBlockSize();
|
||||
long availableBlocks = stat.getAvailableBlocks();
|
||||
return availableBlocks*blockSize/1024;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if SD card exists.
|
||||
*
|
||||
* @return T=exists, F=not found
|
||||
*/
|
||||
protected static boolean testSaveLocationExists() {
|
||||
String sDCardStatus = Environment.getExternalStorageState();
|
||||
boolean status;
|
||||
|
||||
// If SD card is mounted
|
||||
if (sDCardStatus.equals(Environment.MEDIA_MOUNTED)) {
|
||||
status = true;
|
||||
}
|
||||
|
||||
// If no SD card
|
||||
else {
|
||||
status = false;
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new file object from two file paths.
|
||||
*
|
||||
* @param file1 Base file path
|
||||
* @param file2 Remaining file path
|
||||
* @return File object
|
||||
*/
|
||||
private static File constructFilePaths (String file1, String file2) {
|
||||
File newPath;
|
||||
if (file2.startsWith(file1)) {
|
||||
newPath = new File(file2);
|
||||
}
|
||||
else {
|
||||
newPath = new File(file1+"/"+file2);
|
||||
}
|
||||
return newPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if we can use the SD Card to store the temporary file. If not then use
|
||||
* the internal cache directory.
|
||||
*
|
||||
* @return the absolute path of where to store the file
|
||||
*/
|
||||
protected static String getTempDirectoryPath(Context ctx) {
|
||||
File cache = null;
|
||||
|
||||
// SD Card Mounted
|
||||
if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
|
||||
cache = new File(Environment.getExternalStorageDirectory().getAbsolutePath() +
|
||||
"/Android/data/" + ctx.getPackageName() + "/cache/");
|
||||
}
|
||||
// Use internal storage
|
||||
else {
|
||||
cache = ctx.getCacheDir();
|
||||
}
|
||||
|
||||
// Create the cache directory if it doesn't exist
|
||||
if (!cache.exists()) {
|
||||
cache.mkdirs();
|
||||
}
|
||||
|
||||
return cache.getAbsolutePath();
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,165 +0,0 @@
|
||||
/*
|
||||
Licensed to the Apache Software Foundation (ASF) under one
|
||||
or more contributor license agreements. See the NOTICE file
|
||||
distributed with this work for additional information
|
||||
regarding copyright ownership. The ASF licenses this file
|
||||
to you under the Apache License, Version 2.0 (the
|
||||
"License"); you may not use this file except in compliance
|
||||
with the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing,
|
||||
software distributed under the License is distributed on an
|
||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
KIND, either express or implied. See the License for the
|
||||
specific language governing permissions and limitations
|
||||
under the License.
|
||||
*/
|
||||
package com.phonegap;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import android.media.ExifInterface;
|
||||
|
||||
public class ExifHelper {
|
||||
private String aperature = null;
|
||||
private String datetime = null;
|
||||
private String exposureTime = null;
|
||||
private String flash = null;
|
||||
private String focalLength = null;
|
||||
private String gpsAltitude = null;
|
||||
private String gpsAltitudeRef = null;
|
||||
private String gpsDateStamp = null;
|
||||
private String gpsLatitude = null;
|
||||
private String gpsLatitudeRef = null;
|
||||
private String gpsLongitude = null;
|
||||
private String gpsLongitudeRef = null;
|
||||
private String gpsProcessingMethod = null;
|
||||
private String gpsTimestamp = null;
|
||||
private String iso = null;
|
||||
private String make = null;
|
||||
private String model = null;
|
||||
private String orientation = null;
|
||||
private String whiteBalance = null;
|
||||
|
||||
private ExifInterface inFile = null;
|
||||
private ExifInterface outFile = null;
|
||||
|
||||
/**
|
||||
* The file before it is compressed
|
||||
*
|
||||
* @param filePath
|
||||
* @throws IOException
|
||||
*/
|
||||
public void createInFile(String filePath) throws IOException {
|
||||
this.inFile = new ExifInterface(filePath);
|
||||
}
|
||||
|
||||
/**
|
||||
* The file after it has been compressed
|
||||
*
|
||||
* @param filePath
|
||||
* @throws IOException
|
||||
*/
|
||||
public void createOutFile(String filePath) throws IOException {
|
||||
this.outFile = new ExifInterface(filePath);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads all the EXIF data from the input file.
|
||||
*/
|
||||
public void readExifData() {
|
||||
this.aperature = inFile.getAttribute(ExifInterface.TAG_APERTURE);
|
||||
this.datetime = inFile.getAttribute(ExifInterface.TAG_DATETIME);
|
||||
this.exposureTime = inFile.getAttribute(ExifInterface.TAG_EXPOSURE_TIME);
|
||||
this.flash = inFile.getAttribute(ExifInterface.TAG_FLASH);
|
||||
this.focalLength = inFile.getAttribute(ExifInterface.TAG_FOCAL_LENGTH);
|
||||
this.gpsAltitude = inFile.getAttribute(ExifInterface.TAG_GPS_ALTITUDE);
|
||||
this.gpsAltitudeRef = inFile.getAttribute(ExifInterface.TAG_GPS_ALTITUDE_REF);
|
||||
this.gpsDateStamp = inFile.getAttribute(ExifInterface.TAG_GPS_DATESTAMP);
|
||||
this.gpsLatitude = inFile.getAttribute(ExifInterface.TAG_GPS_LATITUDE);
|
||||
this.gpsLatitudeRef = inFile.getAttribute(ExifInterface.TAG_GPS_LATITUDE_REF);
|
||||
this.gpsLongitude = inFile.getAttribute(ExifInterface.TAG_GPS_LONGITUDE);
|
||||
this.gpsLongitudeRef = inFile.getAttribute(ExifInterface.TAG_GPS_LONGITUDE_REF);
|
||||
this.gpsProcessingMethod = inFile.getAttribute(ExifInterface.TAG_GPS_PROCESSING_METHOD);
|
||||
this.gpsTimestamp = inFile.getAttribute(ExifInterface.TAG_GPS_TIMESTAMP);
|
||||
this.iso = inFile.getAttribute(ExifInterface.TAG_ISO);
|
||||
this.make = inFile.getAttribute(ExifInterface.TAG_MAKE);
|
||||
this.model = inFile.getAttribute(ExifInterface.TAG_MODEL);
|
||||
this.orientation = inFile.getAttribute(ExifInterface.TAG_ORIENTATION);
|
||||
this.whiteBalance = inFile.getAttribute(ExifInterface.TAG_WHITE_BALANCE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the previously stored EXIF data to the output file.
|
||||
*
|
||||
* @throws IOException
|
||||
*/
|
||||
public void writeExifData() throws IOException {
|
||||
// Don't try to write to a null file
|
||||
if (this.outFile == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.aperature != null) {
|
||||
this.outFile.setAttribute(ExifInterface.TAG_APERTURE, this.aperature);
|
||||
}
|
||||
if (this.datetime != null) {
|
||||
this.outFile.setAttribute(ExifInterface.TAG_DATETIME, this.datetime);
|
||||
}
|
||||
if (this.exposureTime != null) {
|
||||
this.outFile.setAttribute(ExifInterface.TAG_EXPOSURE_TIME, this.exposureTime);
|
||||
}
|
||||
if (this.flash != null) {
|
||||
this.outFile.setAttribute(ExifInterface.TAG_FLASH, this.flash);
|
||||
}
|
||||
if (this.focalLength != null) {
|
||||
this.outFile.setAttribute(ExifInterface.TAG_FOCAL_LENGTH, this.focalLength);
|
||||
}
|
||||
if (this.gpsAltitude != null) {
|
||||
this.outFile.setAttribute(ExifInterface.TAG_GPS_ALTITUDE, this.gpsAltitude);
|
||||
}
|
||||
if (this.gpsAltitudeRef != null) {
|
||||
this.outFile.setAttribute(ExifInterface.TAG_GPS_ALTITUDE_REF, this.gpsAltitudeRef);
|
||||
}
|
||||
if (this.gpsDateStamp != null) {
|
||||
this.outFile.setAttribute(ExifInterface.TAG_GPS_DATESTAMP, this.gpsDateStamp);
|
||||
}
|
||||
if (this.gpsLatitude != null) {
|
||||
this.outFile.setAttribute(ExifInterface.TAG_GPS_LATITUDE, this.gpsLatitude);
|
||||
}
|
||||
if (this.gpsLatitudeRef != null) {
|
||||
this.outFile.setAttribute(ExifInterface.TAG_GPS_LATITUDE_REF, this.gpsLatitudeRef);
|
||||
}
|
||||
if (this.gpsLongitude != null) {
|
||||
this.outFile.setAttribute(ExifInterface.TAG_GPS_LONGITUDE, this.gpsLongitude);
|
||||
}
|
||||
if (this.gpsLongitudeRef != null) {
|
||||
this.outFile.setAttribute(ExifInterface.TAG_GPS_LONGITUDE_REF, this.gpsLongitudeRef);
|
||||
}
|
||||
if (this.gpsProcessingMethod != null) {
|
||||
this.outFile.setAttribute(ExifInterface.TAG_GPS_PROCESSING_METHOD, this.gpsProcessingMethod);
|
||||
}
|
||||
if (this.gpsTimestamp != null) {
|
||||
this.outFile.setAttribute(ExifInterface.TAG_GPS_TIMESTAMP, this.gpsTimestamp);
|
||||
}
|
||||
if (this.iso != null) {
|
||||
this.outFile.setAttribute(ExifInterface.TAG_ISO, this.iso);
|
||||
}
|
||||
if (this.make != null) {
|
||||
this.outFile.setAttribute(ExifInterface.TAG_MAKE, this.make);
|
||||
}
|
||||
if (this.model != null) {
|
||||
this.outFile.setAttribute(ExifInterface.TAG_MODEL, this.model);
|
||||
}
|
||||
if (this.orientation != null) {
|
||||
this.outFile.setAttribute(ExifInterface.TAG_ORIENTATION, this.orientation);
|
||||
}
|
||||
if (this.whiteBalance != null) {
|
||||
this.outFile.setAttribute(ExifInterface.TAG_WHITE_BALANCE, this.whiteBalance);
|
||||
}
|
||||
|
||||
this.outFile.saveAttributes();
|
||||
}
|
||||
}
|
||||
@@ -1,443 +0,0 @@
|
||||
/*
|
||||
Licensed to the Apache Software Foundation (ASF) under one
|
||||
or more contributor license agreements. See the NOTICE file
|
||||
distributed with this work for additional information
|
||||
regarding copyright ownership. The ASF licenses this file
|
||||
to you under the Apache License, Version 2.0 (the
|
||||
"License"); you may not use this file except in compliance
|
||||
with the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing,
|
||||
software distributed under the License is distributed on an
|
||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
KIND, either express or implied. See the License for the
|
||||
specific language governing permissions and limitations
|
||||
under the License.
|
||||
*/
|
||||
package com.phonegap;
|
||||
|
||||
import java.io.DataInputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.URL;
|
||||
import java.security.cert.CertificateException;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.util.Iterator;
|
||||
|
||||
import javax.net.ssl.HostnameVerifier;
|
||||
import javax.net.ssl.HttpsURLConnection;
|
||||
import javax.net.ssl.SSLContext;
|
||||
import javax.net.ssl.SSLException;
|
||||
import javax.net.ssl.SSLSession;
|
||||
import javax.net.ssl.SSLSocketFactory;
|
||||
import javax.net.ssl.TrustManager;
|
||||
import javax.net.ssl.X509TrustManager;
|
||||
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import android.net.Uri;
|
||||
import android.util.Log;
|
||||
import android.webkit.CookieManager;
|
||||
|
||||
import com.phonegap.api.Plugin;
|
||||
import com.phonegap.api.PluginResult;
|
||||
|
||||
public class FileTransfer extends Plugin {
|
||||
|
||||
private static final String LOG_TAG = "FileTransfer";
|
||||
private static final String LINE_START = "--";
|
||||
private static final String LINE_END = "\r\n";
|
||||
private static final String BOUNDRY = "*****";
|
||||
|
||||
public static int FILE_NOT_FOUND_ERR = 1;
|
||||
public static int INVALID_URL_ERR = 2;
|
||||
public static int CONNECTION_ERR = 3;
|
||||
|
||||
private SSLSocketFactory defaultSSLSocketFactory = null;
|
||||
private HostnameVerifier defaultHostnameVerifier = null;
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see com.phonegap.api.Plugin#execute(java.lang.String, org.json.JSONArray, java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
public PluginResult execute(String action, JSONArray args, String callbackId) {
|
||||
String source = null;
|
||||
String target = null;
|
||||
try {
|
||||
source = args.getString(0);
|
||||
target = args.getString(1);
|
||||
}
|
||||
catch (JSONException e) {
|
||||
Log.d(LOG_TAG, "Missing source or target");
|
||||
return new PluginResult(PluginResult.Status.JSON_EXCEPTION, "Missing source or target");
|
||||
}
|
||||
|
||||
try {
|
||||
if (action.equals("upload")) {
|
||||
// Setup the options
|
||||
String fileKey = null;
|
||||
String fileName = null;
|
||||
String mimeType = null;
|
||||
|
||||
fileKey = getArgument(args, 2, "file");
|
||||
fileName = getArgument(args, 3, "image.jpg");
|
||||
mimeType = getArgument(args, 4, "image/jpeg");
|
||||
JSONObject params = args.optJSONObject(5);
|
||||
boolean trustEveryone = args.optBoolean(6);
|
||||
boolean chunkedMode = args.optBoolean(7);
|
||||
FileUploadResult r = upload(source, target, fileKey, fileName, mimeType, params, trustEveryone, chunkedMode);
|
||||
Log.d(LOG_TAG, "****** About to return a result from upload");
|
||||
return new PluginResult(PluginResult.Status.OK, r.toJSONObject());
|
||||
} else if (action.equals("download")) {
|
||||
JSONObject r = download(source, target);
|
||||
Log.d(LOG_TAG, "****** About to return a result from download");
|
||||
return new PluginResult(PluginResult.Status.OK, r, "window.localFileSystem._castEntry");
|
||||
} else {
|
||||
return new PluginResult(PluginResult.Status.INVALID_ACTION);
|
||||
}
|
||||
} catch (FileNotFoundException e) {
|
||||
Log.e(LOG_TAG, e.getMessage(), e);
|
||||
JSONObject error = createFileTransferError(FILE_NOT_FOUND_ERR, source, target);
|
||||
return new PluginResult(PluginResult.Status.IO_EXCEPTION, error);
|
||||
} catch (IllegalArgumentException e) {
|
||||
Log.e(LOG_TAG, e.getMessage(), e);
|
||||
JSONObject error = createFileTransferError(INVALID_URL_ERR, source, target);
|
||||
return new PluginResult(PluginResult.Status.IO_EXCEPTION, error);
|
||||
} catch (SSLException e) {
|
||||
Log.e(LOG_TAG, e.getMessage(), e);
|
||||
Log.d(LOG_TAG, "Got my ssl exception!!!");
|
||||
JSONObject error = createFileTransferError(CONNECTION_ERR, source, target);
|
||||
return new PluginResult(PluginResult.Status.IO_EXCEPTION, error);
|
||||
} catch (IOException e) {
|
||||
Log.e(LOG_TAG, e.getMessage(), e);
|
||||
JSONObject error = createFileTransferError(CONNECTION_ERR, source, target);
|
||||
return new PluginResult(PluginResult.Status.IO_EXCEPTION, error);
|
||||
} catch (JSONException e) {
|
||||
Log.e(LOG_TAG, e.getMessage(), e);
|
||||
return new PluginResult(PluginResult.Status.JSON_EXCEPTION);
|
||||
}
|
||||
}
|
||||
|
||||
// always verify the host - don't check for certificate
|
||||
final static HostnameVerifier DO_NOT_VERIFY = new HostnameVerifier() {
|
||||
public boolean verify(String hostname, SSLSession session) {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* This function will install a trust manager that will blindly trust all SSL
|
||||
* certificates. The reason this code is being added is to enable developers
|
||||
* to do development using self signed SSL certificates on their web server.
|
||||
*
|
||||
* The standard HttpsURLConnection class will throw an exception on self
|
||||
* signed certificates if this code is not run.
|
||||
*/
|
||||
private void trustAllHosts() {
|
||||
// Create a trust manager that does not validate certificate chains
|
||||
TrustManager[] trustAllCerts = new TrustManager[] { new X509TrustManager() {
|
||||
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
|
||||
return new java.security.cert.X509Certificate[] {};
|
||||
}
|
||||
|
||||
public void checkClientTrusted(X509Certificate[] chain,
|
||||
String authType) throws CertificateException {
|
||||
}
|
||||
|
||||
public void checkServerTrusted(X509Certificate[] chain,
|
||||
String authType) throws CertificateException {
|
||||
}
|
||||
} };
|
||||
|
||||
// Install the all-trusting trust manager
|
||||
try {
|
||||
// Backup the current SSL socket factory
|
||||
defaultSSLSocketFactory = HttpsURLConnection.getDefaultSSLSocketFactory();
|
||||
// Install our all trusting manager
|
||||
SSLContext sc = SSLContext.getInstance("TLS");
|
||||
sc.init(null, trustAllCerts, new java.security.SecureRandom());
|
||||
HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
|
||||
} catch (Exception e) {
|
||||
Log.e(LOG_TAG, e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an error object based on the passed in errorCode
|
||||
* @param errorCode the error
|
||||
* @return JSONObject containing the error
|
||||
*/
|
||||
private JSONObject createFileTransferError(int errorCode, String source, String target) {
|
||||
JSONObject error = null;
|
||||
try {
|
||||
error = new JSONObject();
|
||||
error.put("code", errorCode);
|
||||
error.put("source", source);
|
||||
error.put("target", target);
|
||||
} catch (JSONException e) {
|
||||
Log.e(LOG_TAG, e.getMessage(), e);
|
||||
}
|
||||
return error;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience method to read a parameter from the list of JSON args.
|
||||
* @param args the args passed to the Plugin
|
||||
* @param position the position to retrieve the arg from
|
||||
* @param defaultString the default to be used if the arg does not exist
|
||||
* @return String with the retrieved value
|
||||
*/
|
||||
private String getArgument(JSONArray args, int position, String defaultString) {
|
||||
String arg = defaultString;
|
||||
if(args.length() >= position) {
|
||||
arg = args.optString(position);
|
||||
if (arg == null || "null".equals(arg)) {
|
||||
arg = defaultString;
|
||||
}
|
||||
}
|
||||
return arg;
|
||||
}
|
||||
|
||||
/**
|
||||
* Uploads the specified file to the server URL provided using an HTTP
|
||||
* multipart request.
|
||||
* @param file Full path of the file on the file system
|
||||
* @param server URL of the server to receive the file
|
||||
* @param fileKey Name of file request parameter
|
||||
* @param fileName File name to be used on server
|
||||
* @param mimeType Describes file content type
|
||||
* @param params key:value pairs of user-defined parameters
|
||||
* @return FileUploadResult containing result of upload request
|
||||
*/
|
||||
public FileUploadResult upload(String file, String server, final String fileKey, final String fileName,
|
||||
final String mimeType, JSONObject params, boolean trustEveryone, boolean chunkedMode) throws IOException, SSLException {
|
||||
// Create return object
|
||||
FileUploadResult result = new FileUploadResult();
|
||||
|
||||
// Get a input stream of the file on the phone
|
||||
InputStream fileInputStream = getPathFromUri(file);
|
||||
|
||||
HttpURLConnection conn = null;
|
||||
DataOutputStream dos = null;
|
||||
|
||||
int bytesRead, bytesAvailable, bufferSize;
|
||||
long totalBytes;
|
||||
byte[] buffer;
|
||||
int maxBufferSize = 8096;
|
||||
|
||||
//------------------ CLIENT REQUEST
|
||||
// open a URL connection to the server
|
||||
URL url = new URL(server);
|
||||
|
||||
// Open a HTTP connection to the URL based on protocol
|
||||
if (url.getProtocol().toLowerCase().equals("https")) {
|
||||
// Using standard HTTPS connection. Will not allow self signed certificate
|
||||
if (!trustEveryone) {
|
||||
conn = (HttpsURLConnection) url.openConnection();
|
||||
}
|
||||
// Use our HTTPS connection that blindly trusts everyone.
|
||||
// This should only be used in debug environments
|
||||
else {
|
||||
// Setup the HTTPS connection class to trust everyone
|
||||
trustAllHosts();
|
||||
HttpsURLConnection https = (HttpsURLConnection) url.openConnection();
|
||||
// Save the current hostnameVerifier
|
||||
defaultHostnameVerifier = https.getHostnameVerifier();
|
||||
// Setup the connection not to verify hostnames
|
||||
https.setHostnameVerifier(DO_NOT_VERIFY);
|
||||
conn = https;
|
||||
}
|
||||
}
|
||||
// Return a standard HTTP connection
|
||||
else {
|
||||
conn = (HttpURLConnection) url.openConnection();
|
||||
}
|
||||
|
||||
// Allow Inputs
|
||||
conn.setDoInput(true);
|
||||
|
||||
// Allow Outputs
|
||||
conn.setDoOutput(true);
|
||||
|
||||
// Don't use a cached copy.
|
||||
conn.setUseCaches(false);
|
||||
|
||||
// Use a post method.
|
||||
conn.setRequestMethod("POST");
|
||||
conn.setRequestProperty("Connection", "Keep-Alive");
|
||||
conn.setRequestProperty("Content-Type", "multipart/form-data;boundary="+BOUNDRY);
|
||||
|
||||
// Set the cookies on the response
|
||||
String cookie = CookieManager.getInstance().getCookie(server);
|
||||
if (cookie != null) {
|
||||
conn.setRequestProperty("Cookie", cookie);
|
||||
}
|
||||
|
||||
// Should set this up as an option
|
||||
if (chunkedMode) {
|
||||
conn.setChunkedStreamingMode(maxBufferSize);
|
||||
}
|
||||
|
||||
dos = new DataOutputStream( conn.getOutputStream() );
|
||||
|
||||
// Send any extra parameters
|
||||
try {
|
||||
for (Iterator iter = params.keys(); iter.hasNext();) {
|
||||
Object key = iter.next();
|
||||
dos.writeBytes(LINE_START + BOUNDRY + LINE_END);
|
||||
dos.writeBytes("Content-Disposition: form-data; name=\"" + key.toString() + "\";");
|
||||
dos.writeBytes(LINE_END + LINE_END);
|
||||
dos.write(params.getString(key.toString()).getBytes());
|
||||
dos.writeBytes(LINE_END);
|
||||
}
|
||||
} catch (JSONException e) {
|
||||
Log.e(LOG_TAG, e.getMessage(), e);
|
||||
}
|
||||
|
||||
dos.writeBytes(LINE_START + BOUNDRY + LINE_END);
|
||||
dos.writeBytes("Content-Disposition: form-data; name=\"" + fileKey + "\";" + " filename=\"" + fileName +"\"" + LINE_END);
|
||||
dos.writeBytes("Content-Type: " + mimeType + LINE_END);
|
||||
dos.writeBytes(LINE_END);
|
||||
|
||||
// create a buffer of maximum size
|
||||
bytesAvailable = fileInputStream.available();
|
||||
bufferSize = Math.min(bytesAvailable, maxBufferSize);
|
||||
buffer = new byte[bufferSize];
|
||||
|
||||
// read file and write it into form...
|
||||
bytesRead = fileInputStream.read(buffer, 0, bufferSize);
|
||||
totalBytes = 0;
|
||||
|
||||
while (bytesRead > 0) {
|
||||
totalBytes += bytesRead;
|
||||
result.setBytesSent(totalBytes);
|
||||
dos.write(buffer, 0, bufferSize);
|
||||
bytesAvailable = fileInputStream.available();
|
||||
bufferSize = Math.min(bytesAvailable, maxBufferSize);
|
||||
bytesRead = fileInputStream.read(buffer, 0, bufferSize);
|
||||
}
|
||||
|
||||
// send multipart form data necesssary after file data...
|
||||
dos.writeBytes(LINE_END);
|
||||
dos.writeBytes(LINE_START + BOUNDRY + LINE_START + LINE_END);
|
||||
|
||||
// close streams
|
||||
fileInputStream.close();
|
||||
dos.flush();
|
||||
dos.close();
|
||||
|
||||
//------------------ read the SERVER RESPONSE
|
||||
StringBuffer responseString = new StringBuffer("");
|
||||
DataInputStream inStream;
|
||||
try {
|
||||
inStream = new DataInputStream ( conn.getInputStream() );
|
||||
} catch(FileNotFoundException e) {
|
||||
throw new IOException("Received error from server");
|
||||
}
|
||||
|
||||
String line;
|
||||
while (( line = inStream.readLine()) != null) {
|
||||
responseString.append(line);
|
||||
}
|
||||
Log.d(LOG_TAG, "got response from server");
|
||||
Log.d(LOG_TAG, responseString.toString());
|
||||
|
||||
// send request and retrieve response
|
||||
result.setResponseCode(conn.getResponseCode());
|
||||
result.setResponse(responseString.toString());
|
||||
|
||||
inStream.close();
|
||||
conn.disconnect();
|
||||
|
||||
// Revert back to the proper verifier and socket factories
|
||||
if (trustEveryone && url.getProtocol().toLowerCase().equals("https")) {
|
||||
((HttpsURLConnection)conn).setHostnameVerifier(defaultHostnameVerifier);
|
||||
HttpsURLConnection.setDefaultSSLSocketFactory(defaultSSLSocketFactory);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Downloads a file form a given URL and saves it to the specified directory.
|
||||
*
|
||||
* @param source URL of the server to receive the file
|
||||
* @param target Full path of the file on the file system
|
||||
* @return JSONObject the downloaded file
|
||||
*/
|
||||
public JSONObject download(String source, String target) throws IOException {
|
||||
try {
|
||||
File file = new File(target);
|
||||
|
||||
// create needed directories
|
||||
file.getParentFile().mkdirs();
|
||||
|
||||
// connect to server
|
||||
URL url = new URL(source);
|
||||
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
|
||||
connection.setRequestMethod("GET");
|
||||
connection.connect();
|
||||
|
||||
Log.d(LOG_TAG, "Download file:" + url);
|
||||
|
||||
InputStream inputStream = connection.getInputStream();
|
||||
byte[] buffer = new byte[1024];
|
||||
int bytesRead = 0;
|
||||
|
||||
FileOutputStream outputStream = new FileOutputStream(file);
|
||||
|
||||
// write bytes to file
|
||||
while ( (bytesRead = inputStream.read(buffer)) > 0 ) {
|
||||
outputStream.write(buffer,0, bytesRead);
|
||||
}
|
||||
|
||||
outputStream.close();
|
||||
|
||||
Log.d(LOG_TAG, "Saved file: " + target);
|
||||
|
||||
// create FileEntry object
|
||||
FileUtils fileUtil = new FileUtils();
|
||||
|
||||
return fileUtil.getEntry(file);
|
||||
} catch (Exception e) {
|
||||
Log.d(LOG_TAG, e.getMessage(), e);
|
||||
throw new IOException("Error while downloading");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an input stream based on file path or content:// uri
|
||||
*
|
||||
* @param path
|
||||
* @return an input stream
|
||||
* @throws FileNotFoundException
|
||||
*/
|
||||
private InputStream getPathFromUri(String path) throws FileNotFoundException {
|
||||
if (path.startsWith("content:")) {
|
||||
Uri uri = Uri.parse(path);
|
||||
return ctx.getContentResolver().openInputStream(uri);
|
||||
}
|
||||
else if (path.startsWith("file://")) {
|
||||
int question = path.indexOf("?");
|
||||
if (question == -1) {
|
||||
return new FileInputStream(path.substring(7));
|
||||
} else {
|
||||
return new FileInputStream(path.substring(7, question));
|
||||
}
|
||||
}
|
||||
else {
|
||||
return new FileInputStream(path);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,63 +0,0 @@
|
||||
/*
|
||||
Licensed to the Apache Software Foundation (ASF) under one
|
||||
or more contributor license agreements. See the NOTICE file
|
||||
distributed with this work for additional information
|
||||
regarding copyright ownership. The ASF licenses this file
|
||||
to you under the Apache License, Version 2.0 (the
|
||||
"License"); you may not use this file except in compliance
|
||||
with the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing,
|
||||
software distributed under the License is distributed on an
|
||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
KIND, either express or implied. See the License for the
|
||||
specific language governing permissions and limitations
|
||||
under the License.
|
||||
*/
|
||||
package com.phonegap;
|
||||
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
/**
|
||||
* Encapsulates the result and/or status of uploading a file to a remote server.
|
||||
*/
|
||||
public class FileUploadResult {
|
||||
|
||||
private long bytesSent = 0; // bytes sent
|
||||
private int responseCode = -1; // HTTP response code
|
||||
private String response = null; // HTTP response
|
||||
|
||||
public long getBytesSent() {
|
||||
return bytesSent;
|
||||
}
|
||||
|
||||
public void setBytesSent(long bytes) {
|
||||
this.bytesSent = bytes;
|
||||
}
|
||||
|
||||
public int getResponseCode() {
|
||||
return responseCode;
|
||||
}
|
||||
|
||||
public void setResponseCode(int responseCode) {
|
||||
this.responseCode = responseCode;
|
||||
}
|
||||
|
||||
public String getResponse() {
|
||||
return response;
|
||||
}
|
||||
|
||||
public void setResponse(String response) {
|
||||
this.response = response;
|
||||
}
|
||||
|
||||
public JSONObject toJSONObject() throws JSONException {
|
||||
return new JSONObject(
|
||||
"{bytesSent:" + bytesSent +
|
||||
",responseCode:" + responseCode +
|
||||
",response:" + JSONObject.quote(response) + "}");
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,165 +0,0 @@
|
||||
/*
|
||||
Licensed to the Apache Software Foundation (ASF) under one
|
||||
or more contributor license agreements. See the NOTICE file
|
||||
distributed with this work for additional information
|
||||
regarding copyright ownership. The ASF licenses this file
|
||||
to you under the Apache License, Version 2.0 (the
|
||||
"License"); you may not use this file except in compliance
|
||||
with the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing,
|
||||
software distributed under the License is distributed on an
|
||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
KIND, either express or implied. See the License for the
|
||||
specific language governing permissions and limitations
|
||||
under the License.
|
||||
*/
|
||||
package com.phonegap;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
|
||||
import com.phonegap.api.Plugin;
|
||||
import com.phonegap.api.PluginResult;
|
||||
|
||||
/*
|
||||
* This class is the interface to the Geolocation. It's bound to the geo object.
|
||||
*
|
||||
* This class only starts and stops various GeoListeners, which consist of a GPS and a Network Listener
|
||||
*/
|
||||
|
||||
public class GeoBroker extends Plugin {
|
||||
|
||||
// List of gGeolocation listeners
|
||||
private HashMap<String, GeoListener> geoListeners;
|
||||
private GeoListener global;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
public GeoBroker() {
|
||||
this.geoListeners = new HashMap<String, GeoListener>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes the request and returns PluginResult.
|
||||
*
|
||||
* @param action The action to execute.
|
||||
* @param args JSONArry of arguments for the plugin.
|
||||
* @param callbackId The callback id used when calling back into JavaScript.
|
||||
* @return A PluginResult object with a status and message.
|
||||
*/
|
||||
public PluginResult execute(String action, JSONArray args, String callbackId) {
|
||||
PluginResult.Status status = PluginResult.Status.OK;
|
||||
String result = "";
|
||||
|
||||
try {
|
||||
if (action.equals("getCurrentLocation")) {
|
||||
this.getCurrentLocation(args.getBoolean(0), args.getInt(1), args.getInt(2));
|
||||
}
|
||||
else if (action.equals("start")) {
|
||||
String s = this.start(args.getString(0), args.getBoolean(1), args.getInt(2), args.getInt(3));
|
||||
return new PluginResult(status, s);
|
||||
}
|
||||
else if (action.equals("stop")) {
|
||||
this.stop(args.getString(0));
|
||||
}
|
||||
return new PluginResult(status, result);
|
||||
} catch (JSONException e) {
|
||||
return new PluginResult(PluginResult.Status.JSON_EXCEPTION);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Identifies if action to be executed returns a value and should be run synchronously.
|
||||
*
|
||||
* @param action The action to execute
|
||||
* @return T=returns value
|
||||
*/
|
||||
public boolean isSynch(String action) {
|
||||
// Starting listeners is easier to run on main thread, so don't run async.
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the activity is to be shut down.
|
||||
* Stop listener.
|
||||
*/
|
||||
public void onDestroy() {
|
||||
java.util.Set<Entry<String,GeoListener>> s = this.geoListeners.entrySet();
|
||||
java.util.Iterator<Entry<String,GeoListener>> it = s.iterator();
|
||||
while (it.hasNext()) {
|
||||
Entry<String,GeoListener> entry = it.next();
|
||||
GeoListener listener = entry.getValue();
|
||||
listener.destroy();
|
||||
}
|
||||
this.geoListeners.clear();
|
||||
if (this.global != null) {
|
||||
this.global.destroy();
|
||||
}
|
||||
this.global = null;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// LOCAL METHODS
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Get current location.
|
||||
* The result is returned to JavaScript via a callback.
|
||||
*
|
||||
* @param enableHighAccuracy
|
||||
* @param timeout
|
||||
* @param maximumAge
|
||||
*/
|
||||
public void getCurrentLocation(boolean enableHighAccuracy, int timeout, int maximumAge) {
|
||||
|
||||
// Create a geolocation listener just for getCurrentLocation and call it "global"
|
||||
if (this.global == null) {
|
||||
this.global = new GeoListener(this, "global", maximumAge);
|
||||
}
|
||||
else {
|
||||
this.global.start(maximumAge);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Start geolocation listener and add to listener list.
|
||||
*
|
||||
* @param key The listener id
|
||||
* @param enableHighAccuracy
|
||||
* @param timeout
|
||||
* @param maximumAge
|
||||
* @return
|
||||
*/
|
||||
public String start(String key, boolean enableHighAccuracy, int timeout, int maximumAge) {
|
||||
|
||||
// Make sure this listener doesn't already exist
|
||||
GeoListener listener = geoListeners.get(key);
|
||||
if (listener == null) {
|
||||
listener = new GeoListener(this, key, maximumAge);
|
||||
geoListeners.put(key, listener);
|
||||
}
|
||||
|
||||
// Start it
|
||||
listener.start(maximumAge);
|
||||
return key;
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop geolocation listener and remove from listener list.
|
||||
*
|
||||
* @param key The listener id
|
||||
*/
|
||||
public void stop(String key) {
|
||||
GeoListener listener = geoListeners.remove(key);
|
||||
if (listener != null) {
|
||||
listener.stop();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,133 +0,0 @@
|
||||
/*
|
||||
Licensed to the Apache Software Foundation (ASF) under one
|
||||
or more contributor license agreements. See the NOTICE file
|
||||
distributed with this work for additional information
|
||||
regarding copyright ownership. The ASF licenses this file
|
||||
to you under the Apache License, Version 2.0 (the
|
||||
"License"); you may not use this file except in compliance
|
||||
with the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing,
|
||||
software distributed under the License is distributed on an
|
||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
KIND, either express or implied. See the License for the
|
||||
specific language governing permissions and limitations
|
||||
under the License.
|
||||
*/
|
||||
package com.phonegap;
|
||||
|
||||
import android.content.Context;
|
||||
import android.location.Location;
|
||||
import android.location.LocationManager;
|
||||
import android.webkit.WebView;
|
||||
|
||||
public class GeoListener {
|
||||
public static int PERMISSION_DENIED = 1;
|
||||
public static int POSITION_UNAVAILABLE = 2;
|
||||
public static int TIMEOUT = 3;
|
||||
|
||||
String id; // Listener ID
|
||||
String successCallback; //
|
||||
String failCallback;
|
||||
GpsListener mGps; // GPS listener
|
||||
NetworkListener mNetwork; // Network listener
|
||||
LocationManager mLocMan; // Location manager
|
||||
|
||||
private GeoBroker broker; // GeoBroker object
|
||||
|
||||
int interval;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param id Listener id
|
||||
* @param ctx
|
||||
* @param time Sampling period in msec
|
||||
* @param appView
|
||||
*/
|
||||
GeoListener(GeoBroker broker, String id, int time) {
|
||||
this.id = id;
|
||||
this.interval = time;
|
||||
this.broker = broker;
|
||||
this.mGps = null;
|
||||
this.mNetwork = null;
|
||||
this.mLocMan = (LocationManager) broker.ctx.getSystemService(Context.LOCATION_SERVICE);
|
||||
|
||||
// If GPS provider, then create and start GPS listener
|
||||
if (this.mLocMan.getProvider(LocationManager.GPS_PROVIDER) != null) {
|
||||
this.mGps = new GpsListener(broker.ctx, time, this);
|
||||
}
|
||||
|
||||
// If network provider, then create and start network listener
|
||||
if (this.mLocMan.getProvider(LocationManager.NETWORK_PROVIDER) != null) {
|
||||
this.mNetwork = new NetworkListener(broker.ctx, time, this);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroy listener.
|
||||
*/
|
||||
public void destroy() {
|
||||
this.stop();
|
||||
}
|
||||
|
||||
/**
|
||||
* Location found. Send location back to JavaScript.
|
||||
*
|
||||
* @param loc
|
||||
*/
|
||||
void success(Location loc) {
|
||||
|
||||
String params = loc.getLatitude() + "," + loc.getLongitude() + ", " + loc.getAltitude() +
|
||||
"," + loc.getAccuracy() + "," + loc.getBearing() +
|
||||
"," + loc.getSpeed() + "," + loc.getTime();
|
||||
|
||||
if (id == "global") {
|
||||
this.stop();
|
||||
}
|
||||
this.broker.sendJavascript("navigator._geo.success('" + id + "'," + params + ");");
|
||||
}
|
||||
|
||||
/**
|
||||
* Location failed. Send error back to JavaScript.
|
||||
*
|
||||
* @param code The error code
|
||||
* @param msg The error message
|
||||
*/
|
||||
void fail(int code, String msg) {
|
||||
this.broker.sendJavascript("navigator._geo.fail('" + this.id + "', '" + code + "', '" + msg + "');");
|
||||
this.stop();
|
||||
}
|
||||
|
||||
/**
|
||||
* Start retrieving location.
|
||||
*
|
||||
* @param interval
|
||||
*/
|
||||
void start(int interval) {
|
||||
if (this.mGps != null) {
|
||||
this.mGps.start(interval);
|
||||
}
|
||||
if (this.mNetwork != null) {
|
||||
this.mNetwork.start(interval);
|
||||
}
|
||||
if (this.mNetwork == null && this.mGps == null) {
|
||||
this.fail(POSITION_UNAVAILABLE, "No location providers available.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop listening for location.
|
||||
*/
|
||||
void stop() {
|
||||
if (this.mGps != null) {
|
||||
this.mGps.stop();
|
||||
}
|
||||
if (this.mNetwork != null) {
|
||||
this.mNetwork.stop();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,163 +0,0 @@
|
||||
/*
|
||||
Licensed to the Apache Software Foundation (ASF) under one
|
||||
or more contributor license agreements. See the NOTICE file
|
||||
distributed with this work for additional information
|
||||
regarding copyright ownership. The ASF licenses this file
|
||||
to you under the Apache License, Version 2.0 (the
|
||||
"License"); you may not use this file except in compliance
|
||||
with the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing,
|
||||
software distributed under the License is distributed on an
|
||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
KIND, either express or implied. See the License for the
|
||||
specific language governing permissions and limitations
|
||||
under the License.
|
||||
*/
|
||||
|
||||
package com.phonegap;
|
||||
|
||||
import com.phonegap.api.PhonegapActivity;
|
||||
|
||||
import android.content.Context;
|
||||
import android.location.Location;
|
||||
import android.location.LocationManager;
|
||||
import android.location.LocationListener;
|
||||
import android.os.Bundle;
|
||||
|
||||
/**
|
||||
* This class handles requests for GPS location services.
|
||||
*
|
||||
*/
|
||||
public class GpsListener implements LocationListener {
|
||||
|
||||
private PhonegapActivity mCtx; // PhonegapActivity object
|
||||
|
||||
private LocationManager mLocMan; // Location manager object
|
||||
private GeoListener owner; // Geolistener object (parent)
|
||||
private boolean hasData = false; // Flag indicates if location data is available in cLoc
|
||||
private Location cLoc; // Last recieved location
|
||||
private boolean running = false; // Flag indicates if listener is running
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
* Automatically starts listening.
|
||||
*
|
||||
* @param ctx
|
||||
* @param interval
|
||||
* @param m
|
||||
*/
|
||||
public GpsListener(PhonegapActivity ctx, int interval, GeoListener m) {
|
||||
this.owner = m;
|
||||
this.mCtx = ctx;
|
||||
this.mLocMan = (LocationManager) this.mCtx.getSystemService(Context.LOCATION_SERVICE);
|
||||
this.running = false;
|
||||
this.start(interval);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get last location.
|
||||
*
|
||||
* @return Location object
|
||||
*/
|
||||
public Location getLocation() {
|
||||
this.cLoc = this.mLocMan.getLastKnownLocation(LocationManager.GPS_PROVIDER);
|
||||
if (this.cLoc != null) {
|
||||
this.hasData = true;
|
||||
}
|
||||
return this.cLoc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the provider is disabled by the user.
|
||||
*
|
||||
* @param provider
|
||||
*/
|
||||
public void onProviderDisabled(String provider) {
|
||||
this.owner.fail(GeoListener.POSITION_UNAVAILABLE, "GPS provider disabled.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the provider is enabled by the user.
|
||||
*
|
||||
* @param provider
|
||||
*/
|
||||
public void onProviderEnabled(String provider) {
|
||||
System.out.println("GpsListener: The provider "+ provider + " is enabled");
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the provider status changes. This method is called when a
|
||||
* provider is unable to fetch a location or if the provider has recently
|
||||
* become available after a period of unavailability.
|
||||
*
|
||||
* @param provider
|
||||
* @param status
|
||||
* @param extras
|
||||
*/
|
||||
public void onStatusChanged(String provider, int status, Bundle extras) {
|
||||
System.out.println("GpsListener: The status of the provider " + provider + " has changed");
|
||||
if (status == 0) {
|
||||
System.out.println("GpsListener: " + provider + " is OUT OF SERVICE");
|
||||
this.owner.fail(GeoListener.POSITION_UNAVAILABLE, "GPS out of service.");
|
||||
}
|
||||
else if (status == 1) {
|
||||
System.out.println("GpsListener: " + provider + " is TEMPORARILY_UNAVAILABLE");
|
||||
}
|
||||
else {
|
||||
System.out.println("GpsListener: " + provider + " is Available");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the location has changed.
|
||||
*
|
||||
* @param location
|
||||
*/
|
||||
public void onLocationChanged(Location location) {
|
||||
System.out.println("GpsListener: The location has been updated!");
|
||||
this.hasData = true;
|
||||
this.cLoc = location;
|
||||
this.owner.success(location);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if location data is available.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public boolean hasLocation() {
|
||||
return this.hasData;
|
||||
}
|
||||
|
||||
/**
|
||||
* Start requesting location updates.
|
||||
*
|
||||
* @param interval
|
||||
*/
|
||||
public void start(int interval) {
|
||||
if (!this.running) {
|
||||
this.running = true;
|
||||
this.mLocMan.requestLocationUpdates(LocationManager.GPS_PROVIDER, interval, 0, this);
|
||||
this.getLocation();
|
||||
|
||||
// If GPS provider has data, then send now
|
||||
if (this.hasData) {
|
||||
this.owner.success(this.cLoc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop receiving location updates.
|
||||
*/
|
||||
public void stop() {
|
||||
if (this.running) {
|
||||
this.mLocMan.removeUpdates(this);
|
||||
}
|
||||
this.running = false;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,80 +0,0 @@
|
||||
/*
|
||||
Licensed to the Apache Software Foundation (ASF) under one
|
||||
or more contributor license agreements. See the NOTICE file
|
||||
distributed with this work for additional information
|
||||
regarding copyright ownership. The ASF licenses this file
|
||||
to you under the Apache License, Version 2.0 (the
|
||||
"License"); you may not use this file except in compliance
|
||||
with the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing,
|
||||
software distributed under the License is distributed on an
|
||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
KIND, either express or implied. See the License for the
|
||||
specific language governing permissions and limitations
|
||||
under the License.
|
||||
*/
|
||||
package com.phonegap;
|
||||
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
import org.apache.http.HttpEntity;
|
||||
import org.apache.http.HttpResponse;
|
||||
import org.apache.http.client.methods.HttpGet;
|
||||
import org.apache.http.impl.client.DefaultHttpClient;
|
||||
|
||||
public class HttpHandler {
|
||||
|
||||
protected Boolean get(String url, String file)
|
||||
{
|
||||
HttpEntity entity = getHttpEntity(url);
|
||||
try {
|
||||
writeToDisk(entity, file);
|
||||
} catch (Exception e) { e.printStackTrace(); return false; }
|
||||
try {
|
||||
entity.consumeContent();
|
||||
} catch (Exception e) { e.printStackTrace(); return false; }
|
||||
return true;
|
||||
}
|
||||
|
||||
private HttpEntity getHttpEntity(String url)
|
||||
/**
|
||||
* get the http entity at a given url
|
||||
*/
|
||||
{
|
||||
HttpEntity entity=null;
|
||||
try {
|
||||
DefaultHttpClient httpclient = new DefaultHttpClient();
|
||||
HttpGet httpget = new HttpGet(url);
|
||||
HttpResponse response = httpclient.execute(httpget);
|
||||
entity = response.getEntity();
|
||||
} catch (Exception e) { e.printStackTrace(); return null; }
|
||||
return entity;
|
||||
}
|
||||
|
||||
private void writeToDisk(HttpEntity entity, String file) throws IllegalStateException, IOException
|
||||
/**
|
||||
* writes a HTTP entity to the specified filename and location on disk
|
||||
*/
|
||||
{
|
||||
int i=0;
|
||||
String FilePath="/sdcard/" + file;
|
||||
InputStream in = entity.getContent();
|
||||
byte buff[] = new byte[1024];
|
||||
FileOutputStream out=
|
||||
new FileOutputStream(FilePath);
|
||||
do {
|
||||
int numread = in.read(buff);
|
||||
if (numread <= 0)
|
||||
break;
|
||||
out.write(buff, 0, numread);
|
||||
i++;
|
||||
} while (true);
|
||||
out.flush();
|
||||
out.close();
|
||||
}
|
||||
}
|
||||
@@ -1,104 +0,0 @@
|
||||
/*
|
||||
Licensed to the Apache Software Foundation (ASF) under one
|
||||
or more contributor license agreements. See the NOTICE file
|
||||
distributed with this work for additional information
|
||||
regarding copyright ownership. The ASF licenses this file
|
||||
to you under the Apache License, Version 2.0 (the
|
||||
"License"); you may not use this file except in compliance
|
||||
with the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing,
|
||||
software distributed under the License is distributed on an
|
||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
KIND, either express or implied. See the License for the
|
||||
specific language governing permissions and limitations
|
||||
under the License.
|
||||
*/
|
||||
package com.phonegap;
|
||||
import com.phonegap.api.LOG;
|
||||
|
||||
import android.content.Context;
|
||||
import android.view.View.MeasureSpec;
|
||||
import android.widget.LinearLayout;
|
||||
|
||||
/**
|
||||
* This class is used to detect when the soft keyboard is shown and hidden in the web view.
|
||||
*/
|
||||
public class LinearLayoutSoftKeyboardDetect extends LinearLayout {
|
||||
|
||||
private static final String TAG = "SoftKeyboardDetect";
|
||||
|
||||
private int oldHeight = 0; // Need to save the old height as not to send redundant events
|
||||
private int oldWidth = 0; // Need to save old width for orientation change
|
||||
private int screenWidth = 0;
|
||||
private int screenHeight = 0;
|
||||
private DroidGap app = null;
|
||||
|
||||
public LinearLayoutSoftKeyboardDetect(Context context, int width, int height) {
|
||||
super(context);
|
||||
screenWidth = width;
|
||||
screenHeight = height;
|
||||
app = (DroidGap) context;
|
||||
}
|
||||
|
||||
@Override
|
||||
/**
|
||||
* Start listening to new measurement events. Fire events when the height
|
||||
* gets smaller fire a show keyboard event and when height gets bigger fire
|
||||
* a hide keyboard event.
|
||||
*
|
||||
* Note: We are using app.postMessage so that this is more compatible with the API
|
||||
*
|
||||
* @param widthMeasureSpec
|
||||
* @param heightMeasureSpec
|
||||
*/
|
||||
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
||||
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
|
||||
|
||||
LOG.v(TAG, "We are in our onMeasure method");
|
||||
|
||||
// Get the current height of the visible part of the screen.
|
||||
// This height will not included the status bar.\
|
||||
int width, height;
|
||||
|
||||
height = MeasureSpec.getSize(heightMeasureSpec);
|
||||
width = MeasureSpec.getSize(widthMeasureSpec);
|
||||
LOG.v(TAG, "Old Height = %d", oldHeight);
|
||||
LOG.v(TAG, "Height = %d", height);
|
||||
LOG.v(TAG, "Old Width = %d", oldWidth);
|
||||
LOG.v(TAG, "Width = %d", width);
|
||||
|
||||
// If the oldHeight = 0 then this is the first measure event as the app starts up.
|
||||
// If oldHeight == height then we got a measurement change that doesn't affect us.
|
||||
if (oldHeight == 0 || oldHeight == height) {
|
||||
LOG.d(TAG, "Ignore this event");
|
||||
}
|
||||
// Account for orientation change and ignore this event/Fire orientation change
|
||||
else if(screenHeight == width)
|
||||
{
|
||||
int tmp_var = screenHeight;
|
||||
screenHeight = screenWidth;
|
||||
screenWidth = tmp_var;
|
||||
LOG.v(TAG, "Orientation Change");
|
||||
}
|
||||
// If the height as gotten bigger then we will assume the soft keyboard has
|
||||
// gone away.
|
||||
else if (height > oldHeight) {
|
||||
if(app != null)
|
||||
app.sendJavascript("PhoneGap.fireDocumentEvent('hidekeyboard');");
|
||||
}
|
||||
// If the height as gotten smaller then we will assume the soft keyboard has
|
||||
// been displayed.
|
||||
else if (height < oldHeight) {
|
||||
if(app != null)
|
||||
app.sendJavascript("PhoneGap.fireDocumentEvent('showkeyboard');");
|
||||
}
|
||||
|
||||
// Update the old height for the next event
|
||||
oldHeight = height;
|
||||
oldWidth = width;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,153 +0,0 @@
|
||||
/*
|
||||
Licensed to the Apache Software Foundation (ASF) under one
|
||||
or more contributor license agreements. See the NOTICE file
|
||||
distributed with this work for additional information
|
||||
regarding copyright ownership. The ASF licenses this file
|
||||
to you under the Apache License, Version 2.0 (the
|
||||
"License"); you may not use this file except in compliance
|
||||
with the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing,
|
||||
software distributed under the License is distributed on an
|
||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
KIND, either express or implied. See the License for the
|
||||
specific language governing permissions and limitations
|
||||
under the License.
|
||||
*/
|
||||
package com.phonegap;
|
||||
|
||||
import com.phonegap.api.PhonegapActivity;
|
||||
|
||||
import android.content.Context;
|
||||
import android.location.Location;
|
||||
import android.location.LocationManager;
|
||||
import android.location.LocationListener;
|
||||
import android.os.Bundle;
|
||||
|
||||
public class NetworkListener implements LocationListener {
|
||||
|
||||
private PhonegapActivity mCtx; // PhonegapActivity object
|
||||
|
||||
private LocationManager mLocMan; // Location manager object
|
||||
private GeoListener owner; // Geolistener object (parent)
|
||||
private boolean hasData = false; // Flag indicates if location data is available in cLoc
|
||||
private Location cLoc; // Last recieved location
|
||||
private boolean running = false; // Flag indicates if listener is running
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
* Automatically starts listening.
|
||||
*
|
||||
* @param ctx
|
||||
* @param interval
|
||||
* @param m
|
||||
*/
|
||||
public NetworkListener(PhonegapActivity ctx, int interval, GeoListener m) {
|
||||
this.owner = m;
|
||||
this.mCtx = ctx;
|
||||
this.mLocMan = (LocationManager) this.mCtx.getSystemService(Context.LOCATION_SERVICE);
|
||||
this.running = false;
|
||||
this.start(interval);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get last location.
|
||||
*
|
||||
* @return Location object
|
||||
*/
|
||||
public Location getLocation() {
|
||||
this.cLoc = this.mLocMan.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);
|
||||
if (this.cLoc != null) {
|
||||
this.hasData = true;
|
||||
}
|
||||
return this.cLoc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the provider is disabled by the user.
|
||||
*
|
||||
* @param provider
|
||||
*/
|
||||
public void onProviderDisabled(String provider) {
|
||||
System.out.println("NetworkListener: The provider " + provider + " is disabled");
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the provider is enabled by the user.
|
||||
*
|
||||
* @param provider
|
||||
*/
|
||||
public void onProviderEnabled(String provider) {
|
||||
System.out.println("NetworkListener: The provider "+ provider + " is enabled");
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the provider status changes. This method is called when a
|
||||
* provider is unable to fetch a location or if the provider has recently
|
||||
* become available after a period of unavailability.
|
||||
*
|
||||
* @param provider
|
||||
* @param status
|
||||
* @param extras
|
||||
*/
|
||||
public void onStatusChanged(String provider, int status, Bundle extras) {
|
||||
System.out.println("NetworkListener: The status of the provider " + provider + " has changed");
|
||||
if (status == 0) {
|
||||
System.out.println("NetworkListener: " + provider + " is OUT OF SERVICE");
|
||||
}
|
||||
else if (status == 1) {
|
||||
System.out.println("NetworkListener: " + provider + " is TEMPORARILY_UNAVAILABLE");
|
||||
}
|
||||
else {
|
||||
System.out.println("NetworkListener: " + provider + " is Available");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the location has changed.
|
||||
*
|
||||
* @param location
|
||||
*/
|
||||
public void onLocationChanged(Location location) {
|
||||
System.out.println("NetworkListener: The location has been updated!");
|
||||
this.hasData = true;
|
||||
this.cLoc = location;
|
||||
|
||||
// The GPS is the primary form of Geolocation in PhoneGap.
|
||||
// Only fire the success variables if the GPS is down for some reason.
|
||||
if (!this.owner.mGps.hasLocation()) {
|
||||
this.owner.success(location);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Start requesting location updates.
|
||||
*
|
||||
* @param interval
|
||||
*/
|
||||
public void start(int interval) {
|
||||
if (!this.running) {
|
||||
this.running = true;
|
||||
this.mLocMan.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, interval, 0, this);
|
||||
this.getLocation();
|
||||
|
||||
// If Network provider has data but GPS provider doesn't, then send ours
|
||||
if (this.hasData && !this.owner.mGps.hasLocation()) {
|
||||
this.owner.success(this.cLoc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop receiving location updates.
|
||||
*/
|
||||
public void stop() {
|
||||
if (this.running) {
|
||||
this.mLocMan.removeUpdates(this);
|
||||
}
|
||||
this.running = false;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,248 +0,0 @@
|
||||
/*
|
||||
Licensed to the Apache Software Foundation (ASF) under one
|
||||
or more contributor license agreements. See the NOTICE file
|
||||
distributed with this work for additional information
|
||||
regarding copyright ownership. The ASF licenses this file
|
||||
to you under the Apache License, Version 2.0 (the
|
||||
"License"); you may not use this file except in compliance
|
||||
with the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing,
|
||||
software distributed under the License is distributed on an
|
||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
KIND, either express or implied. See the License for the
|
||||
specific language governing permissions and limitations
|
||||
under the License.
|
||||
*/
|
||||
package com.phonegap;
|
||||
|
||||
import org.json.JSONArray;
|
||||
|
||||
import com.phonegap.api.PhonegapActivity;
|
||||
import com.phonegap.api.Plugin;
|
||||
import com.phonegap.api.PluginResult;
|
||||
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.net.ConnectivityManager;
|
||||
import android.net.NetworkInfo;
|
||||
import android.util.Log;
|
||||
|
||||
public class NetworkManager extends Plugin {
|
||||
|
||||
public static int NOT_REACHABLE = 0;
|
||||
public static int REACHABLE_VIA_CARRIER_DATA_NETWORK = 1;
|
||||
public static int REACHABLE_VIA_WIFI_NETWORK = 2;
|
||||
|
||||
public static final String WIFI = "wifi";
|
||||
public static final String WIMAX = "wimax";
|
||||
// mobile
|
||||
public static final String MOBILE = "mobile";
|
||||
// 2G network types
|
||||
public static final String GSM = "gsm";
|
||||
public static final String GPRS = "gprs";
|
||||
public static final String EDGE = "edge";
|
||||
// 3G network types
|
||||
public static final String CDMA = "cdma";
|
||||
public static final String UMTS = "umts";
|
||||
public static final String HSPA = "hspa";
|
||||
public static final String HSUPA = "hsupa";
|
||||
public static final String HSDPA = "hsdpa";
|
||||
public static final String ONEXRTT = "1xrtt";
|
||||
public static final String EHRPD = "ehrpd";
|
||||
// 4G network types
|
||||
public static final String LTE = "lte";
|
||||
public static final String UMB = "umb";
|
||||
public static final String HSPA_PLUS = "hspa+";
|
||||
// return types
|
||||
public static final String TYPE_UNKNOWN = "unknown";
|
||||
public static final String TYPE_ETHERNET = "ethernet";
|
||||
public static final String TYPE_WIFI = "wifi";
|
||||
public static final String TYPE_2G = "2g";
|
||||
public static final String TYPE_3G = "3g";
|
||||
public static final String TYPE_4G = "4g";
|
||||
public static final String TYPE_NONE = "none";
|
||||
|
||||
private static final String LOG_TAG = "NetworkManager";
|
||||
|
||||
private String connectionCallbackId;
|
||||
|
||||
ConnectivityManager sockMan;
|
||||
BroadcastReceiver receiver;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
public NetworkManager() {
|
||||
this.receiver = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the context of the Command. This can then be used to do things like
|
||||
* get file paths associated with the Activity.
|
||||
*
|
||||
* @param ctx The context of the main Activity.
|
||||
*/
|
||||
public void setContext(PhonegapActivity ctx) {
|
||||
super.setContext(ctx);
|
||||
this.sockMan = (ConnectivityManager) ctx.getSystemService(Context.CONNECTIVITY_SERVICE);
|
||||
this.connectionCallbackId = null;
|
||||
|
||||
// We need to listen to connectivity events to update navigator.connection
|
||||
IntentFilter intentFilter = new IntentFilter() ;
|
||||
intentFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
|
||||
if (this.receiver == null) {
|
||||
this.receiver = new BroadcastReceiver() {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
updateConnectionInfo((NetworkInfo) intent.getParcelableExtra(ConnectivityManager.EXTRA_NETWORK_INFO));
|
||||
}
|
||||
};
|
||||
ctx.registerReceiver(this.receiver, intentFilter);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes the request and returns PluginResult.
|
||||
*
|
||||
* @param action The action to execute.
|
||||
* @param args JSONArry of arguments for the plugin.
|
||||
* @param callbackId The callback id used when calling back into JavaScript.
|
||||
* @return A PluginResult object with a status and message.
|
||||
*/
|
||||
public PluginResult execute(String action, JSONArray args, String callbackId) {
|
||||
PluginResult.Status status = PluginResult.Status.INVALID_ACTION;
|
||||
String result = "Unsupported Operation: " + action;
|
||||
|
||||
if (action.equals("getConnectionInfo")) {
|
||||
this.connectionCallbackId = callbackId;
|
||||
NetworkInfo info = sockMan.getActiveNetworkInfo();
|
||||
PluginResult pluginResult = new PluginResult(PluginResult.Status.OK, this.getConnectionInfo(info));
|
||||
pluginResult.setKeepCallback(true);
|
||||
return pluginResult;
|
||||
}
|
||||
|
||||
return new PluginResult(status, result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Identifies if action to be executed returns a value and should be run synchronously.
|
||||
*
|
||||
* @param action The action to execute
|
||||
* @return T=returns value
|
||||
*/
|
||||
public boolean isSynch(String action) {
|
||||
// All methods take a while, so always use async
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop network receiver.
|
||||
*/
|
||||
public void onDestroy() {
|
||||
if (this.receiver != null) {
|
||||
try {
|
||||
this.ctx.unregisterReceiver(this.receiver);
|
||||
} catch (Exception e) {
|
||||
Log.e(LOG_TAG, "Error unregistering network receiver: " + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// LOCAL METHODS
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
|
||||
/**
|
||||
* Updates the JavaScript side whenever the connection changes
|
||||
*
|
||||
* @param info the current active network info
|
||||
* @return
|
||||
*/
|
||||
private void updateConnectionInfo(NetworkInfo info) {
|
||||
// send update to javascript "navigator.network.connection"
|
||||
sendUpdate(this.getConnectionInfo(info));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the latest network connection information
|
||||
*
|
||||
* @param info the current active network info
|
||||
* @return a JSONObject that represents the network info
|
||||
*/
|
||||
private String getConnectionInfo(NetworkInfo info) {
|
||||
String type = TYPE_NONE;
|
||||
if (info != null) {
|
||||
// If we are not connected to any network set type to none
|
||||
if (!info.isConnected()) {
|
||||
type = TYPE_NONE;
|
||||
}
|
||||
else {
|
||||
type = getType(info);
|
||||
}
|
||||
}
|
||||
return type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new plugin result and send it back to JavaScript
|
||||
*
|
||||
* @param connection the network info to set as navigator.connection
|
||||
*/
|
||||
private void sendUpdate(String type) {
|
||||
PluginResult result = new PluginResult(PluginResult.Status.OK, type);
|
||||
result.setKeepCallback(true);
|
||||
this.success(result, this.connectionCallbackId);
|
||||
|
||||
// Send to all plugins
|
||||
this.ctx.postMessage("networkconnection", type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine the type of connection
|
||||
*
|
||||
* @param info the network info so we can determine connection type.
|
||||
* @return the type of mobile network we are on
|
||||
*/
|
||||
private String getType(NetworkInfo info) {
|
||||
if (info != null) {
|
||||
String type = info.getTypeName();
|
||||
|
||||
if (type.toLowerCase().equals(WIFI)) {
|
||||
return TYPE_WIFI;
|
||||
}
|
||||
else if (type.toLowerCase().equals(MOBILE)) {
|
||||
type = info.getSubtypeName();
|
||||
if (type.toLowerCase().equals(GSM) ||
|
||||
type.toLowerCase().equals(GPRS) ||
|
||||
type.toLowerCase().equals(EDGE)) {
|
||||
return TYPE_2G;
|
||||
}
|
||||
else if (type.toLowerCase().startsWith(CDMA) ||
|
||||
type.toLowerCase().equals(UMTS) ||
|
||||
type.toLowerCase().equals(ONEXRTT) ||
|
||||
type.toLowerCase().equals(EHRPD) ||
|
||||
type.toLowerCase().equals(HSUPA) ||
|
||||
type.toLowerCase().equals(HSDPA) ||
|
||||
type.toLowerCase().equals(HSPA)) {
|
||||
return TYPE_3G;
|
||||
}
|
||||
else if (type.toLowerCase().equals(LTE) ||
|
||||
type.toLowerCase().equals(UMB) ||
|
||||
type.toLowerCase().equals(HSPA_PLUS)) {
|
||||
return TYPE_4G;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
return TYPE_NONE;
|
||||
}
|
||||
return TYPE_UNKNOWN;
|
||||
}
|
||||
}
|
||||
@@ -1,366 +0,0 @@
|
||||
/*
|
||||
Licensed to the Apache Software Foundation (ASF) under one
|
||||
or more contributor license agreements. See the NOTICE file
|
||||
distributed with this work for additional information
|
||||
regarding copyright ownership. The ASF licenses this file
|
||||
to you under the Apache License, Version 2.0 (the
|
||||
"License"); you may not use this file except in compliance
|
||||
with the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing,
|
||||
software distributed under the License is distributed on an
|
||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
KIND, either express or implied. See the License for the
|
||||
specific language governing permissions and limitations
|
||||
under the License.
|
||||
*/
|
||||
package com.phonegap;
|
||||
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
import com.phonegap.api.Plugin;
|
||||
import com.phonegap.api.PhonegapActivity;
|
||||
import com.phonegap.api.PluginResult;
|
||||
import android.app.AlertDialog;
|
||||
import android.app.ProgressDialog;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.media.Ringtone;
|
||||
import android.media.RingtoneManager;
|
||||
import android.net.Uri;
|
||||
import android.os.Vibrator;
|
||||
|
||||
/**
|
||||
* This class provides access to notifications on the device.
|
||||
*/
|
||||
public class Notification extends Plugin {
|
||||
|
||||
public int confirmResult = -1;
|
||||
public ProgressDialog spinnerDialog = null;
|
||||
public ProgressDialog progressDialog = null;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
public Notification() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes the request and returns PluginResult.
|
||||
*
|
||||
* @param action The action to execute.
|
||||
* @param args JSONArry of arguments for the plugin.
|
||||
* @param callbackId The callback id used when calling back into JavaScript.
|
||||
* @return A PluginResult object with a status and message.
|
||||
*/
|
||||
public PluginResult execute(String action, JSONArray args, String callbackId) {
|
||||
PluginResult.Status status = PluginResult.Status.OK;
|
||||
String result = "";
|
||||
|
||||
try {
|
||||
if (action.equals("beep")) {
|
||||
this.beep(args.getLong(0));
|
||||
}
|
||||
else if (action.equals("vibrate")) {
|
||||
this.vibrate(args.getLong(0));
|
||||
}
|
||||
else if (action.equals("alert")) {
|
||||
this.alert(args.getString(0),args.getString(1),args.getString(2), callbackId);
|
||||
PluginResult r = new PluginResult(PluginResult.Status.NO_RESULT);
|
||||
r.setKeepCallback(true);
|
||||
return r;
|
||||
}
|
||||
else if (action.equals("confirm")) {
|
||||
this.confirm(args.getString(0),args.getString(1),args.getString(2), callbackId);
|
||||
PluginResult r = new PluginResult(PluginResult.Status.NO_RESULT);
|
||||
r.setKeepCallback(true);
|
||||
return r;
|
||||
}
|
||||
else if (action.equals("activityStart")) {
|
||||
this.activityStart(args.getString(0),args.getString(1));
|
||||
}
|
||||
else if (action.equals("activityStop")) {
|
||||
this.activityStop();
|
||||
}
|
||||
else if (action.equals("progressStart")) {
|
||||
this.progressStart(args.getString(0),args.getString(1));
|
||||
}
|
||||
else if (action.equals("progressValue")) {
|
||||
this.progressValue(args.getInt(0));
|
||||
}
|
||||
else if (action.equals("progressStop")) {
|
||||
this.progressStop();
|
||||
}
|
||||
return new PluginResult(status, result);
|
||||
} catch (JSONException e) {
|
||||
return new PluginResult(PluginResult.Status.JSON_EXCEPTION);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Identifies if action to be executed returns a value and should be run synchronously.
|
||||
*
|
||||
* @param action The action to execute
|
||||
* @return T=returns value
|
||||
*/
|
||||
public boolean isSynch(String action) {
|
||||
if (action.equals("alert")) {
|
||||
return true;
|
||||
}
|
||||
else if (action.equals("confirm")) {
|
||||
return true;
|
||||
}
|
||||
else if (action.equals("activityStart")) {
|
||||
return true;
|
||||
}
|
||||
else if (action.equals("activityStop")) {
|
||||
return true;
|
||||
}
|
||||
else if (action.equals("progressStart")) {
|
||||
return true;
|
||||
}
|
||||
else if (action.equals("progressValue")) {
|
||||
return true;
|
||||
}
|
||||
else if (action.equals("progressStop")) {
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// LOCAL METHODS
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Beep plays the default notification ringtone.
|
||||
*
|
||||
* @param count Number of times to play notification
|
||||
*/
|
||||
public void beep(long count) {
|
||||
Uri ringtone = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
|
||||
Ringtone notification = RingtoneManager.getRingtone(this.ctx, ringtone);
|
||||
|
||||
// If phone is not set to silent mode
|
||||
if (notification != null) {
|
||||
for (long i = 0; i < count; ++i) {
|
||||
notification.play();
|
||||
long timeout = 5000;
|
||||
while (notification.isPlaying() && (timeout > 0)) {
|
||||
timeout = timeout - 100;
|
||||
try {
|
||||
Thread.sleep(100);
|
||||
} catch (InterruptedException e) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Vibrates the device for the specified amount of time.
|
||||
*
|
||||
* @param time Time to vibrate in ms.
|
||||
*/
|
||||
public void vibrate(long time){
|
||||
// Start the vibration, 0 defaults to half a second.
|
||||
if (time == 0) {
|
||||
time = 500;
|
||||
}
|
||||
Vibrator vibrator = (Vibrator) this.ctx.getSystemService(Context.VIBRATOR_SERVICE);
|
||||
vibrator.vibrate(time);
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds and shows a native Android alert with given Strings
|
||||
* @param message The message the alert should display
|
||||
* @param title The title of the alert
|
||||
* @param buttonLabel The label of the button
|
||||
* @param callbackId The callback id
|
||||
*/
|
||||
public synchronized void alert(final String message, final String title, final String buttonLabel, final String callbackId) {
|
||||
|
||||
final PhonegapActivity ctx = this.ctx;
|
||||
final Notification notification = this;
|
||||
|
||||
Runnable runnable = new Runnable() {
|
||||
public void run() {
|
||||
|
||||
AlertDialog.Builder dlg = new AlertDialog.Builder(ctx);
|
||||
dlg.setMessage(message);
|
||||
dlg.setTitle(title);
|
||||
dlg.setCancelable(false);
|
||||
dlg.setPositiveButton(buttonLabel,
|
||||
new AlertDialog.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
dialog.dismiss();
|
||||
notification.success(new PluginResult(PluginResult.Status.OK, 0), callbackId);
|
||||
}
|
||||
});
|
||||
dlg.create();
|
||||
dlg.show();
|
||||
};
|
||||
};
|
||||
this.ctx.runOnUiThread(runnable);
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds and shows a native Android confirm dialog with given title, message, buttons.
|
||||
* This dialog only shows up to 3 buttons. Any labels after that will be ignored.
|
||||
* The index of the button pressed will be returned to the JavaScript callback identified by callbackId.
|
||||
*
|
||||
* @param message The message the dialog should display
|
||||
* @param title The title of the dialog
|
||||
* @param buttonLabels A comma separated list of button labels (Up to 3 buttons)
|
||||
* @param callbackId The callback id
|
||||
*/
|
||||
public synchronized void confirm(final String message, final String title, String buttonLabels, final String callbackId) {
|
||||
|
||||
final PhonegapActivity ctx = this.ctx;
|
||||
final Notification notification = this;
|
||||
final String[] fButtons = buttonLabels.split(",");
|
||||
|
||||
Runnable runnable = new Runnable() {
|
||||
public void run() {
|
||||
AlertDialog.Builder dlg = new AlertDialog.Builder(ctx);
|
||||
dlg.setMessage(message);
|
||||
dlg.setTitle(title);
|
||||
dlg.setCancelable(false);
|
||||
|
||||
// First button
|
||||
if (fButtons.length > 0) {
|
||||
dlg.setPositiveButton(fButtons[0],
|
||||
new AlertDialog.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
dialog.dismiss();
|
||||
notification.success(new PluginResult(PluginResult.Status.OK, 1), callbackId);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Second button
|
||||
if (fButtons.length > 1) {
|
||||
dlg.setNeutralButton(fButtons[1],
|
||||
new AlertDialog.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
dialog.dismiss();
|
||||
notification.success(new PluginResult(PluginResult.Status.OK, 2), callbackId);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Third button
|
||||
if (fButtons.length > 2) {
|
||||
dlg.setNegativeButton(fButtons[2],
|
||||
new AlertDialog.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
dialog.dismiss();
|
||||
notification.success(new PluginResult(PluginResult.Status.OK, 3), callbackId);
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
dlg.create();
|
||||
dlg.show();
|
||||
};
|
||||
};
|
||||
this.ctx.runOnUiThread(runnable);
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the spinner.
|
||||
*
|
||||
* @param title Title of the dialog
|
||||
* @param message The message of the dialog
|
||||
*/
|
||||
public synchronized void activityStart(final String title, final String message) {
|
||||
if (this.spinnerDialog != null) {
|
||||
this.spinnerDialog.dismiss();
|
||||
this.spinnerDialog = null;
|
||||
}
|
||||
final Notification notification = this;
|
||||
final PhonegapActivity ctx = this.ctx;
|
||||
Runnable runnable = new Runnable() {
|
||||
public void run() {
|
||||
notification.spinnerDialog = ProgressDialog.show(ctx, title , message, true, true,
|
||||
new DialogInterface.OnCancelListener() {
|
||||
public void onCancel(DialogInterface dialog) {
|
||||
notification.spinnerDialog = null;
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
this.ctx.runOnUiThread(runnable);
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop spinner.
|
||||
*/
|
||||
public synchronized void activityStop() {
|
||||
if (this.spinnerDialog != null) {
|
||||
this.spinnerDialog.dismiss();
|
||||
this.spinnerDialog = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the progress dialog.
|
||||
*
|
||||
* @param title Title of the dialog
|
||||
* @param message The message of the dialog
|
||||
*/
|
||||
public synchronized void progressStart(final String title, final String message) {
|
||||
if (this.progressDialog != null) {
|
||||
this.progressDialog.dismiss();
|
||||
this.progressDialog = null;
|
||||
}
|
||||
final Notification notification = this;
|
||||
final PhonegapActivity ctx = this.ctx;
|
||||
Runnable runnable = new Runnable() {
|
||||
public void run() {
|
||||
notification.progressDialog = new ProgressDialog(ctx);
|
||||
notification.progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
|
||||
notification.progressDialog.setTitle(title);
|
||||
notification.progressDialog.setMessage(message);
|
||||
notification.progressDialog.setCancelable(true);
|
||||
notification.progressDialog.setMax(100);
|
||||
notification.progressDialog.setProgress(0);
|
||||
notification.progressDialog.setOnCancelListener(
|
||||
new DialogInterface.OnCancelListener() {
|
||||
public void onCancel(DialogInterface dialog) {
|
||||
notification.progressDialog = null;
|
||||
}
|
||||
});
|
||||
notification.progressDialog.show();
|
||||
}
|
||||
};
|
||||
this.ctx.runOnUiThread(runnable);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set value of progress bar.
|
||||
*
|
||||
* @param value 0-100
|
||||
*/
|
||||
public synchronized void progressValue(int value) {
|
||||
if (this.progressDialog != null) {
|
||||
this.progressDialog.setProgress(value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop progress dialog.
|
||||
*/
|
||||
public synchronized void progressStop() {
|
||||
if (this.progressDialog != null) {
|
||||
this.progressDialog.dismiss();
|
||||
this.progressDialog = null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
package com.phonegap;
|
||||
|
||||
// represents the <preference> element from the W3C config.xml spec
|
||||
// see http://www.w3.org/TR/widgets/#the-preference-element-and-its-attributes
|
||||
public class PreferenceNode {
|
||||
public String name;
|
||||
public String value;
|
||||
public boolean readonly;
|
||||
|
||||
// constructor
|
||||
public PreferenceNode(String name, String value, boolean readonly) {
|
||||
this.name = name;
|
||||
this.value = value;
|
||||
this.readonly = readonly;
|
||||
}
|
||||
}
|
||||
@@ -1,43 +0,0 @@
|
||||
package com.phonegap;
|
||||
|
||||
import java.util.HashSet;
|
||||
|
||||
import com.phonegap.PreferenceNode;
|
||||
|
||||
public class PreferenceSet {
|
||||
private HashSet<PreferenceNode> innerSet;
|
||||
|
||||
public PreferenceSet() {
|
||||
this.innerSet = new HashSet<PreferenceNode>();
|
||||
}
|
||||
|
||||
public void add(PreferenceNode node) {
|
||||
this.innerSet.add(node);
|
||||
}
|
||||
|
||||
public int size() {
|
||||
return this.innerSet.size();
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
this.innerSet.clear();
|
||||
}
|
||||
|
||||
public String pref(String prefName) {
|
||||
for (PreferenceNode n : innerSet)
|
||||
if (prefName.equals(n.name))
|
||||
return n.value;
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public boolean prefMatches(String prefName, String prefValue) {
|
||||
String value = pref(prefName);
|
||||
|
||||
if (value == null) {
|
||||
return false;
|
||||
} else {
|
||||
return value.equals(prefValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
/*
|
||||
Licensed to the Apache Software Foundation (ASF) under one
|
||||
or more contributor license agreements. See the NOTICE file
|
||||
distributed with this work for additional information
|
||||
regarding copyright ownership. The ASF licenses this file
|
||||
to you under the Apache License, Version 2.0 (the
|
||||
"License"); you may not use this file except in compliance
|
||||
with the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing,
|
||||
software distributed under the License is distributed on an
|
||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
KIND, either express or implied. See the License for the
|
||||
specific language governing permissions and limitations
|
||||
under the License.
|
||||
*/
|
||||
package com.phonegap;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.os.Bundle;
|
||||
|
||||
public class StandAlone extends DroidGap {
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
super.loadUrl("file:///android_asset/www/index.html");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,239 +0,0 @@
|
||||
/*
|
||||
Licensed to the Apache Software Foundation (ASF) under one
|
||||
or more contributor license agreements. See the NOTICE file
|
||||
distributed with this work for additional information
|
||||
regarding copyright ownership. The ASF licenses this file
|
||||
to you under the Apache License, Version 2.0 (the
|
||||
"License"); you may not use this file except in compliance
|
||||
with the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing,
|
||||
software distributed under the License is distributed on an
|
||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
KIND, either express or implied. See the License for the
|
||||
specific language governing permissions and limitations
|
||||
under the License.
|
||||
*/
|
||||
package com.phonegap;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
import com.phonegap.api.Plugin;
|
||||
import com.phonegap.api.PluginResult;
|
||||
|
||||
import android.content.Context;
|
||||
import android.database.Cursor;
|
||||
import android.database.sqlite.*;
|
||||
|
||||
/**
|
||||
* This class implements the HTML5 database support to work around a bug for
|
||||
* Android 3.0 devices. It is not used for other versions of Android, since
|
||||
* HTML5 database is built in to the browser.
|
||||
*/
|
||||
public class Storage extends Plugin {
|
||||
|
||||
// Data Definition Language
|
||||
private static final String ALTER = "alter";
|
||||
private static final String CREATE = "create";
|
||||
private static final String DROP = "drop";
|
||||
private static final String TRUNCATE = "truncate";
|
||||
|
||||
SQLiteDatabase myDb = null; // Database object
|
||||
String path = null; // Database path
|
||||
String dbName = null; // Database name
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
public Storage() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes the request and returns PluginResult.
|
||||
*
|
||||
* @param action
|
||||
* The action to execute.
|
||||
* @param args
|
||||
* JSONArry of arguments for the plugin.
|
||||
* @param callbackId
|
||||
* The callback id used when calling back into JavaScript.
|
||||
* @return A PluginResult object with a status and message.
|
||||
*/
|
||||
public PluginResult execute(String action, JSONArray args, String callbackId) {
|
||||
PluginResult.Status status = PluginResult.Status.OK;
|
||||
String result = "";
|
||||
|
||||
try {
|
||||
if (action.equals("openDatabase")) {
|
||||
this.openDatabase(args.getString(0), args.getString(1),
|
||||
args.getString(2), args.getLong(3));
|
||||
} else if (action.equals("executeSql")) {
|
||||
String[] s = null;
|
||||
if (args.isNull(1)) {
|
||||
s = new String[0];
|
||||
} else {
|
||||
JSONArray a = args.getJSONArray(1);
|
||||
int len = a.length();
|
||||
s = new String[len];
|
||||
for (int i = 0; i < len; i++) {
|
||||
s[i] = a.getString(i);
|
||||
}
|
||||
}
|
||||
this.executeSql(args.getString(0), s, args.getString(2));
|
||||
}
|
||||
return new PluginResult(status, result);
|
||||
} catch (JSONException e) {
|
||||
return new PluginResult(PluginResult.Status.JSON_EXCEPTION);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Identifies if action to be executed returns a value and should be run
|
||||
* synchronously.
|
||||
*
|
||||
* @param action
|
||||
* The action to execute
|
||||
* @return T=returns value
|
||||
*/
|
||||
public boolean isSynch(String action) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clean up and close database.
|
||||
*/
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
if (this.myDb != null) {
|
||||
this.myDb.close();
|
||||
this.myDb = null;
|
||||
}
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// LOCAL METHODS
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Open database.
|
||||
*
|
||||
* @param db
|
||||
* The name of the database
|
||||
* @param version
|
||||
* The version
|
||||
* @param display_name
|
||||
* The display name
|
||||
* @param size
|
||||
* The size in bytes
|
||||
*/
|
||||
public void openDatabase(String db, String version, String display_name,
|
||||
long size) {
|
||||
|
||||
// If database is open, then close it
|
||||
if (this.myDb != null) {
|
||||
this.myDb.close();
|
||||
}
|
||||
|
||||
// If no database path, generate from application package
|
||||
if (this.path == null) {
|
||||
this.path = this.ctx.getApplicationContext().getDir("database", Context.MODE_PRIVATE).getPath();
|
||||
}
|
||||
|
||||
this.dbName = this.path + File.pathSeparator + db + ".db";
|
||||
this.myDb = SQLiteDatabase.openOrCreateDatabase(this.dbName, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute SQL statement.
|
||||
*
|
||||
* @param query
|
||||
* The SQL query
|
||||
* @param params
|
||||
* Parameters for the query
|
||||
* @param tx_id
|
||||
* Transaction id
|
||||
*/
|
||||
public void executeSql(String query, String[] params, String tx_id) {
|
||||
try {
|
||||
if (isDDL(query)) {
|
||||
this.myDb.execSQL(query);
|
||||
this.sendJavascript("droiddb.completeQuery('" + tx_id + "', '');");
|
||||
}
|
||||
else {
|
||||
Cursor myCursor = this.myDb.rawQuery(query, params);
|
||||
this.processResults(myCursor, tx_id);
|
||||
myCursor.close();
|
||||
}
|
||||
}
|
||||
catch (SQLiteException ex) {
|
||||
ex.printStackTrace();
|
||||
System.out.println("Storage.executeSql(): Error=" + ex.getMessage());
|
||||
|
||||
// Send error message back to JavaScript
|
||||
this.sendJavascript("droiddb.fail('" + ex.getMessage() + "','" + tx_id + "');");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks to see the the query is a Data Definintion command
|
||||
*
|
||||
* @param query to be executed
|
||||
* @return true if it is a DDL command, false otherwise
|
||||
*/
|
||||
private boolean isDDL(String query) {
|
||||
String cmd = query.toLowerCase();
|
||||
if (cmd.startsWith(DROP) || cmd.startsWith(CREATE) || cmd.startsWith(ALTER) || cmd.startsWith(TRUNCATE)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process query results.
|
||||
*
|
||||
* @param cur
|
||||
* Cursor into query results
|
||||
* @param tx_id
|
||||
* Transaction id
|
||||
*/
|
||||
public void processResults(Cursor cur, String tx_id) {
|
||||
|
||||
String result = "[]";
|
||||
// If query result has rows
|
||||
|
||||
if (cur.moveToFirst()) {
|
||||
JSONArray fullresult = new JSONArray();
|
||||
String key = "";
|
||||
String value = "";
|
||||
int colCount = cur.getColumnCount();
|
||||
|
||||
// Build up JSON result object for each row
|
||||
do {
|
||||
JSONObject row = new JSONObject();
|
||||
try {
|
||||
for (int i = 0; i < colCount; ++i) {
|
||||
key = cur.getColumnName(i);
|
||||
value = cur.getString(i);
|
||||
row.put(key, value);
|
||||
}
|
||||
fullresult.put(row);
|
||||
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
} while (cur.moveToNext());
|
||||
|
||||
result = fullresult.toString();
|
||||
}
|
||||
|
||||
// Let JavaScript know that there are no more rows
|
||||
this.sendJavascript("droiddb.completeQuery('" + tx_id + "', " + result + ");");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,112 +0,0 @@
|
||||
/*
|
||||
Licensed to the Apache Software Foundation (ASF) under one
|
||||
or more contributor license agreements. See the NOTICE file
|
||||
distributed with this work for additional information
|
||||
regarding copyright ownership. The ASF licenses this file
|
||||
to you under the Apache License, Version 2.0 (the
|
||||
"License"); you may not use this file except in compliance
|
||||
with the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing,
|
||||
software distributed under the License is distributed on an
|
||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
KIND, either express or implied. See the License for the
|
||||
specific language governing permissions and limitations
|
||||
under the License.
|
||||
*/
|
||||
package com.phonegap;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.json.JSONArray;
|
||||
|
||||
import com.phonegap.api.PhonegapActivity;
|
||||
import com.phonegap.api.Plugin;
|
||||
import com.phonegap.api.PluginResult;
|
||||
|
||||
import android.hardware.Sensor;
|
||||
import android.hardware.SensorEvent;
|
||||
import android.hardware.SensorEventListener;
|
||||
import android.hardware.SensorManager;
|
||||
import android.content.Context;
|
||||
|
||||
public class TempListener extends Plugin implements SensorEventListener {
|
||||
|
||||
Sensor mSensor;
|
||||
private SensorManager sensorManager;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
public TempListener() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the context of the Command. This can then be used to do things like
|
||||
* get file paths associated with the Activity.
|
||||
*
|
||||
* @param ctx The context of the main Activity.
|
||||
*/
|
||||
public void setContext(PhonegapActivity ctx) {
|
||||
super.setContext(ctx);
|
||||
this.sensorManager = (SensorManager) ctx.getSystemService(Context.SENSOR_SERVICE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes the request and returns PluginResult.
|
||||
*
|
||||
* @param action The action to execute.
|
||||
* @param args JSONArry of arguments for the plugin.
|
||||
* @param callbackId The callback id used when calling back into JavaScript.
|
||||
* @return A PluginResult object with a status and message.
|
||||
*/
|
||||
public PluginResult execute(String action, JSONArray args, String callbackId) {
|
||||
PluginResult.Status status = PluginResult.Status.OK;
|
||||
String result = "";
|
||||
|
||||
if (action.equals("start")) {
|
||||
this.start();
|
||||
}
|
||||
else if (action.equals("stop")) {
|
||||
this.stop();
|
||||
}
|
||||
return new PluginResult(status, result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called by AccelBroker when listener is to be shut down.
|
||||
* Stop listener.
|
||||
*/
|
||||
public void onDestroy() {
|
||||
this.stop();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// LOCAL METHODS
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
public void start() {
|
||||
List<Sensor> list = this.sensorManager.getSensorList(Sensor.TYPE_TEMPERATURE);
|
||||
if (list.size() > 0) {
|
||||
this.mSensor = list.get(0);
|
||||
this.sensorManager.registerListener(this, this.mSensor, SensorManager.SENSOR_DELAY_NORMAL);
|
||||
}
|
||||
}
|
||||
|
||||
public void stop() {
|
||||
this.sensorManager.unregisterListener(this);
|
||||
}
|
||||
|
||||
public void onAccuracyChanged(Sensor sensor, int accuracy) {
|
||||
// TODO Auto-generated method stub
|
||||
}
|
||||
|
||||
public void onSensorChanged(SensorEvent event) {
|
||||
// We want to know what temp this is.
|
||||
float temp = event.values[0];
|
||||
this.sendJavascript("gotTemp(" + temp + ");");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,116 +0,0 @@
|
||||
/*
|
||||
Licensed to the Apache Software Foundation (ASF) under one
|
||||
or more contributor license agreements. See the NOTICE file
|
||||
distributed with this work for additional information
|
||||
regarding copyright ownership. The ASF licenses this file
|
||||
to you under the Apache License, Version 2.0 (the
|
||||
"License"); you may not use this file except in compliance
|
||||
with the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing,
|
||||
software distributed under the License is distributed on an
|
||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
KIND, either express or implied. See the License for the
|
||||
specific language governing permissions and limitations
|
||||
under the License.
|
||||
*/
|
||||
package com.phonegap.api;
|
||||
|
||||
import org.json.JSONArray;
|
||||
import android.content.Intent;
|
||||
import android.webkit.WebView;
|
||||
|
||||
/**
|
||||
* Plugin interface must be implemented by any plugin classes.
|
||||
*
|
||||
* The execute method is called by the PluginManager.
|
||||
*/
|
||||
public interface IPlugin {
|
||||
|
||||
/**
|
||||
* Executes the request and returns PluginResult.
|
||||
*
|
||||
* @param action The action to execute.
|
||||
* @param args JSONArry of arguments for the plugin.
|
||||
* @param callbackId The callback id used when calling back into JavaScript.
|
||||
* @return A PluginResult object with a status and message.
|
||||
*/
|
||||
PluginResult execute(String action, JSONArray args, String callbackId);
|
||||
|
||||
/**
|
||||
* Identifies if action to be executed returns a value and should be run synchronously.
|
||||
*
|
||||
* @param action The action to execute
|
||||
* @return T=returns value
|
||||
*/
|
||||
public boolean isSynch(String action);
|
||||
|
||||
/**
|
||||
* Sets the context of the Plugin. This can then be used to do things like
|
||||
* get file paths associated with the Activity.
|
||||
*
|
||||
* @param ctx The context of the main Activity.
|
||||
*/
|
||||
void setContext(PhonegapActivity ctx);
|
||||
|
||||
/**
|
||||
* Sets the main View of the application, this is the WebView within which
|
||||
* a PhoneGap app runs.
|
||||
*
|
||||
* @param webView The PhoneGap WebView
|
||||
*/
|
||||
void setView(WebView webView);
|
||||
|
||||
/**
|
||||
* Called when the system is about to start resuming a previous activity.
|
||||
*
|
||||
* @param multitasking Flag indicating if multitasking is turned on for app
|
||||
*/
|
||||
void onPause(boolean multitasking);
|
||||
|
||||
/**
|
||||
* Called when the activity will start interacting with the user.
|
||||
*
|
||||
* @param multitasking Flag indicating if multitasking is turned on for app
|
||||
*/
|
||||
void onResume(boolean multitasking);
|
||||
|
||||
/**
|
||||
* Called when the activity receives a new intent.
|
||||
*/
|
||||
void onNewIntent(Intent intent);
|
||||
|
||||
/**
|
||||
* The final call you receive before your activity is destroyed.
|
||||
*/
|
||||
void onDestroy();
|
||||
|
||||
/**
|
||||
* Called when a message is sent to plugin.
|
||||
*
|
||||
* @param id The message id
|
||||
* @param data The message data
|
||||
*/
|
||||
public void onMessage(String id, Object data);
|
||||
|
||||
/**
|
||||
* Called when an activity you launched exits, giving you the requestCode you started it with,
|
||||
* the resultCode it returned, and any additional data from it.
|
||||
*
|
||||
* @param requestCode The request code originally supplied to startActivityForResult(),
|
||||
* allowing you to identify who this result came from.
|
||||
* @param resultCode The integer result code returned by the child activity through its setResult().
|
||||
* @param data An Intent, which can return result data to the caller (various data can be attached to Intent "extras").
|
||||
*/
|
||||
void onActivityResult(int requestCode, int resultCode, Intent intent);
|
||||
|
||||
/**
|
||||
* By specifying a <url-filter> in plugins.xml you can map a URL (using startsWith atm) to this method.
|
||||
*
|
||||
* @param url The URL that is trying to be loaded in the PhoneGap webview.
|
||||
* @return Return true to prevent the URL from loading. Default is false.
|
||||
*/
|
||||
boolean onOverrideUrlLoading(String url);
|
||||
}
|
||||
@@ -1,234 +0,0 @@
|
||||
/*
|
||||
Licensed to the Apache Software Foundation (ASF) under one
|
||||
or more contributor license agreements. See the NOTICE file
|
||||
distributed with this work for additional information
|
||||
regarding copyright ownership. The ASF licenses this file
|
||||
to you under the Apache License, Version 2.0 (the
|
||||
"License"); you may not use this file except in compliance
|
||||
with the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing,
|
||||
software distributed under the License is distributed on an
|
||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
KIND, either express or implied. See the License for the
|
||||
specific language governing permissions and limitations
|
||||
under the License.
|
||||
*/
|
||||
package com.phonegap.api;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
/**
|
||||
* Log to Android logging system.
|
||||
*
|
||||
* Log message can be a string or a printf formatted string with arguments.
|
||||
* See http://developer.android.com/reference/java/util/Formatter.html
|
||||
*/
|
||||
public class LOG {
|
||||
|
||||
public static final int VERBOSE = Log.VERBOSE;
|
||||
public static final int DEBUG = Log.DEBUG;
|
||||
public static final int INFO = Log.INFO;
|
||||
public static final int WARN = Log.WARN;
|
||||
public static final int ERROR = Log.ERROR;
|
||||
|
||||
// Current log level
|
||||
public static int LOGLEVEL = Log.ERROR;
|
||||
|
||||
/**
|
||||
* Set the current log level.
|
||||
*
|
||||
* @param logLevel
|
||||
*/
|
||||
public static void setLogLevel(int logLevel) {
|
||||
LOGLEVEL = logLevel;
|
||||
Log.i("PhoneGapLog", "Changing log level to " + logLevel);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the current log level.
|
||||
*
|
||||
* @param logLevel
|
||||
*/
|
||||
public static void setLogLevel(String logLevel) {
|
||||
if ("VERBOSE".equals(logLevel)) LOGLEVEL = VERBOSE;
|
||||
else if ("DEBUG".equals(logLevel)) LOGLEVEL = DEBUG;
|
||||
else if ("INFO".equals(logLevel)) LOGLEVEL = INFO;
|
||||
else if ("WARN".equals(logLevel)) LOGLEVEL = WARN;
|
||||
else if ("ERROR".equals(logLevel)) LOGLEVEL = ERROR;
|
||||
Log.i("PhoneGapLog", "Changing log level to " + logLevel + "(" + LOGLEVEL + ")");
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if log level will be logged
|
||||
*
|
||||
* @param logLevel
|
||||
* @return
|
||||
*/
|
||||
public static boolean isLoggable(int logLevel) {
|
||||
return (logLevel >= LOGLEVEL);
|
||||
}
|
||||
|
||||
/**
|
||||
* Verbose log message.
|
||||
*
|
||||
* @param tag
|
||||
* @param s
|
||||
*/
|
||||
public static void v(String tag, String s) {
|
||||
if (LOG.VERBOSE >= LOGLEVEL) Log.v(tag, s);
|
||||
}
|
||||
|
||||
/**
|
||||
* Debug log message.
|
||||
*
|
||||
* @param tag
|
||||
* @param s
|
||||
*/
|
||||
public static void d(String tag, String s) {
|
||||
if (LOG.DEBUG >= LOGLEVEL) Log.d(tag, s);
|
||||
}
|
||||
|
||||
/**
|
||||
* Info log message.
|
||||
*
|
||||
* @param tag
|
||||
* @param s
|
||||
*/
|
||||
public static void i(String tag, String s) {
|
||||
if (LOG.INFO >= LOGLEVEL) Log.i(tag, s);
|
||||
}
|
||||
|
||||
/**
|
||||
* Warning log message.
|
||||
*
|
||||
* @param tag
|
||||
* @param s
|
||||
*/
|
||||
public static void w(String tag, String s) {
|
||||
if (LOG.WARN >= LOGLEVEL) Log.w(tag, s);
|
||||
}
|
||||
|
||||
/**
|
||||
* Error log message.
|
||||
*
|
||||
* @param tag
|
||||
* @param s
|
||||
*/
|
||||
public static void e(String tag, String s) {
|
||||
if (LOG.ERROR >= LOGLEVEL) Log.e(tag, s);
|
||||
}
|
||||
|
||||
/**
|
||||
* Verbose log message.
|
||||
*
|
||||
* @param tag
|
||||
* @param s
|
||||
* @param e
|
||||
*/
|
||||
public static void v(String tag, String s, Throwable e) {
|
||||
if (LOG.VERBOSE >= LOGLEVEL) Log.v(tag, s, e);
|
||||
}
|
||||
|
||||
/**
|
||||
* Debug log message.
|
||||
*
|
||||
* @param tag
|
||||
* @param s
|
||||
* @param e
|
||||
*/
|
||||
public static void d(String tag, String s, Throwable e) {
|
||||
if (LOG.DEBUG >= LOGLEVEL) Log.d(tag, s, e);
|
||||
}
|
||||
|
||||
/**
|
||||
* Info log message.
|
||||
*
|
||||
* @param tag
|
||||
* @param s
|
||||
* @param e
|
||||
*/
|
||||
public static void i(String tag, String s, Throwable e) {
|
||||
if (LOG.INFO >= LOGLEVEL) Log.i(tag, s, e);
|
||||
}
|
||||
|
||||
/**
|
||||
* Warning log message.
|
||||
*
|
||||
* @param tag
|
||||
* @param s
|
||||
* @param e
|
||||
*/
|
||||
public static void w(String tag, String s, Throwable e) {
|
||||
if (LOG.WARN >= LOGLEVEL) Log.w(tag, s, e);
|
||||
}
|
||||
|
||||
/**
|
||||
* Error log message.
|
||||
*
|
||||
* @param tag
|
||||
* @param s
|
||||
* @param e
|
||||
*/
|
||||
public static void e(String tag, String s, Throwable e) {
|
||||
if (LOG.ERROR >= LOGLEVEL) Log.e(tag, s, e);
|
||||
}
|
||||
|
||||
/**
|
||||
* Verbose log message with printf formatting.
|
||||
*
|
||||
* @param tag
|
||||
* @param s
|
||||
* @param args
|
||||
*/
|
||||
public static void v(String tag, String s, Object... args) {
|
||||
if (LOG.VERBOSE >= LOGLEVEL) Log.v(tag, String.format(s, args));
|
||||
}
|
||||
|
||||
/**
|
||||
* Debug log message with printf formatting.
|
||||
*
|
||||
* @param tag
|
||||
* @param s
|
||||
* @param args
|
||||
*/
|
||||
public static void d(String tag, String s, Object... args) {
|
||||
if (LOG.DEBUG >= LOGLEVEL) Log.d(tag, String.format(s, args));
|
||||
}
|
||||
|
||||
/**
|
||||
* Info log message with printf formatting.
|
||||
*
|
||||
* @param tag
|
||||
* @param s
|
||||
* @param args
|
||||
*/
|
||||
public static void i(String tag, String s, Object... args) {
|
||||
if (LOG.INFO >= LOGLEVEL) Log.i(tag, String.format(s, args));
|
||||
}
|
||||
|
||||
/**
|
||||
* Warning log message with printf formatting.
|
||||
*
|
||||
* @param tag
|
||||
* @param s
|
||||
* @param args
|
||||
*/
|
||||
public static void w(String tag, String s, Object... args) {
|
||||
if (LOG.WARN >= LOGLEVEL) Log.w(tag, String.format(s, args));
|
||||
}
|
||||
|
||||
/**
|
||||
* Error log message with printf formatting.
|
||||
*
|
||||
* @param tag
|
||||
* @param s
|
||||
* @param args
|
||||
*/
|
||||
public static void e(String tag, String s, Object... args) {
|
||||
if (LOG.ERROR >= LOGLEVEL) Log.e(tag, String.format(s, args));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,80 +0,0 @@
|
||||
/*
|
||||
Licensed to the Apache Software Foundation (ASF) under one
|
||||
or more contributor license agreements. See the NOTICE file
|
||||
distributed with this work for additional information
|
||||
regarding copyright ownership. The ASF licenses this file
|
||||
to you under the Apache License, Version 2.0 (the
|
||||
"License"); you may not use this file except in compliance
|
||||
with the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing,
|
||||
software distributed under the License is distributed on an
|
||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
KIND, either express or implied. See the License for the
|
||||
specific language governing permissions and limitations
|
||||
under the License.
|
||||
*/
|
||||
package com.phonegap.api;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Intent;
|
||||
|
||||
/**
|
||||
* The Phonegap activity abstract class that is extended by DroidGap.
|
||||
* It is used to isolate plugin development, and remove dependency on entire Phonegap library.
|
||||
*/
|
||||
public abstract class PhonegapActivity extends Activity {
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
* Add services to res/xml/plugins.xml instead.
|
||||
*
|
||||
* Add a class that implements a service.
|
||||
*
|
||||
* @param serviceType
|
||||
* @param className
|
||||
*/
|
||||
@Deprecated
|
||||
abstract public void addService(String serviceType, String className);
|
||||
|
||||
/**
|
||||
* Send JavaScript statement back to JavaScript.
|
||||
*
|
||||
* @param message
|
||||
*/
|
||||
abstract public void sendJavascript(String statement);
|
||||
|
||||
/**
|
||||
* Launch an activity for which you would like a result when it finished. When this activity exits,
|
||||
* your onActivityResult() method will be called.
|
||||
*
|
||||
* @param command The command object
|
||||
* @param intent The intent to start
|
||||
* @param requestCode The request code that is passed to callback to identify the activity
|
||||
*/
|
||||
abstract public void startActivityForResult(IPlugin command, Intent intent, int requestCode);
|
||||
|
||||
/**
|
||||
* Set the plugin to be called when a sub-activity exits.
|
||||
*
|
||||
* @param plugin The plugin on which onActivityResult is to be called
|
||||
*/
|
||||
abstract public void setActivityResultCallback(IPlugin plugin);
|
||||
|
||||
/**
|
||||
* Load the specified URL in the PhoneGap webview.
|
||||
*
|
||||
* @param url The URL to load.
|
||||
*/
|
||||
abstract public void loadUrl(String url);
|
||||
|
||||
/**
|
||||
* Send a message to all plugins.
|
||||
*
|
||||
* @param id The message id
|
||||
* @param data The message data
|
||||
*/
|
||||
abstract public void postMessage(String id, Object data);
|
||||
}
|
||||
@@ -1,210 +0,0 @@
|
||||
/*
|
||||
Licensed to the Apache Software Foundation (ASF) under one
|
||||
or more contributor license agreements. See the NOTICE file
|
||||
distributed with this work for additional information
|
||||
regarding copyright ownership. The ASF licenses this file
|
||||
to you under the Apache License, Version 2.0 (the
|
||||
"License"); you may not use this file except in compliance
|
||||
with the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing,
|
||||
software distributed under the License is distributed on an
|
||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
KIND, either express or implied. See the License for the
|
||||
specific language governing permissions and limitations
|
||||
under the License.
|
||||
*/
|
||||
package com.phonegap.api;
|
||||
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.webkit.WebView;
|
||||
|
||||
/**
|
||||
* Plugin interface must be implemented by any plugin classes.
|
||||
*
|
||||
* The execute method is called by the PluginManager.
|
||||
*/
|
||||
public abstract class Plugin implements IPlugin {
|
||||
|
||||
public String id;
|
||||
public WebView webView; // WebView object
|
||||
public PhonegapActivity ctx; // PhonegapActivity object
|
||||
|
||||
/**
|
||||
* Executes the request and returns PluginResult.
|
||||
*
|
||||
* @param action The action to execute.
|
||||
* @param args JSONArry of arguments for the plugin.
|
||||
* @param callbackId The callback id used when calling back into JavaScript.
|
||||
* @return A PluginResult object with a status and message.
|
||||
*/
|
||||
public abstract PluginResult execute(String action, JSONArray args, String callbackId);
|
||||
|
||||
/**
|
||||
* Identifies if action to be executed returns a value and should be run synchronously.
|
||||
*
|
||||
* @param action The action to execute
|
||||
* @return T=returns value
|
||||
*/
|
||||
public boolean isSynch(String action) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the context of the Plugin. This can then be used to do things like
|
||||
* get file paths associated with the Activity.
|
||||
*
|
||||
* @param ctx The context of the main Activity.
|
||||
*/
|
||||
public void setContext(PhonegapActivity ctx) {
|
||||
this.ctx = ctx;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the main View of the application, this is the WebView within which
|
||||
* a PhoneGap app runs.
|
||||
*
|
||||
* @param webView The PhoneGap WebView
|
||||
*/
|
||||
public void setView(WebView webView) {
|
||||
this.webView = webView;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the system is about to start resuming a previous activity.
|
||||
*
|
||||
* @param multitasking Flag indicating if multitasking is turned on for app
|
||||
*/
|
||||
public void onPause(boolean multitasking) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the activity will start interacting with the user.
|
||||
*
|
||||
* @param multitasking Flag indicating if multitasking is turned on for app
|
||||
*/
|
||||
public void onResume(boolean multitasking) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the activity receives a new intent.
|
||||
*/
|
||||
public void onNewIntent(Intent intent) {
|
||||
}
|
||||
|
||||
/**
|
||||
* The final call you receive before your activity is destroyed.
|
||||
*/
|
||||
public void onDestroy() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when a message is sent to plugin.
|
||||
*
|
||||
* @param id The message id
|
||||
* @param data The message data
|
||||
*/
|
||||
public void onMessage(String id, Object data) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when an activity you launched exits, giving you the requestCode you started it with,
|
||||
* the resultCode it returned, and any additional data from it.
|
||||
*
|
||||
* @param requestCode The request code originally supplied to startActivityForResult(),
|
||||
* allowing you to identify who this result came from.
|
||||
* @param resultCode The integer result code returned by the child activity through its setResult().
|
||||
* @param data An Intent, which can return result data to the caller (various data can be attached to Intent "extras").
|
||||
*/
|
||||
public void onActivityResult(int requestCode, int resultCode, Intent intent) {
|
||||
}
|
||||
|
||||
/**
|
||||
* By specifying a <url-filter> in plugins.xml you can map a URL (using startsWith atm) to this method.
|
||||
*
|
||||
* @param url The URL that is trying to be loaded in the PhoneGap webview.
|
||||
* @return Return true to prevent the URL from loading. Default is false.
|
||||
*/
|
||||
public boolean onOverrideUrlLoading(String url) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Send generic JavaScript statement back to JavaScript.
|
||||
* success(...) and error(...) should be used instead where possible.
|
||||
*
|
||||
* @param statement
|
||||
*/
|
||||
public void sendJavascript(String statement) {
|
||||
this.ctx.sendJavascript(statement);
|
||||
}
|
||||
|
||||
/**
|
||||
* Call the JavaScript success callback for this plugin.
|
||||
*
|
||||
* This can be used if the execute code for the plugin is asynchronous meaning
|
||||
* that execute should return null and the callback from the async operation can
|
||||
* call success(...) or error(...)
|
||||
*
|
||||
* @param pluginResult The result to return.
|
||||
* @param callbackId The callback id used when calling back into JavaScript.
|
||||
*/
|
||||
public void success(PluginResult pluginResult, String callbackId) {
|
||||
this.ctx.sendJavascript(pluginResult.toSuccessCallbackString(callbackId));
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper for success callbacks that just returns the Status.OK by default
|
||||
*
|
||||
* @param message The message to add to the success result.
|
||||
* @param callbackId The callback id used when calling back into JavaScript.
|
||||
*/
|
||||
public void success(JSONObject message, String callbackId) {
|
||||
this.ctx.sendJavascript(new PluginResult(PluginResult.Status.OK, message).toSuccessCallbackString(callbackId));
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper for success callbacks that just returns the Status.OK by default
|
||||
*
|
||||
* @param message The message to add to the success result.
|
||||
* @param callbackId The callback id used when calling back into JavaScript.
|
||||
*/
|
||||
public void success(String message, String callbackId) {
|
||||
this.ctx.sendJavascript(new PluginResult(PluginResult.Status.OK, message).toSuccessCallbackString(callbackId));
|
||||
}
|
||||
|
||||
/**
|
||||
* Call the JavaScript error callback for this plugin.
|
||||
*
|
||||
* @param pluginResult The result to return.
|
||||
* @param callbackId The callback id used when calling back into JavaScript.
|
||||
*/
|
||||
public void error(PluginResult pluginResult, String callbackId) {
|
||||
this.ctx.sendJavascript(pluginResult.toErrorCallbackString(callbackId));
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper for error callbacks that just returns the Status.ERROR by default
|
||||
*
|
||||
* @param message The message to add to the error result.
|
||||
* @param callbackId The callback id used when calling back into JavaScript.
|
||||
*/
|
||||
public void error(JSONObject message, String callbackId) {
|
||||
this.ctx.sendJavascript(new PluginResult(PluginResult.Status.ERROR, message).toErrorCallbackString(callbackId));
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper for error callbacks that just returns the Status.ERROR by default
|
||||
*
|
||||
* @param message The message to add to the error result.
|
||||
* @param callbackId The callback id used when calling back into JavaScript.
|
||||
*/
|
||||
public void error(String message, String callbackId) {
|
||||
this.ctx.sendJavascript(new PluginResult(PluginResult.Status.ERROR, message).toErrorCallbackString(callbackId));
|
||||
}
|
||||
}
|
||||
@@ -1,359 +0,0 @@
|
||||
/*
|
||||
Licensed to the Apache Software Foundation (ASF) under one
|
||||
or more contributor license agreements. See the NOTICE file
|
||||
distributed with this work for additional information
|
||||
regarding copyright ownership. The ASF licenses this file
|
||||
to you under the Apache License, Version 2.0 (the
|
||||
"License"); you may not use this file except in compliance
|
||||
with the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing,
|
||||
software distributed under the License is distributed on an
|
||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
KIND, either express or implied. See the License for the
|
||||
specific language governing permissions and limitations
|
||||
under the License.
|
||||
*/
|
||||
package com.phonegap.api;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
import org.xmlpull.v1.XmlPullParserException;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.content.res.XmlResourceParser;
|
||||
import android.util.Log;
|
||||
import android.webkit.WebView;
|
||||
|
||||
/**
|
||||
* PluginManager is exposed to JavaScript in the PhoneGap WebView.
|
||||
*
|
||||
* Calling native plugin code can be done by calling PluginManager.exec(...)
|
||||
* from JavaScript.
|
||||
*/
|
||||
public final class PluginManager {
|
||||
|
||||
private HashMap<String, IPlugin> plugins = new HashMap<String,IPlugin>();
|
||||
private HashMap<String, String> services = new HashMap<String,String>();
|
||||
|
||||
private final PhonegapActivity ctx;
|
||||
private final WebView app;
|
||||
|
||||
// Map URL schemes like foo: to plugins that want to handle those schemes
|
||||
// This would allow how all URLs are handled to be offloaded to a plugin
|
||||
protected HashMap<String, String> urlMap = new HashMap<String,String>();
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param app
|
||||
* @param ctx
|
||||
*/
|
||||
public PluginManager(WebView app, PhonegapActivity ctx) {
|
||||
this.ctx = ctx;
|
||||
this.app = app;
|
||||
this.loadPlugins();
|
||||
}
|
||||
|
||||
/**
|
||||
* Re-init when loading a new HTML page into webview.
|
||||
*/
|
||||
public void reinit() {
|
||||
|
||||
// Stop plugins on current HTML page and discard
|
||||
this.onPause(false);
|
||||
this.onDestroy();
|
||||
this.plugins = new HashMap<String, IPlugin>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Load plugins from res/xml/plugins.xml
|
||||
*/
|
||||
public void loadPlugins() {
|
||||
int id = ctx.getResources().getIdentifier("plugins", "xml", ctx.getPackageName());
|
||||
if (id == 0) { pluginConfigurationMissing(); }
|
||||
XmlResourceParser xml = ctx.getResources().getXml(id);
|
||||
int eventType = -1;
|
||||
String pluginClass = "", pluginName = "";
|
||||
while (eventType != XmlResourceParser.END_DOCUMENT) {
|
||||
if (eventType == XmlResourceParser.START_TAG) {
|
||||
String strNode = xml.getName();
|
||||
if (strNode.equals("plugin")) {
|
||||
pluginClass = xml.getAttributeValue(null, "value");
|
||||
pluginName = xml.getAttributeValue(null, "name");
|
||||
//System.out.println("Plugin: "+name+" => "+value);
|
||||
this.addService(pluginName, pluginClass);
|
||||
|
||||
// Create plugin at load time if attribute "onload"
|
||||
if ("true".equals(xml.getAttributeValue(null, "onload"))) {
|
||||
this.getPlugin(pluginName);
|
||||
}
|
||||
} else if (strNode.equals("url-filter")) {
|
||||
this.urlMap.put(xml.getAttributeValue(null, "value"), pluginName);
|
||||
}
|
||||
}
|
||||
try {
|
||||
eventType = xml.next();
|
||||
} catch (XmlPullParserException e) {
|
||||
e.printStackTrace();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Receives a request for execution and fulfills it by finding the appropriate
|
||||
* Java class and calling it's execute method.
|
||||
*
|
||||
* PluginManager.exec can be used either synchronously or async. In either case, a JSON encoded
|
||||
* string is returned that will indicate if any errors have occurred when trying to find
|
||||
* or execute the class denoted by the clazz argument.
|
||||
*
|
||||
* @param service String containing the service to run
|
||||
* @param action String containt the action that the class is supposed to perform. This is
|
||||
* passed to the plugin execute method and it is up to the plugin developer
|
||||
* how to deal with it.
|
||||
* @param callbackId String containing the id of the callback that is execute in JavaScript if
|
||||
* this is an async plugin call.
|
||||
* @param args An Array literal string containing any arguments needed in the
|
||||
* plugin execute method.
|
||||
* @param async Boolean indicating whether the calling JavaScript code is expecting an
|
||||
* immediate return value. If true, either PhoneGap.callbackSuccess(...) or
|
||||
* PhoneGap.callbackError(...) is called once the plugin code has executed.
|
||||
*
|
||||
* @return JSON encoded string with a response message and status.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public String exec(final String service, final String action, final String callbackId, final String jsonArgs, final boolean async) {
|
||||
PluginResult cr = null;
|
||||
boolean runAsync = async;
|
||||
try {
|
||||
final JSONArray args = new JSONArray(jsonArgs);
|
||||
final IPlugin plugin = this.getPlugin(service);
|
||||
final PhonegapActivity ctx = this.ctx;
|
||||
if (plugin != null) {
|
||||
runAsync = async && !plugin.isSynch(action);
|
||||
if (runAsync) {
|
||||
// Run this on a different thread so that this one can return back to JS
|
||||
Thread thread = new Thread(new Runnable() {
|
||||
public void run() {
|
||||
try {
|
||||
// Call execute on the plugin so that it can do it's thing
|
||||
PluginResult cr = plugin.execute(action, args, callbackId);
|
||||
int status = cr.getStatus();
|
||||
|
||||
// If no result to be sent and keeping callback, then no need to sent back to JavaScript
|
||||
if ((status == PluginResult.Status.NO_RESULT.ordinal()) && cr.getKeepCallback()) {
|
||||
}
|
||||
|
||||
// Check the success (OK, NO_RESULT & !KEEP_CALLBACK)
|
||||
else if ((status == PluginResult.Status.OK.ordinal()) || (status == PluginResult.Status.NO_RESULT.ordinal())) {
|
||||
ctx.sendJavascript(cr.toSuccessCallbackString(callbackId));
|
||||
}
|
||||
|
||||
// If error
|
||||
else {
|
||||
ctx.sendJavascript(cr.toErrorCallbackString(callbackId));
|
||||
}
|
||||
} catch (Exception e) {
|
||||
PluginResult cr = new PluginResult(PluginResult.Status.ERROR, e.getMessage());
|
||||
ctx.sendJavascript(cr.toErrorCallbackString(callbackId));
|
||||
}
|
||||
}
|
||||
});
|
||||
thread.start();
|
||||
return "";
|
||||
} else {
|
||||
// Call execute on the plugin so that it can do it's thing
|
||||
cr = plugin.execute(action, args, callbackId);
|
||||
|
||||
// If no result to be sent and keeping callback, then no need to sent back to JavaScript
|
||||
if ((cr.getStatus() == PluginResult.Status.NO_RESULT.ordinal()) && cr.getKeepCallback()) {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (JSONException e) {
|
||||
System.out.println("ERROR: "+e.toString());
|
||||
cr = new PluginResult(PluginResult.Status.JSON_EXCEPTION);
|
||||
}
|
||||
// if async we have already returned at this point unless there was an error...
|
||||
if (runAsync) {
|
||||
if (cr == null) {
|
||||
cr = new PluginResult(PluginResult.Status.CLASS_NOT_FOUND_EXCEPTION);
|
||||
}
|
||||
ctx.sendJavascript(cr.toErrorCallbackString(callbackId));
|
||||
}
|
||||
return ( cr != null ? cr.getJSONString() : "{ status: 0, message: 'all good' }" );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the class.
|
||||
*
|
||||
* @param clazz
|
||||
* @return
|
||||
* @throws ClassNotFoundException
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
private Class getClassByName(final String clazz) throws ClassNotFoundException {
|
||||
Class c = null;
|
||||
if (clazz != null) {
|
||||
c = Class.forName(clazz);
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the interfaces that a class implements and see if it implements the
|
||||
* com.phonegap.api.Plugin interface.
|
||||
*
|
||||
* @param c The class to check the interfaces of.
|
||||
* @return Boolean indicating if the class implements com.phonegap.api.Plugin
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
private boolean isPhoneGapPlugin(Class c) {
|
||||
if (c != null) {
|
||||
return com.phonegap.api.Plugin.class.isAssignableFrom(c) || com.phonegap.api.IPlugin.class.isAssignableFrom(c);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add plugin to be loaded and cached. This creates an instance of the plugin.
|
||||
* If plugin is already created, then just return it.
|
||||
*
|
||||
* @param className The class to load
|
||||
* @param clazz The class object (must be a class object of the className)
|
||||
* @param callbackId The callback id to use when calling back into JavaScript
|
||||
* @return The plugin
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
private IPlugin addPlugin(String pluginName, String className) {
|
||||
try {
|
||||
Class c = getClassByName(className);
|
||||
if (isPhoneGapPlugin(c)) {
|
||||
IPlugin plugin = (IPlugin)c.newInstance();
|
||||
this.plugins.put(className, plugin);
|
||||
plugin.setContext(this.ctx);
|
||||
plugin.setView(this.app);
|
||||
return plugin;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
System.out.println("Error adding plugin "+className+".");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the loaded plugin.
|
||||
*
|
||||
* If the plugin is not already loaded then load it.
|
||||
*
|
||||
* @param className The class of the loaded plugin.
|
||||
* @return
|
||||
*/
|
||||
private IPlugin getPlugin(String pluginName) {
|
||||
String className = this.services.get(pluginName);
|
||||
if (this.plugins.containsKey(className)) {
|
||||
return this.plugins.get(className);
|
||||
} else {
|
||||
return this.addPlugin(pluginName, className);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a class that implements a service.
|
||||
* This does not create the class instance. It just maps service name to class name.
|
||||
*
|
||||
* @param serviceType
|
||||
* @param className
|
||||
*/
|
||||
public void addService(String serviceType, String className) {
|
||||
this.services.put(serviceType, className);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the system is about to start resuming a previous activity.
|
||||
*
|
||||
* @param multitasking Flag indicating if multitasking is turned on for app
|
||||
*/
|
||||
public void onPause(boolean multitasking) {
|
||||
for (IPlugin plugin : this.plugins.values()) {
|
||||
plugin.onPause(multitasking);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the activity will start interacting with the user.
|
||||
*
|
||||
* @param multitasking Flag indicating if multitasking is turned on for app
|
||||
*/
|
||||
public void onResume(boolean multitasking) {
|
||||
for (IPlugin plugin : this.plugins.values()) {
|
||||
plugin.onResume(multitasking);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The final call you receive before your activity is destroyed.
|
||||
*/
|
||||
public void onDestroy() {
|
||||
for (IPlugin plugin : this.plugins.values()) {
|
||||
plugin.onDestroy();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a message to all plugins.
|
||||
*
|
||||
* @param id The message id
|
||||
* @param data The message data
|
||||
*/
|
||||
public void postMessage(String id, Object data) {
|
||||
for (IPlugin plugin : this.plugins.values()) {
|
||||
plugin.onMessage(id, data);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the activity receives a new intent.
|
||||
*/
|
||||
public void onNewIntent(Intent intent) {
|
||||
for (IPlugin plugin : this.plugins.values()) {
|
||||
plugin.onNewIntent(intent);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the URL of the webview changes.
|
||||
*
|
||||
* @param url The URL that is being changed to.
|
||||
* @return Return false to allow the URL to load, return true to prevent the URL from loading.
|
||||
*/
|
||||
public boolean onOverrideUrlLoading(String url) {
|
||||
Iterator<Entry<String, String>> it = this.urlMap.entrySet().iterator();
|
||||
while (it.hasNext()) {
|
||||
HashMap.Entry<String, String> pairs = it.next();
|
||||
if (url.startsWith(pairs.getKey())) {
|
||||
return this.getPlugin(pairs.getValue()).onOverrideUrlLoading(url);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private void pluginConfigurationMissing() {
|
||||
System.err.println("=====================================================================================");
|
||||
System.err.println("ERROR: plugin.xml is missing. Add res/xml/plugins.xml to your project.");
|
||||
System.err.println("https://raw.github.com/phonegap/phonegap-android/master/framework/res/xml/plugins.xml");
|
||||
System.err.println("=====================================================================================");
|
||||
}
|
||||
}
|
||||
@@ -1,140 +0,0 @@
|
||||
/*
|
||||
Licensed to the Apache Software Foundation (ASF) under one
|
||||
or more contributor license agreements. See the NOTICE file
|
||||
distributed with this work for additional information
|
||||
regarding copyright ownership. The ASF licenses this file
|
||||
to you under the Apache License, Version 2.0 (the
|
||||
"License"); you may not use this file except in compliance
|
||||
with the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing,
|
||||
software distributed under the License is distributed on an
|
||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
KIND, either express or implied. See the License for the
|
||||
specific language governing permissions and limitations
|
||||
under the License.
|
||||
*/
|
||||
package com.phonegap.api;
|
||||
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
public class PluginResult {
|
||||
private final int status;
|
||||
private final String message;
|
||||
private boolean keepCallback = false;
|
||||
private String cast = null;
|
||||
|
||||
public PluginResult(Status status) {
|
||||
this.status = status.ordinal();
|
||||
this.message = "'" + PluginResult.StatusMessages[this.status] + "'";
|
||||
}
|
||||
|
||||
public PluginResult(Status status, String message) {
|
||||
this.status = status.ordinal();
|
||||
this.message = JSONObject.quote(message);
|
||||
}
|
||||
|
||||
public PluginResult(Status status, JSONArray message, String cast) {
|
||||
this.status = status.ordinal();
|
||||
this.message = message.toString();
|
||||
this.cast = cast;
|
||||
}
|
||||
|
||||
public PluginResult(Status status, JSONObject message, String cast) {
|
||||
this.status = status.ordinal();
|
||||
this.message = message.toString();
|
||||
this.cast = cast;
|
||||
}
|
||||
|
||||
public PluginResult(Status status, JSONArray message) {
|
||||
this.status = status.ordinal();
|
||||
this.message = message.toString();
|
||||
}
|
||||
|
||||
public PluginResult(Status status, JSONObject message) {
|
||||
this.status = status.ordinal();
|
||||
this.message = message.toString();
|
||||
}
|
||||
|
||||
public PluginResult(Status status, int i) {
|
||||
this.status = status.ordinal();
|
||||
this.message = ""+i;
|
||||
}
|
||||
|
||||
public PluginResult(Status status, float f) {
|
||||
this.status = status.ordinal();
|
||||
this.message = ""+f;
|
||||
}
|
||||
|
||||
public PluginResult(Status status, boolean b) {
|
||||
this.status = status.ordinal();
|
||||
this.message = ""+b;
|
||||
}
|
||||
|
||||
public void setKeepCallback(boolean b) {
|
||||
this.keepCallback = b;
|
||||
}
|
||||
|
||||
public int getStatus() {
|
||||
return status;
|
||||
}
|
||||
|
||||
public String getMessage() {
|
||||
return message;
|
||||
}
|
||||
|
||||
public boolean getKeepCallback() {
|
||||
return this.keepCallback;
|
||||
}
|
||||
|
||||
public String getJSONString() {
|
||||
return "{status:" + this.status + ",message:" + this.message + ",keepCallback:" + this.keepCallback + "}";
|
||||
}
|
||||
|
||||
public String toSuccessCallbackString(String callbackId) {
|
||||
StringBuffer buf = new StringBuffer("");
|
||||
if (cast != null) {
|
||||
buf.append("var temp = "+cast+"("+this.getJSONString() + ");\n");
|
||||
buf.append("PhoneGap.callbackSuccess('"+callbackId+"',temp);");
|
||||
}
|
||||
else {
|
||||
buf.append("PhoneGap.callbackSuccess('"+callbackId+"',"+this.getJSONString()+");");
|
||||
}
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
public String toErrorCallbackString(String callbackId) {
|
||||
return "PhoneGap.callbackError('"+callbackId+"', " + this.getJSONString()+ ");";
|
||||
}
|
||||
|
||||
public static String[] StatusMessages = new String[] {
|
||||
"No result",
|
||||
"OK",
|
||||
"Class not found",
|
||||
"Illegal access",
|
||||
"Instantiation error",
|
||||
"Malformed url",
|
||||
"IO error",
|
||||
"Invalid action",
|
||||
"JSON error",
|
||||
"Error"
|
||||
};
|
||||
|
||||
public enum Status {
|
||||
NO_RESULT,
|
||||
OK,
|
||||
CLASS_NOT_FOUND_EXCEPTION,
|
||||
ILLEGAL_ACCESS_EXCEPTION,
|
||||
INSTANTIATION_EXCEPTION,
|
||||
MALFORMED_URL_EXCEPTION,
|
||||
IO_EXCEPTION,
|
||||
INVALID_ACTION,
|
||||
JSON_EXCEPTION,
|
||||
ERROR
|
||||
}
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
/*
|
||||
Licensed to the Apache Software Foundation (ASF) under one
|
||||
or more contributor license agreements. See the NOTICE file
|
||||
distributed with this work for additional information
|
||||
regarding copyright ownership. The ASF licenses this file
|
||||
to you under the Apache License, Version 2.0 (the
|
||||
"License"); you may not use this file except in compliance
|
||||
with the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing,
|
||||
software distributed under the License is distributed on an
|
||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
KIND, either express or implied. See the License for the
|
||||
specific language governing permissions and limitations
|
||||
under the License.
|
||||
*/
|
||||
|
||||
package com.phonegap.file;
|
||||
|
||||
public class EncodingException extends Exception {
|
||||
|
||||
public EncodingException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
/*
|
||||
Licensed to the Apache Software Foundation (ASF) under one
|
||||
or more contributor license agreements. See the NOTICE file
|
||||
distributed with this work for additional information
|
||||
regarding copyright ownership. The ASF licenses this file
|
||||
to you under the Apache License, Version 2.0 (the
|
||||
"License"); you may not use this file except in compliance
|
||||
with the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing,
|
||||
software distributed under the License is distributed on an
|
||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
KIND, either express or implied. See the License for the
|
||||
specific language governing permissions and limitations
|
||||
under the License.
|
||||
*/
|
||||
|
||||
package com.phonegap.file;
|
||||
|
||||
public class FileExistsException extends Exception {
|
||||
|
||||
public FileExistsException(String msg) {
|
||||
super(msg);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
/*
|
||||
Licensed to the Apache Software Foundation (ASF) under one
|
||||
or more contributor license agreements. See the NOTICE file
|
||||
distributed with this work for additional information
|
||||
regarding copyright ownership. The ASF licenses this file
|
||||
to you under the Apache License, Version 2.0 (the
|
||||
"License"); you may not use this file except in compliance
|
||||
with the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing,
|
||||
software distributed under the License is distributed on an
|
||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
KIND, either express or implied. See the License for the
|
||||
specific language governing permissions and limitations
|
||||
under the License.
|
||||
*/
|
||||
|
||||
|
||||
package com.phonegap.file;
|
||||
|
||||
public class InvalidModificationException extends Exception {
|
||||
|
||||
public InvalidModificationException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
/*
|
||||
Licensed to the Apache Software Foundation (ASF) under one
|
||||
or more contributor license agreements. See the NOTICE file
|
||||
distributed with this work for additional information
|
||||
regarding copyright ownership. The ASF licenses this file
|
||||
to you under the Apache License, Version 2.0 (the
|
||||
"License"); you may not use this file except in compliance
|
||||
with the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing,
|
||||
software distributed under the License is distributed on an
|
||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
KIND, either express or implied. See the License for the
|
||||
specific language governing permissions and limitations
|
||||
under the License.
|
||||
*/
|
||||
|
||||
package com.phonegap.file;
|
||||
|
||||
public class NoModificationAllowedException extends Exception {
|
||||
|
||||
public NoModificationAllowedException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
/*
|
||||
Licensed to the Apache Software Foundation (ASF) under one
|
||||
or more contributor license agreements. See the NOTICE file
|
||||
distributed with this work for additional information
|
||||
regarding copyright ownership. The ASF licenses this file
|
||||
to you under the Apache License, Version 2.0 (the
|
||||
"License"); you may not use this file except in compliance
|
||||
with the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing,
|
||||
software distributed under the License is distributed on an
|
||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
KIND, either express or implied. See the License for the
|
||||
specific language governing permissions and limitations
|
||||
under the License.
|
||||
*/
|
||||
|
||||
|
||||
package com.phonegap.file;
|
||||
|
||||
public class TypeMismatchException extends Exception {
|
||||
|
||||
public TypeMismatchException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user